From 39687aa7c7b138d2a1ce2551f2400bade3b1a6fb Mon Sep 17 00:00:00 2001 From: James McKenzie Date: Sun, 2 Aug 2015 23:30:06 +0100 Subject: fis --- .gitmodules | 3 + Makefile | 15 ++ Makefile.include | 50 ++++++ Makefile.rules | 252 +++++++++++++++++++++++++++++++ app/.Makefile.swo | Bin 0 -> 12288 bytes app/.Makefile.swp | Bin 0 -> 4096 bytes app/.usart.c.swn | Bin 0 -> 4096 bytes app/.usart.c.swo | Bin 0 -> 16384 bytes app/Makefile | 51 +++++++ app/crypto.c | 116 ++++++++++++++ app/crypto.ld | 40 +++++ app/dfu.c | 85 +++++++++++ app/i2c.c | 132 ++++++++++++++++ app/i2c.h | 2 + app/lcd.c | 344 ++++++++++++++++++++++++++++++++++++++++++ app/led.c | 50 ++++++ app/main.c | 39 +++++ app/project.h | 23 +++ app/prototypes.h | 53 +++++++ app/ticker.c | 82 ++++++++++ app/usb.c | 170 +++++++++++++++++++++ board/STM32F101C8T6_BOARD.cfg | 4 + boot/Makefile | 32 ++++ boot/project.h | 23 +++ boot/prototypes.h | 18 +++ boot/usbdfu.c | 289 +++++++++++++++++++++++++++++++++++ boot/usbdfu.ld | 40 +++++ interface/j-link.cfg | 5 + interface/stlink-v2.cfg | 5 + libopencm3 | 1 + 30 files changed, 1924 insertions(+) create mode 100644 .gitmodules create mode 100644 Makefile create mode 100644 Makefile.include create mode 100644 Makefile.rules create mode 100644 app/.Makefile.swo create mode 100644 app/.Makefile.swp create mode 100644 app/.usart.c.swn create mode 100644 app/.usart.c.swo create mode 100644 app/Makefile create mode 100644 app/crypto.c create mode 100644 app/crypto.ld create mode 100644 app/dfu.c create mode 100644 app/i2c.c create mode 100644 app/i2c.h create mode 100644 app/lcd.c create mode 100644 app/led.c create mode 100644 app/main.c create mode 100644 app/project.h create mode 100644 app/prototypes.h create mode 100644 app/ticker.c create mode 100644 app/usb.c create mode 100644 board/STM32F101C8T6_BOARD.cfg create mode 100644 boot/Makefile create mode 100644 boot/project.h create mode 100644 boot/prototypes.h create mode 100644 boot/usbdfu.c create mode 100644 boot/usbdfu.ld create mode 100644 interface/j-link.cfg create mode 100644 interface/stlink-v2.cfg create mode 160000 libopencm3 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..29e93ae --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "libopencm3"] + path = libopencm3 + url = git://github.com/libopencm3/libopencm3.git diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..db356c8 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +default:app.dummy + +app.dummy: libopencm3.dummy + make -C app + +libopencm3.dummy: libopencm3/Makefile + make -C libopencm3 + +clean: + make -C app $@ + make -C libopencm3 $@ + +libopencm3/Makefile: + git submodule init + git submodule update diff --git a/Makefile.include b/Makefile.include new file mode 100644 index 0000000..ff799bd --- /dev/null +++ b/Makefile.include @@ -0,0 +1,50 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2010 Piotr Esden-Tempski +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +LIBNAME = opencm3_stm32f1 +DEFS = -DSTM32F1 + +FP_FLAGS ?= -msoft-float +ARCH_FLAGS = -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd + +################################################################################ +# OpenOCD specific variables + +#OOCD ?= openocd +#OOCD_INTERFACE ?= flossjtag +#OOCD_BOARD ?= olimex_stm32_h103 + +OOCD ?= openocd +#OOCD_INTERFACE ?= ../interface/j-link.cfg +OOCD_INTERFACE ?= ../interface/stlink-v2.cfg +#OOCD_BOARD ?= ../board/st_link_v2.cfg +OOCD_BOARD ?= ../board/STM32F101C8T6_BOARD.cfg + +################################################################################ +# Black Magic Probe specific variables +# Set the BMP_PORT to a serial port and then BMP is used for flashing +BMP_PORT ?= + +################################################################################ +# texane/stlink specific variables +#STLINK_PORT ?= :4242 + + +include ../Makefile.rules diff --git a/Makefile.rules b/Makefile.rules new file mode 100644 index 0000000..0e521e6 --- /dev/null +++ b/Makefile.rules @@ -0,0 +1,252 @@ +# +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## Copyright (C) 2010 Piotr Esden-Tempski +## Copyright (C) 2013 Frantisek Burian +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +# Be silent per default, but 'make V=1' will show all compiler calls. +ifneq ($(V),1) +Q := @ +NULL := 2>/dev/null +endif + +############################################################################### +# Executables + +PREFIX ?= arm-none-eabi + +CC := $(PREFIX)-gcc +CXX := $(PREFIX)-g++ +LD := $(PREFIX)-gcc +AR := $(PREFIX)-ar +AS := $(PREFIX)-as +OBJCOPY := $(PREFIX)-objcopy +OBJDUMP := $(PREFIX)-objdump +GDB := $(PREFIX)-gdb +STFLASH = $(shell which st-flash) +STYLECHECK := /checkpatch.pl +STYLECHECKFLAGS := --no-tree -f --terse --mailback +STYLECHECKFILES := $(shell find . -name '*.[ch]') + + +############################################################################### +# Source files + +LDSCRIPT ?= $(BINARY).ld + +#OBJS += $(BINARY).o + + +ifeq ($(strip $(OPENCM3_DIR)),) +# user has not specified the library path, so we try to detect it + +# where we search for the library +LIBPATHS := ./libopencm3 ../libopencm3 + +OPENCM3_DIR := $(wildcard $(LIBPATHS:=/locm3.sublime-project)) +OPENCM3_DIR := $(firstword $(dir $(OPENCM3_DIR))) + +ifeq ($(strip $(OPENCM3_DIR)),) +$(warning Cannot find libopencm3 library in the standard search paths.) +$(error Please specify it through OPENCM3_DIR variable!) +endif +endif + +ifeq ($(V),1) +$(info Using $(OPENCM3_DIR) path to library) +endif + +INCLUDE_DIR = $(OPENCM3_DIR)/include +LIB_DIR = $(OPENCM3_DIR)/lib +SCRIPT_DIR = $(OPENCM3_DIR)/scripts + +############################################################################### +# C flags + +#CFLAGS += -Os -g +CFLAGS += -g +CFLAGS += -Wextra -Wimplicit-function-declaration +CFLAGS += -Wmissing-prototypes -Wstrict-prototypes +CFLAGS += -fno-common -ffunction-sections -fdata-sections + +############################################################################### +# C++ flags + +CXXFLAGS += -Os -g +CXXFLAGS += -Wextra -Wshadow -Wredundant-decls -Weffc++ +CXXFLAGS += -fno-common -ffunction-sections -fdata-sections + +############################################################################### +# C & C++ preprocessor common flags + +CPPFLAGS += -MD +CPPFLAGS += -Wall -Wundef + +INCLUDES = -I$(INCLUDE_DIR) +DEFINES = $(DEFS) + +CPPFLAGS += $(INCLUDES) $(DEFINES) + +############################################################################### +# Linker flags + +LDFLAGS += --static -nostartfiles +LDFLAGS += -L$(LIB_DIR) +LDFLAGS += -T$(LDSCRIPT) +LDFLAGS += -Wl,-Map=$(*).map +LDFLAGS += -Wl,--gc-sections +ifeq ($(V),99) +LDFLAGS += -Wl,--print-gc-sections +endif + +############################################################################### +# Used libraries + +LDLIBS += -l$(LIBNAME) +LDLIBS += -Wl,--start-group -lc -lnosys -lgcc -Wl,--end-group + +############################################################################### +############################################################################### +############################################################################### + +.SUFFIXES: .elf .bin .hex .srec .list .map .images .dfu +.SECONDEXPANSION: +.SECONDARY: + +all: elf + +elf: $(BINARY).elf +bin: $(BINARY).bin +hex: $(BINARY).hex +srec: $(BINARY).srec +list: $(BINARY).list + +images: $(BINARY).images +flash: $(BINARY).flash + +%.images: %.bin %.hex %.srec %.list %.map %.dfu + @#printf "*** $* images generated ***\n" + +%.bin: %.elf + @#printf " OBJCOPY $(*).bin\n" + $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).bin + +%.hex: %.elf + @#printf " OBJCOPY $(*).hex\n" + $(Q)$(OBJCOPY) -Oihex $(*).elf $(*).hex + +%.dfu: %.elf + @#printf " OBJCOPY $(*).dfu\n" + $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).dfu + +%.srec: %.elf + @#printf " OBJCOPY $(*).srec\n" + $(Q)$(OBJCOPY) -Osrec $(*).elf $(*).srec + +%.list: %.elf + @#printf " OBJDUMP $(*).list\n" + $(Q)$(OBJDUMP) -S $(*).elf > $(*).list + +fish: + echo %.elf %.map: $(OBJS) $(LDSCRIPT) $(LIB_DIR)/lib$(LIBNAME).a + echo $(BINARY).elf + +%.elf %.map: $(OBJS) $(LDSCRIPT) $(LIB_DIR)/lib$(LIBNAME).a + @#printf " LD $(*).elf\n" + $(Q)$(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJS) $(LDLIBS) -o $(*).elf + +%.o: %.c + @#printf " CC $(*).c\n" + $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $(*).o -c $(*).c + +%.o: %.cxx + @#printf " CXX $(*).cxx\n" + $(Q)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $(*).o -c $(*).cxx + +%.o: %.cpp + @#printf " CXX $(*).cpp\n" + $(Q)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $(*).o -c $(*).cpp + +clean: + @#printf " CLEAN\n" + $(Q)$(RM) *.o *.d *.elf *.bin *.hex *.srec *.list *.map *~ *.dfu ${EXTRA_CLEAN} + +stylecheck: $(STYLECHECKFILES:=.stylecheck) +styleclean: $(STYLECHECKFILES:=.styleclean) + +# the cat is due to multithreaded nature - we like to have consistent chunks of text on the output +%.stylecheck: % + $(Q)$(SCRIPT_DIR)$(STYLECHECK) $(STYLECHECKFLAGS) $* > $*.stylecheck; \ + if [ -s $*.stylecheck ]; then \ + cat $*.stylecheck; \ + else \ + rm -f $*.stylecheck; \ + fi; + +%.styleclean: + $(Q)rm -f $*.stylecheck; + + +%.stlink-flash: %.bin + @printf " FLASH $<\n" + $(Q)$(STFLASH) write $(*).bin 0x8000000 + +ifeq ($(STLINK_PORT),) +ifeq ($(BMP_PORT),) +ifeq ($(OOCD_SERIAL),) +%.flash: %.hex + @printf " FLASH $<\n" + @# IMPORTANT: Don't use "resume", only "reset" will work correctly! + $(Q)$(OOCD) -f $(OOCD_INTERFACE) \ + -f $(OOCD_BOARD) \ + -c "init" -c "reset init" \ + -c "flash write_image erase $(*).hex" \ + -c "reset" \ + -c "shutdown" $(NULL) +else +%.flash: %.hex + @printf " FLASH $<\n" + @# IMPORTANT: Don't use "resume", only "reset" will work correctly! + $(Q)$(OOCD) -f $(OOCD_INTERFACE) \ + -f $(OOCD_BOARD) \ + -c "ft2232_serial $(OOCD_SERIAL)" \ + -c "init" -c "reset init" \ + -c "flash write_image erase $(*).hex" \ + -c "reset" \ + -c "shutdown" $(NULL) +endif +else +%.flash: %.elf + @printf " GDB $(*).elf (flash)\n" + $(Q)$(GDB) --batch \ + -ex 'target extended-remote $(BMP_PORT)' \ + -x $(SCRIPT_DIR)/black_magic_probe_flash.scr \ + $(*).elf +endif +else +%.flash: %.elf + @printf " GDB $(*).elf (flash)\n" + $(Q)$(GDB) --batch \ + -ex 'target extended-remote $(STLINK_PORT)' \ + -x $(SCRIPT_DIR)/stlink_flash.scr \ + $(*).elf +endif + +.PHONY: images clean stylecheck styleclean elf bin hex srec list + +-include $(OBJS:.o=.d) diff --git a/app/.Makefile.swo b/app/.Makefile.swo new file mode 100644 index 0000000..c28d39f Binary files /dev/null and b/app/.Makefile.swo differ diff --git a/app/.Makefile.swp b/app/.Makefile.swp new file mode 100644 index 0000000..db8a3c3 Binary files /dev/null and b/app/.Makefile.swp differ diff --git a/app/.usart.c.swn b/app/.usart.c.swn new file mode 100644 index 0000000..88c369d Binary files /dev/null and b/app/.usart.c.swn differ diff --git a/app/.usart.c.swo b/app/.usart.c.swo new file mode 100644 index 0000000..e5985d3 Binary files /dev/null and b/app/.usart.c.swo differ diff --git a/app/Makefile b/app/Makefile new file mode 100644 index 0000000..7b4e978 --- /dev/null +++ b/app/Makefile @@ -0,0 +1,51 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + +CPROTO=cproto +PROG=crypto + + +V=1 +default: ${PROG}.elf + +CSRCS=dfu.c crypto.c main.c usb.c led.c ticker.c i2c.c lcd.c + + +BINARY = ${PROG} +OBJS = ${CSRCS:%.c=%.o} + +include ../Makefile.include + +#DID=$(shell printf '\#include "id.h"\nID_PRODUCT' | ${CC} -I.. -E - | grep -v ^\# ) + +INCLUDES += -I.. + +dfu:${PROG}.dfu + dfu-util -R -a 0 -d 1d6b:1932 -s 0x08002000:leave -D $< + +program: ${PROG}.elf + echo halt | nc -t localhost 4444 + echo flash write_image erase ${PWD}/$< 0x2000 | nc -t localhost 4444 + echo reset run | nc -t localhost 4444 + +protos: + echo -n > prototypes.h + ${CPROTO} $(INCLUDES) $(DEFINES) -e -v ${CSRCS} > prototypes.h.tmp + mv -f prototypes.h.tmp prototypes.h + diff --git a/app/crypto.c b/app/crypto.c new file mode 100644 index 0000000..4a0098d --- /dev/null +++ b/app/crypto.c @@ -0,0 +1,116 @@ +#include "project.h" + +static const uint8_t crypto_report_descriptor[] = { + 0x05, 0x01, /* Usage Page (Generic Desktop) */ + 0x09, 0x06, /* Usage (Keyboard) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x05, 0x07, /* Usage page (Key Codes) */ + 0x19, 0xE0, /* Usage minimum (224) */ + 0x29, 0xE7, /* Usage maximum (231) */ + 0x15, 0x00, /* Logical minimum (0) */ + 0x25, 0x01, /* Logical maximum (1) */ + 0x75, 0x01, /* Report size (1) */ + 0x95, 0x08, /* Report count (8) */ + 0x81, 0x02, /* Input (data, variable, absolute) */ + 0x95, 0x01, /* Report count (1) */ + 0x75, 0x08, /* Report size (8) */ + 0x81, 0x01, /* Input (constant) */ + 0x95, 0x06, /* Report count (6) */ + 0x75, 0x08, /* Report size (8) */ + 0x15, 0x00, /* Logical minimum (0) */ + //0x25, 0x65, /* Logical maximum (101) */ + 0x26, 0xff, 0x00, /* Logical maximum (255) */ + //0x26, 0x7f, 0x00, /* Logical maximum (255) */ + 0x05, 0x07, /* Usage page (key codes) */ + 0x19, 0x00, /* Usage minimum (0) */ + 0x2A, 0xff, 0x00, /* Usage maximum (255) */ +// 0x29, 0x65, /* Usage maximum (101) */ +// 0x2A, 0xff, 0x03, /* Usage maximum (1023) */ + 0x81, 0x00, /* Input (data, array) */ + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ + 0x09, 0x80, /* USAGE (System Control) */ + 0xA1, 0x01, /* COLLECTION (Application) */ + 0x75, 0x02, /* REPORT_SIZE (2) */ + 0x95, 0x01, /* REPORT_COUNT (1) */ + 0x15, 0x01, /* LOGICAL_MIN (1) */ + 0x25, 0x03, /* LOGICAL_MAX (3) */ + 0x09, 0x82, /* USAGE (System Sleep) */ + 0x09, 0x81, /* USAGE (System Power Down) */ + 0x09, 0x83, /* USAGE (System Wake Up) */ + 0x81, 0x60, /* INPUT (Data Ary Abs NPrf Null) */ + 0x75, 0x06, /* REPORT_SIZE (6) */ + 0x81, 0x03, /* INPUT (Cnst Var Abs) */ + 0xc0, /* END COLLECTION */ + 0xC0 /* End Collection */ +}; + + +static const struct +{ + struct usb_hid_descriptor hid_descriptor; + struct + { + uint8_t bReportDescriptorType; + uint16_t wDescriptorLength; + } __attribute__ ((packed)) hid_report; +} __attribute__ ((packed)) crypto_function = +{ + .hid_descriptor = + { + .bLength = sizeof (crypto_function),.bDescriptorType = + USB_DT_HID,.bcdHID = 0x0100,.bCountryCode = 0,.bNumDescriptors = 1,} + ,.hid_report = + { + .bReportDescriptorType = USB_DT_REPORT,.wDescriptorLength = + sizeof (crypto_report_descriptor),} +,}; + +const struct usb_endpoint_descriptor crypto_endpoint = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x81, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 9, + .bInterval = 0x1 //0x20, +}; + +const struct usb_interface_descriptor crypto_iface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceSubClass = 1, /* boot */ + .bInterfaceProtocol = 1, /* crypto */ + .iInterface = 5, + .endpoint = &crypto_endpoint, + .extra = &crypto_function, + .extralen = sizeof (crypto_function), +}; + + +void +crypto_get_descriptor (uint8_t ** buf, uint16_t * len) +{ + + /* Handle the HID report descriptor. */ + *buf = (uint8_t *) crypto_report_descriptor; + *len = sizeof (crypto_report_descriptor); +} + +void +crypto_test (void) +{ + static int c = 0; + uint8_t buf[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + + buf[0] = (c >> 1) & 7; + + buf[2] = (c & 1) ? 12 : 0; + + c++; + + usbd_ep_write_packet (usbd_dev, 0x81, buf, 9); +} diff --git a/app/crypto.ld b/app/crypto.ld new file mode 100644 index 0000000..b36fefa --- /dev/null +++ b/app/crypto.ld @@ -0,0 +1,40 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F101C8T6, 64K flash, 20K RAM). */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 10K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + +dfu_shared_location = ORIGIN(ram) + LENGTH(ram) - 1024; + +SECTIONS +{ + .dfu_shared dfu_shared_location :{ + dfu_flag = .; + } +} + diff --git a/app/dfu.c b/app/dfu.c new file mode 100644 index 0000000..cc89d4e --- /dev/null +++ b/app/dfu.c @@ -0,0 +1,85 @@ +#include "project.h" + + +extern uint32_t dfu_flag; + +const struct usb_dfu_descriptor dfu_function = { + .bLength = sizeof (struct usb_dfu_descriptor), + .bDescriptorType = DFU_FUNCTIONAL, + .bmAttributes = USB_DFU_CAN_DOWNLOAD, + .wDetachTimeout = 255, + .wTransferSize = 1024, + .bcdDFUVersion = 0x011A, +}; + +const struct usb_interface_descriptor dfu_iface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = 0xFE, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 1, + .iInterface = 6, + + .extra = &dfu_function, + .extralen = sizeof (dfu_function), +}; + + +static int +dfu_detach_complete (usbd_device * usbd_dev, struct usb_setup_data *req) +{ + (void) req; + (void) usbd_dev; + + dfu_flag = 0xfee1dead; + + scb_reset_core (); + + return 0; +} + + + +int +dfu_control_request (usbd_device * usbd_dev, struct usb_setup_data *req, + uint8_t ** buf, uint16_t * len, + int (**complete) (usbd_device * usbd_dev, + struct usb_setup_data * req)) +{ + (void) buf; + (void) len; + (void) usbd_dev; + + if ((req->bmRequestType & 0x7F) != 0x21) + return 0; /* Only accept class request. */ + + switch (req->bRequest) + { + case DFU_GETSTATUS: + { + (*buf)[0] = DFU_STATUS_OK; + (*buf)[1] = 0; + (*buf)[2] = 0; + (*buf)[3] = 0; + (*buf)[4] = STATE_APP_IDLE; + (*buf)[5] = 0; /* iString not used here */ + *len = 6; + return 1; + } + case DFU_GETSTATE: + /* Return state with no state transision. */ + *buf[0] = STATE_APP_IDLE; + *len = 1; + return 1; + case DFU_DETACH: + *complete = dfu_detach_complete; + + return 1; + } + + return 0; + +} diff --git a/app/i2c.c b/app/i2c.c new file mode 100644 index 0000000..89249d0 --- /dev/null +++ b/app/i2c.c @@ -0,0 +1,132 @@ +#include "project.h" + + +#define GPIO_SCL GPIOB +#define GPIO_SDA GPIOB +#define SCL GPIO13 +#define SDA GPIO14 + +#define I2C_BB_DELAY do { delay_us(1); } while (0) + +int +i2c_bb (int scl, int sda) +{ + if (scl) + gpio_set (GPIO_SCL, SCL); + else + gpio_clear (GPIO_SCL, SCL); + if (sda) + gpio_set (GPIO_SDA, SDA); + else + gpio_clear (GPIO_SDA, SDA); + + return ! !(gpio_get (GPIO_SDA, SDA) & SDA); + +} + + +void +i2c_bb_start (void) +{ + i2c_bb (1, 1); + I2C_BB_DELAY; + i2c_bb (1, 0); + I2C_BB_DELAY; + i2c_bb (0, 0); + I2C_BB_DELAY; +} + + +void +i2c_bb_stop (void) +{ + i2c_bb (0, 0); + I2C_BB_DELAY; + i2c_bb (1, 0); + I2C_BB_DELAY; + i2c_bb (1, 1); + I2C_BB_DELAY; +} + +int +i2c_bb_send_data (uint8_t v) +{ + int c; + + + for (c = 0x80; c; c >>= 1) + { + i2c_bb (0, c & v); + I2C_BB_DELAY; + i2c_bb (1, c & v); + I2C_BB_DELAY; + i2c_bb (0, c & v); + I2C_BB_DELAY; + } + + i2c_bb (0, 1); + I2C_BB_DELAY; + i2c_bb (1, 1); + I2C_BB_DELAY; + c = i2c_bb (1, 1); + i2c_bb (0, 1); + + return c; +} + + +int +i2c_bb_start_transaction (uint8_t a, int wnr) +{ + int ret; + + i2c_bb_start (); + ret = i2c_bb_send_data (a << 1 | ! !(wnr)); + + + return ret; +} + +#if 0 +void +i2c_bb_scan (void) +{ + int i, r; + + return; + i2cp_reset (); + + printf ("Probing bus\r\n"); + for (i = 0; i < 128; ++i) + { + while (i2cp_lock ()); + i2cp_start (); + i2cp_abort_start (); + i2cp_stop (); + i2cp_abort_stop (); + r = i2cp_start_transaction (i, I2C_WRITE); + i2cp_stop (); + i2cp_unlock (); + if (!r) + printf ("Found device at address 0x%x\r\n", i); + usart1_drain (); + } + printf ("Done\r\n"); + i2cp_reset (); + +} +#endif + +void +i2c_bb_init (void) +{ + gpio_set_mode (GPIO_SCL, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_OPENDRAIN, SCL); + gpio_set_mode (GPIO_SDA, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_OPENDRAIN, SDA); + + i2c_bb_start (); + i2c_bb_stop (); + + +} diff --git a/app/i2c.h b/app/i2c.h new file mode 100644 index 0000000..b2ba2fc --- /dev/null +++ b/app/i2c.h @@ -0,0 +1,2 @@ +#define I2C_WRITE 0 +#define I2C_READ 1 diff --git a/app/lcd.c b/app/lcd.c new file mode 100644 index 0000000..714e850 --- /dev/null +++ b/app/lcd.c @@ -0,0 +1,344 @@ +#include "project.h" + +#define FOO do { printf("lcd:%x\r\n",__LINE__); usart1_drain(); } while (0) + +#define PCF8574_I2C_ADDRESS 0x27 + +#define LINE_RS 0x1 +#define LINE_RnW 0x2 +#define LINE_EN 0x4 +#define LINE_BACKLIGHT 0x8 + +#define LCD_CLEAR 0x1 +#define LCD_HOME 0x2 + +#define LCD_DISP 0x8 +#define LCD_DISP_ON 0x4 +#define LCD_DISP_CURSOR 0x2 +#define LCD_DISP_CURSOR_BLINK 0x1 + +#define LCD_FUNC 0x20 +#define LCD_FUNC_8BIT 0x10 +#define LCD_FUNC_4BIT 0x00 +#define LCD_FUNC_2ROWS 0x08 +#define LCD_FUNC_1ROW 0x00 +#define LCD_FUNC_5x10 0x04 +#define LCD_FUNC_5X7 0x00 + +#define LCD_SET_DDRAM_ADDR 0x80 + +#define LCD_H_SHIFT 5 +#define LCD_RS (1 << LCD_H_SHIFT) +#define LCD_W 16 +#define LCD_W_MASK (LCD_RS -1 ) +#define LCD_H 2 +#define LCD_SZ (LCD_H << LCD_H_SHIFT) +#define LCD_POS(c,r) (((r) << LCD_H_SHIFT ) +(c)) + +#define BYTES_PER_BYTE 6 + +#define DMA_BUF_SZ (BYTES_PER_BYTE * ( (1 + LCD_W) *LCD_H + 1)) + + +static int backlight; +uint8_t fb[LCD_H][LCD_W]; +uint8_t shadow[LCD_H][LCD_W]; + +static int pos; + + +static void +clock_nibble (uint8_t n) +{ + if (backlight) + n |= LINE_BACKLIGHT; + i2c_bb_send_data (n); + i2c_bb_send_data (LINE_EN | n); + i2c_bb_send_data (n); +} + + +static void +write_reg (uint8_t c, int r) +{ + uint8_t b; + + b = c & 0xf0; + if (r) + b |= LINE_RS; + + clock_nibble (b); + + b = (c & 0xf) << 4; + if (r) + b |= LINE_RS; + + clock_nibble (b); +} + +static void +send_data (uint8_t c) +{ + write_reg (c, 1); +} + + +static void +send_command (uint8_t c) +{ + write_reg (c, 0); +} + +static void +send_one_command (uint8_t cmd, int delay) +{ + i2c_bb_start_transaction (PCF8574_I2C_ADDRESS, I2C_WRITE); + send_command (cmd); + i2c_bb_stop (); + if (delay) + delay_ms (delay); +} + + + +static void +cls (void) +{ + send_one_command (LCD_CLEAR, 2); +} + +#if 0 +static void +home (void) +{ + send_one_command (LCD_HOME, 2); +} +#endif + +static void +on (void) +{ + send_one_command (LCD_DISP | LCD_DISP_ON /* | LCD_DISP_CURSOR */ , 4); +} + +static void +off (void) +{ + send_one_command (LCD_DISP, 4); +} + +static int +lcd_addr (int x, int y) +{ + return x + ((y & 1) << 6) + ((y & 2) ? 20 : 0); +} + + +#if 0 +static void +move (uint8_t c, uint8_t r) +{ + send_one_command (LCD_SET_DDRAM_ADDR | lcd_addr (c, r), 2); +} +#endif + + +void +lcd_refresh (void) +{ + int c, r; + int addr; + + + i2c_bb_start_transaction (PCF8574_I2C_ADDRESS, I2C_WRITE); + + + for (r = 0; r < LCD_H; ++r) + { + for (c = 0; c < LCD_W; ++c) + { + + if (shadow[r][c] != fb[r][c]) + { + + addr = lcd_addr (c, r); + + if (addr != pos) + { + send_command (LCD_SET_DDRAM_ADDR | addr); + pos = addr; + } + + send_data (shadow[r][c]); + fb[r][c] = shadow[r][c]; + + pos++; + } + + } + } + + i2c_bb_stop (); +} + +void +lcd_tick (void) +{ + static int u; + + u++; + + if (u < 100) + return; + + u = 0; + + if (!memcmp (shadow, fb, sizeof (fb))) + return; + + lcd_refresh (); +} + + + + + + +void +lcd_write_char (uint8_t c, int x, int y) +{ + shadow[y][x] = c; +} + + +void +lcd_erase (int x, int y, int w) +{ + uint8_t *ptr = &shadow[y][x]; + while (w--) + *ptr = ' '; +} + +void +lcd_erase_line (int w, int y) +{ + lcd_erase (0, y, w); +} + +void +lcd_erase_all (void) +{ + int y; + for (y = 0; y < LCD_H; ++y) + { + lcd_erase (0, 0, LCD_W); + } +} + +void +lcd_write (char *c, int x, int y) +{ + while (*c) + { + lcd_write_char (*(c++), x++, y); + if (x == LCD_W) + break; + } +} + +#if 0 +static void +lcd_scroll (uint8_t * p) +{ + int i; + for (i = 0; i < 3; ++i) + { + memcpy (p, p + LCD_RS, LCD_W); + p += LCD_RS; + } + memset (p, ' ', LCD_W); +} + +void +lcd_putc (uint8_t c) +{ + + switch (c) + { + case '\r': + pos &= ~LCD_W_MASK; + break; + case '\n': + pos &= ~LCD_W_MASK; + pos += LCD_RS; + break; + default: + buf[pos] = c; + pos++; + } + + + if ((pos & LCD_W_MASK) == LCD_W) + { + pos &= ~LCD_W_MASK; + pos += LCD_RS; + } + + if (pos == LCD_SZ) + { + lcd_scroll (buf); + pos -= LCD_RS; + } + + +} +#endif + +void +lcd_backlight (int i) +{ + backlight = i; + + i2c_bb_start_transaction (PCF8574_I2C_ADDRESS, I2C_WRITE); + i2c_bb_send_data (backlight ? LINE_BACKLIGHT : 0); + i2c_bb_stop (); +} + + + + + + +void +lcd_reset (void) +{ + i2c_bb_start_transaction (PCF8574_I2C_ADDRESS, I2C_WRITE); + clock_nibble (0x30); + delay_ms (5); + clock_nibble (0x30); + delay_us (64); + clock_nibble (0x30); + delay_us (64); + clock_nibble (0x20); + + send_command (LCD_FUNC | LCD_FUNC_4BIT | LCD_FUNC_2ROWS | LCD_FUNC_5X7); + i2c_bb_stop (); + on (); + cls (); +} + +void +lcd_init (void) +{ + lcd_backlight (0); + lcd_reset (); + lcd_backlight (1); + +} + +void +lcd_shutdown (void) +{ + lcd_backlight (0); + off (); +} diff --git a/app/led.c b/app/led.c new file mode 100644 index 0000000..ddbbc34 --- /dev/null +++ b/app/led.c @@ -0,0 +1,50 @@ +#include "project.h" + + +static int led = 0; + +void +led_init (void) +{ + gpio_set_mode (GPIOA, GPIO_MODE_OUTPUT_2_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, GPIO9); + + gpio_set (GPIOA, GPIO9); +} + + +void +led_blink (void) +{ + gpio_set (GPIOA, GPIO9); + led = 50; +} + +void +led_tick (void) +{ + +#if 0 + if (led) + { + led--; + if (!led) + gpio_clear (GPIOA, GPIO9); + } +#else + static int c; + + c++; + if (c > 1000) + { + led ^= 1; + if (led) + gpio_set (GPIOA, GPIO9); + else + gpio_clear (GPIOA, GPIO9); + + + c = 0; + } +#endif +} diff --git a/app/main.c b/app/main.c new file mode 100644 index 0000000..053aa75 --- /dev/null +++ b/app/main.c @@ -0,0 +1,39 @@ +#include "project.h" +extern uint32_t dfu_flag; + +int +main (void) +{ + /*set up pll */ + //rcc_clock_setup_in_hse_8mhz_out_24mhz (); + rcc_clock_setup_in_hse_8mhz_out_72mhz (); + //rcc_clock_setup_in_hsi_out_48mhz(); + + /*turn on clocks to periferals */ + rcc_periph_clock_enable (RCC_GPIOA); + rcc_periph_clock_enable (RCC_GPIOB); + rcc_periph_clock_enable (RCC_GPIOC); + rcc_periph_clock_enable (RCC_AFIO); + + ticker_init (); + led_init (); + i2c_bb_init (); + lcd_init (); + + lcd_backlight (1); + { + char buf[16]; + sprintf(buf,"%x",dfu_flag); + lcd_write(buf,0,1); +} + + + lcd_write ("hello world", 0, 0); + + usb_init (); + + + usb_run (); + + return 0; +} diff --git a/app/project.h b/app/project.h new file mode 100644 index 0000000..3b7fc27 --- /dev/null +++ b/app/project.h @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +#include +#include + + +#include "i2c.h" + + +#include "prototypes.h" diff --git a/app/prototypes.h b/app/prototypes.h new file mode 100644 index 0000000..f977d61 --- /dev/null +++ b/app/prototypes.h @@ -0,0 +1,53 @@ +/* dfu.c */ +extern const struct usb_dfu_descriptor dfu_function; +extern const struct usb_interface_descriptor dfu_iface; +extern int dfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, int (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)); +/* crypto.c */ +extern const struct usb_endpoint_descriptor crypto_endpoint; +extern const struct usb_interface_descriptor crypto_iface; +extern void crypto_get_descriptor(uint8_t **buf, uint16_t *len); +extern void crypto_test(void); +/* main.c */ +extern int main(void); +/* usb.c */ +extern const struct usb_device_descriptor dev; +extern const struct usb_interface ifaces[]; +extern const struct usb_config_descriptor config; +extern usbd_device *usbd_dev; +extern int usb_is_suspended; +extern int usb_wakeup_host(void); +extern void usb_set_config(usbd_device *usbd_dev, uint16_t wValue); +extern void usb_init(void); +extern void usb_run(void); +/* led.c */ +extern void led_init(void); +extern void led_blink(void); +extern void led_tick(void); +/* ticker.c */ +extern volatile uint32_t ticks; +extern void delay_us(uint32_t d); +extern void sys_tick_handler(void); +extern void delay_ms(uint32_t d); +extern int timed_out(uint32_t then, unsigned int ms); +extern void ticker_init(void); +/* i2c.c */ +extern int i2c_bb(int scl, int sda); +extern void i2c_bb_start(void); +extern void i2c_bb_stop(void); +extern int i2c_bb_send_data(uint8_t v); +extern int i2c_bb_start_transaction(uint8_t a, int wnr); +extern void i2c_bb_init(void); +/* lcd.c */ +extern uint8_t fb[2][16]; +extern uint8_t shadow[2][16]; +extern void lcd_refresh(void); +extern void lcd_tick(void); +extern void lcd_write_char(uint8_t c, int x, int y); +extern void lcd_erase(int x, int y, int w); +extern void lcd_erase_line(int w, int y); +extern void lcd_erase_all(void); +extern void lcd_write(char *c, int x, int y); +extern void lcd_backlight(int i); +extern void lcd_reset(void); +extern void lcd_init(void); +extern void lcd_shutdown(void); diff --git a/app/ticker.c b/app/ticker.c new file mode 100644 index 0000000..dcba0d1 --- /dev/null +++ b/app/ticker.c @@ -0,0 +1,82 @@ +#include "project.h" + + +static volatile uint32_t delay_ms_count; +volatile uint32_t ticks; +static uint32_t scale = 7; + + +void +delay_us (uint32_t d) +{ + d *= scale; + while (d--) + { + __asm__ ("nop"); + } +} + + +void +sys_tick_handler (void) +{ + //uint8_t d; + + if (delay_ms_count) + delay_ms_count--; + + ticks++; + + led_tick (); + lcd_tick (); +} + + +void +delay_ms (uint32_t d) +{ + delay_ms_count = d; + while (delay_ms_count); +} + +int +timed_out (uint32_t then, unsigned int ms) +{ + then = ticks - then; + + if (then > ms) + return 1; + return 0; +} + + +void +ticker_init (void) +{ + uint32_t v, w; + + /*Start periodic timer */ + + systick_set_clocksource (STK_CSR_CLKSOURCE_AHB_DIV8); + /* 48MHz / 8 = > 6Mhz */ + systick_set_reload (6000); + /* 6MHz / 6000 => 1kHz */ + systick_interrupt_enable (); + systick_counter_enable (); + + + /*Calibrate the delay loop */ + do + { + scale--; + v = ticks; + while (v == ticks); + delay_us (1000); + w = ticks; + v++; + w -= v; + } + while (w); + + +} diff --git a/app/usb.c b/app/usb.c new file mode 100644 index 0000000..ea03f2a --- /dev/null +++ b/app/usb.c @@ -0,0 +1,170 @@ +#include "project.h" + +/* Define this to include the DFU APP interface. */ +const struct usb_device_descriptor dev = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x1d6b, + .idProduct = 0x1932, + .bcdDevice = 0x0200, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +const struct usb_interface ifaces[] = { + { + .num_altsetting = 1, + .altsetting = &crypto_iface, + }, + { + .num_altsetting = 1, + .altsetting = &dfu_iface, + }, +}; + +const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 2, + .bConfigurationValue = 1, + .iConfiguration = 4, + .bmAttributes = 0xa0, + .bMaxPower = 0x31, + + .interface = ifaces, +}; + +static const char *usb_strings[] = { + "bootpad", + "bootpad", + "bootpad", + "composite", + "bootpad", + "bootpad dfu device", +}; + + + +usbd_device *usbd_dev; + + +int usb_is_suspended = 0; + +static void +usb_suspended (void) +{ + *USB_CNTR_REG |= USB_CNTR_FSUSP; + + usb_is_suspended = 1; +} + + +static void +usb_resumed (void) +{ + + *USB_CNTR_REG &= ~USB_CNTR_FSUSP; + + usb_is_suspended = 0; +} + +int +usb_wakeup_host (void) +{ + if (!usb_is_suspended) + return 1; + + + *USB_CNTR_REG |= USB_CNTR_RESUME; + + delay_us (1000); + delay_us (1000); + delay_us (1000); + delay_us (1000); + delay_us (1000); + + *USB_CNTR_REG &= ~USB_CNTR_RESUME; + + return 0; +} + + +static int +usb_control_request (usbd_device * usbd_dev, struct usb_setup_data *req, + uint8_t ** buf, uint16_t * len, + int (**complete) (usbd_device * usbd_dev, + struct usb_setup_data * req)) +{ + + (void) complete; + (void) usbd_dev; + + if ((req->bmRequestType != 0x81) || + (req->bRequest != USB_REQ_GET_DESCRIPTOR) || (req->wValue != 0x2200)) + return 0; + + switch (req->wIndex) + { + case 0: + crypto_get_descriptor (buf, len); + return 1; + } + + *len = 0; + return 0; +} + + +void +usb_set_config (usbd_device * usbd_dev, uint16_t wValue) +{ + (void) wValue; + (void) usbd_dev; + + usbd_ep_setup (usbd_dev, 0x81, USB_ENDPOINT_ATTR_INTERRUPT, 4, NULL); + + usbd_register_control_callback (usbd_dev, + USB_REQ_TYPE_STANDARD | + USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + usb_control_request); + + usbd_register_control_callback (usbd_dev, + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + dfu_control_request); + + +} + +/* Buffer to be used for control requests. */ +static uint8_t usbd_control_buffer[128]; + +void +usb_init (void) +{ + + usbd_dev = + usbd_init (&stm32f103_usb_driver, &dev, &config, usb_strings, 8, + usbd_control_buffer, sizeof (usbd_control_buffer)); + + usbd_register_set_config_callback (usbd_dev, usb_set_config); + usbd_register_suspend_callback (usbd_dev, usb_suspended); + usbd_register_resume_callback (usbd_dev, usb_resumed); + +} + +void +usb_run (void) +{ + for (;;) + usbd_poll (usbd_dev); +} diff --git a/board/STM32F101C8T6_BOARD.cfg b/board/STM32F101C8T6_BOARD.cfg new file mode 100644 index 0000000..745be89 --- /dev/null +++ b/board/STM32F101C8T6_BOARD.cfg @@ -0,0 +1,4 @@ +# + +#source [find target/stm32f1x.cfg] +source [find target/stm32f1x_stlink.cfg] diff --git a/boot/Makefile b/boot/Makefile new file mode 100644 index 0000000..86d4d2c --- /dev/null +++ b/boot/Makefile @@ -0,0 +1,32 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2009 Uwe Hermann +## +## This library is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This library is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this library. If not, see . +## + + +CSRCS=usbdfu.c +PROG = usbdfu + +CPROTO=cproto +V=1 +BINARY = ${PROG} +OBJS = ${CSRCS:%.c=%.o} + +include ../Makefile.include + +CFLAGS += -I.. + diff --git a/boot/project.h b/boot/project.h new file mode 100644 index 0000000..0323569 --- /dev/null +++ b/boot/project.h @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define INCLUDE_DFU_INTERFACE + + +#ifdef INCLUDE_DFU_INTERFACE +#include +#include +#endif + +#include +#include + +#include "ring.h" + +#include "prototypes.h" diff --git a/boot/prototypes.h b/boot/prototypes.h new file mode 100644 index 0000000..45d399c --- /dev/null +++ b/boot/prototypes.h @@ -0,0 +1,18 @@ +/* usbdfu.c */ +extern uint8_t usbd_control_buffer[1024]; +extern const struct usb_device_descriptor dev; +extern const struct usb_dfu_descriptor dfu_function; +extern const struct usb_interface_descriptor iface; +extern const struct usb_interface ifaces[]; +extern const struct usb_config_descriptor config; +extern int main(void); +/* ring.c */ +extern void ring_init(ring_t *r, uint8_t *buf, size_t len); +extern int ring_write_byte(ring_t *r, uint8_t c); +extern int ring_read_byte(ring_t *r, uint8_t *c); +extern int ring_write(ring_t *r, uint8_t *buf, size_t len); +/* usart.c */ +extern void usart1_isr(void); +extern int _write(int file, char *ptr, int len); +extern void usart_queue(uint8_t d); +extern void usart_init(void); diff --git a/boot/usbdfu.c b/boot/usbdfu.c new file mode 100644 index 0000000..33f4c22 --- /dev/null +++ b/boot/usbdfu.c @@ -0,0 +1,289 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + + +#define APP_ADDRESS 0x08002000 + +/* Commands sent with wBlockNum == 0 as per ST implementation. */ +#define CMD_SETADDR 0x21 +#define CMD_ERASE 0x41 + +void usb_set_config (usbd_device * usbd_dev, uint16_t wValue); + +/* We need a special large control buffer for this device: */ +uint8_t usbd_control_buffer[1024]; + +static enum dfu_state usbdfu_state = STATE_DFU_IDLE; + +extern uint32_t dfu_flag; + +static struct { + uint8_t buf[sizeof(usbd_control_buffer)]; + uint16_t len; + uint32_t addr; + uint16_t blocknum; +} prog; + +const struct usb_device_descriptor dev = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x1d6b, + .idProduct = 0x1932, + .bcdDevice = 0x0200, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +const struct usb_dfu_descriptor dfu_function = { + .bLength = sizeof(struct usb_dfu_descriptor), + .bDescriptorType = DFU_FUNCTIONAL, + .bmAttributes = USB_DFU_CAN_DOWNLOAD, + .wDetachTimeout = 255, + .wTransferSize = 1024, + .bcdDFUVersion = 0x011A, +}; + +const struct usb_interface_descriptor iface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = 0xFE, /* Device Firmware Upgrade */ + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 2, + + /* The ST Microelectronics DfuSe application needs this string. + * The format isn't documented... */ + .iInterface = 4, + + .extra = &dfu_function, + .extralen = sizeof(dfu_function), +}; + +const struct usb_interface ifaces[] = {{ + .num_altsetting = 1, + .altsetting = &iface, +}}; + +const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0xC0, + .bMaxPower = 0x32, + + .interface = ifaces, +}; + +static const char *usb_strings[] = { + "bootpad", + "bootpad", + "bootpad", + /* This string is used by ST Microelectronics' DfuSe utility. */ + "@Internal Flash /0x08000000/8*001Ka,56*001Kg", +}; + +static uint8_t usbdfu_getstatus(usbd_device *usbd_dev, uint32_t *bwPollTimeout) +{ + (void)usbd_dev; + + switch (usbdfu_state) { + case STATE_DFU_DNLOAD_SYNC: + usbdfu_state = STATE_DFU_DNBUSY; + *bwPollTimeout = 100; + return DFU_STATUS_OK; + case STATE_DFU_MANIFEST_SYNC: + /* Device will reset when read is complete. */ + usbdfu_state = STATE_DFU_MANIFEST; + return DFU_STATUS_OK; + default: + return DFU_STATUS_OK; + } +} + +static void usbdfu_getstatus_complete(usbd_device *usbd_dev, struct usb_setup_data *req) +{ + int i; + (void)req; + (void)usbd_dev; + + switch (usbdfu_state) { + case STATE_DFU_DNBUSY: + flash_unlock(); + if (prog.blocknum == 0) { + switch (prog.buf[0]) { + case CMD_ERASE: + { + uint32_t *dat = (uint32_t *)(prog.buf + 1); + flash_erase_page(*dat); + } + case CMD_SETADDR: + { + uint32_t *dat = (uint32_t *)(prog.buf + 1); + prog.addr = *dat; + } + } + } else { + uint32_t baseaddr = prog.addr + ((prog.blocknum - 2) * + dfu_function.wTransferSize); + for (i = 0; i < prog.len; i += 2) { + uint16_t *dat = (uint16_t *)(prog.buf + i); + flash_program_half_word(baseaddr + i, + *dat); + } + } + flash_lock(); + + /* Jump straight to dfuDNLOAD-IDLE, skipping dfuDNLOAD-SYNC. */ + usbdfu_state = STATE_DFU_DNLOAD_IDLE; + return; + case STATE_DFU_MANIFEST: + /* USB device must detach, we just reset... */ + scb_reset_system(); + return; /* Will never return. */ + default: + return; + } +} + +static int usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, + uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req)) +{ + + if ((req->bmRequestType & 0x7F) != 0x21) + return 0; /* Only accept class request. */ + + switch (req->bRequest) { + case DFU_DNLOAD: + if ((len == NULL) || (*len == 0)) { + usbdfu_state = STATE_DFU_MANIFEST_SYNC; + return 1; + } else { + /* Copy download data for use on GET_STATUS. */ + prog.blocknum = req->wValue; + prog.len = *len; + memcpy(prog.buf, *buf, *len); + usbdfu_state = STATE_DFU_DNLOAD_SYNC; + return 1; + } + case DFU_CLRSTATUS: + /* Clear error and return to dfuIDLE. */ + if (usbdfu_state == STATE_DFU_ERROR) + usbdfu_state = STATE_DFU_IDLE; + return 1; + case DFU_ABORT: + /* Abort returns to dfuIDLE state. */ + usbdfu_state = STATE_DFU_IDLE; + return 1; + case DFU_UPLOAD: + /* Upload not supported for now. */ + return 0; + case DFU_GETSTATUS: { + uint32_t bwPollTimeout = 0; /* 24-bit integer in DFU class spec */ + (*buf)[0] = usbdfu_getstatus(usbd_dev, &bwPollTimeout); + (*buf)[1] = bwPollTimeout & 0xFF; + (*buf)[2] = (bwPollTimeout >> 8) & 0xFF; + (*buf)[3] = (bwPollTimeout >> 16) & 0xFF; + (*buf)[4] = usbdfu_state; + (*buf)[5] = 0; /* iString not used here */ + *len = 6; + *complete = usbdfu_getstatus_complete; + return 1; + } + case DFU_GETSTATE: + /* Return state with no state transision. */ + *buf[0] = usbdfu_state; + *len = 1; + return 1; + } + + return 0; +} + +void +usb_set_config (usbd_device * usbd_dev, uint16_t wValue) +{ + (void) wValue; + (void) usbd_dev; + + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + usbdfu_control_request); + +} + +int main(void) +{ + usbd_device *usbd_dev; + + rcc_periph_clock_enable(RCC_GPIOA); + + if (dfu_flag!=0xfee1dead) { + /* Boot the application if it's valid. */ + if ((*(volatile uint32_t *)APP_ADDRESS & 0x2FFE0000) == 0x20000000) { + /* Set vector table base address. */ + SCB_VTOR = APP_ADDRESS & 0xFFFF; + /* Initialise master stack pointer. */ + asm volatile("msr msp, %0"::"g" + (*(volatile uint32_t *)APP_ADDRESS)); + /* Jump to application. */ + (*(void (**)())(APP_ADDRESS + 4))(); + } + } + + dfu_flag=0; + + rcc_clock_setup_in_hsi_out_48mhz(); + + rcc_periph_clock_enable(RCC_GPIOC); + + gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, GPIO11); + gpio_set(GPIOC, GPIO11); + + usbd_dev = usbd_init(&stm32f103_usb_driver, &dev, &config, usb_strings, 4, usbd_control_buffer, sizeof(usbd_control_buffer)); + + usbd_register_set_config_callback (usbd_dev, usb_set_config); + + gpio_clear(GPIOC, GPIO11); + + while (1) + usbd_poll(usbd_dev); +} diff --git a/boot/usbdfu.ld b/boot/usbdfu.ld new file mode 100644 index 0000000..b36fefa --- /dev/null +++ b/boot/usbdfu.ld @@ -0,0 +1,40 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for STM32F101C8T6, 64K flash, 20K RAM). */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 10K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + +dfu_shared_location = ORIGIN(ram) + LENGTH(ram) - 1024; + +SECTIONS +{ + .dfu_shared dfu_shared_location :{ + dfu_flag = .; + } +} + diff --git a/interface/j-link.cfg b/interface/j-link.cfg new file mode 100644 index 0000000..3e95768 --- /dev/null +++ b/interface/j-link.cfg @@ -0,0 +1,5 @@ +# +telnet_port 4444 +gdb_port 3333 + +source [find interface/jlink.cfg] diff --git a/interface/stlink-v2.cfg b/interface/stlink-v2.cfg new file mode 100644 index 0000000..274034e --- /dev/null +++ b/interface/stlink-v2.cfg @@ -0,0 +1,5 @@ +# +telnet_port 4444 +gdb_port 3333 + +source [find interface/stlink-v2.cfg] diff --git a/libopencm3 b/libopencm3 new file mode 160000 index 0000000..7b29cae --- /dev/null +++ b/libopencm3 @@ -0,0 +1 @@ +Subproject commit 7b29caed1a726b5cef4c269b6a6ef7a1f1dd105c -- cgit v1.2.3