From 259ee0e7022ce15f4f2c8294a4fc3de7005d7fab Mon Sep 17 00:00:00 2001 From: fishsoupisgood Date: Mon, 29 Apr 2019 07:30:28 +0100 Subject: working with one set of stripes --- .gitignore | 8 ++ .gitmodules | 3 + Makefile.include | 45 +++++++ Makefile.rules | 251 ++++++++++++++++++++++++++++++++++ app/Makefile | 56 ++++++++ app/cdcacm.c | 285 +++++++++++++++++++++++++++++++++++++++ app/dfu.c | 80 +++++++++++ app/main.c | 34 +++++ app/project.h | 30 +++++ app/prototypes.h | 35 +++++ app/ring.c | 64 +++++++++ app/ring.h | 7 + app/ticker.c | 60 +++++++++ app/timex.c | 248 ++++++++++++++++++++++++++++++++++ app/timex.ld | 43 ++++++ app/usart.c | 87 ++++++++++++ boot/Makefile | 32 +++++ boot/project.h | 23 ++++ boot/prototypes.h | 18 +++ boot/usbdfu.c | 290 ++++++++++++++++++++++++++++++++++++++++ boot/usbdfu.ld | 40 ++++++ id.h | 3 + libopencm3 | 1 + oocd/board/STM32F103R_BOARD.cfg | 6 + oocd/interface/j-link.cfg | 5 + oocd/interface/stlink-v2.cfg | 17 +++ 26 files changed, 1771 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 Makefile.include create mode 100644 Makefile.rules create mode 100644 app/Makefile create mode 100644 app/cdcacm.c create mode 100644 app/dfu.c create mode 100644 app/main.c create mode 100644 app/project.h create mode 100644 app/prototypes.h create mode 100644 app/ring.c create mode 100644 app/ring.h create mode 100644 app/ticker.c create mode 100644 app/timex.c create mode 100644 app/timex.ld create mode 100644 app/usart.c 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 id.h create mode 160000 libopencm3 create mode 100644 oocd/board/STM32F103R_BOARD.cfg create mode 100644 oocd/interface/j-link.cfg create mode 100644 oocd/interface/stlink-v2.cfg diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e46adcb --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.o +*.a +*.d +*.elf +*.map +*.hex +*~ +*.dfu diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..36a9790 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "libopencm3"] + path = libopencm3 + url = git://git.panaceas.org/stm32/libopencm3.git diff --git a/Makefile.include b/Makefile.include new file mode 100644 index 0000000..389aa68 --- /dev/null +++ b/Makefile.include @@ -0,0 +1,45 @@ +## +## 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 ?= ../oocd/interface/stlink-v2.cfg +#OOCD_INTERFACE ?= ../oocd/interface/j-link.cfg +OOCD_BOARD ?= ../oocd/board/STM32F103R_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..28422d9 --- /dev/null +++ b/Makefile.rules @@ -0,0 +1,251 @@ +# +## 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 += -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 -lgcc -lnosys -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 *.orig + +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 b/app/Makefile new file mode 100644 index 0000000..6168bfe --- /dev/null +++ b/app/Makefile @@ -0,0 +1,56 @@ +## +## 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=timex + + +V=1 +default: ${PROG}.elf + +CSRCS= main.c cdcacm.c dfu.c ring.c usart.c ticker.c timex.c +HSRCS = project.h + + +BINARY = ${PROG} +OBJS = ${CSRCS:%.c=%.o} + +include ../Makefile.include + +DID=$(shell printf '\#include "id.h"\nID_PRODUCT' | ${CC} -I.. -E - | grep -v ^\# ) +VID=$(shell printf '\#include "id.h"\nID_VENDOR' | ${CC} -I.. -E - | grep -v ^\# ) + +INCLUDES += -I.. + +dfu:${PROG}.dfu + dfu-util -R -a 0 -d ${VID}:${DID} -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 + + +tidy: + astyle -A3 -s2 --attach-extern-c -L -c -w -Y -m0 -f -p -H -U -k3 -xj -xd ${CSRCS} ${HSRCS} || astyle -A3 -s2 -L -c -w -Y -m0 -f -p -H -U -k3 -xj -xd ${CSRCS} ${HSRCS} diff --git a/app/cdcacm.c b/app/cdcacm.c new file mode 100644 index 0000000..f437a10 --- /dev/null +++ b/app/cdcacm.c @@ -0,0 +1,285 @@ +#include "project.h" + + +#define BUFFER_SIZE 512 + +ring_t cdcacm_rx_ring; +static uint8_t cdcacm_rx_ring_buf[BUFFER_SIZE]; + +ring_t cdcacm_tx_ring; +static uint8_t cdcacm_tx_ring_buf[BUFFER_SIZE]; + + +static const struct usb_device_descriptor dev = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = USB_CLASS_CDC, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = ID_VENDOR, + .idProduct = ID_PRODUCT, + .bcdDevice = 0x0200, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + + +static const struct usb_endpoint_descriptor comm_endp[] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x83, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 16, + .bInterval = 255, + } +}; + +static const struct usb_endpoint_descriptor data_endp[] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x01, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x82, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, + } +}; + +static const struct { + struct usb_cdc_header_descriptor header; + struct usb_cdc_call_management_descriptor call_mgmt; + struct usb_cdc_acm_descriptor acm; + struct usb_cdc_union_descriptor cdc_union; +} __attribute__ ((packed)) cdcacm_functional_descriptors = { + .header = { + .bFunctionLength = sizeof (struct usb_cdc_header_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_HEADER, + .bcdCDC = 0x0110, + }, + .call_mgmt = { + .bFunctionLength = + sizeof (struct usb_cdc_call_management_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, + .bmCapabilities = 0, + .bDataInterface = 1, + }, + .acm = { + .bFunctionLength = sizeof (struct usb_cdc_acm_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_ACM, + .bmCapabilities = 0, + }, + .cdc_union = { + .bFunctionLength = sizeof (struct usb_cdc_union_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_UNION, + .bControlInterface = 0, + .bSubordinateInterface0 = 1, + } +}; + +static const struct usb_interface_descriptor comm_iface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_CDC, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, + .iInterface = 0, + .endpoint = comm_endp, + .extra = &cdcacm_functional_descriptors, + .extralen = sizeof (cdcacm_functional_descriptors) +}; + +static const struct usb_interface_descriptor data_iface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + .endpoint = data_endp, +}; + +static const struct usb_interface ifaces[] = { + { + .num_altsetting = 1, + .altsetting = &comm_iface, + }, + { + .num_altsetting = 1, + .altsetting = &data_iface, + }, +#ifdef INCLUDE_DFU_INTERFACE + { + .num_altsetting = 1, + .altsetting = &dfu_iface, + }, +#endif +}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, +#ifdef INCLUDE_DFU_INTERFACE + .bNumInterfaces = 3, +#else + .bNumInterfaces = 2, +#endif + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + .interface = ifaces, +}; + +static const char *usb_strings[] = { + "Meh", + "Fish", + "Soup", +#ifdef INCLUDE_DFU_INTERFACE + "DFU", +#endif +}; + +/* Buffer to be used for control requests. */ +uint8_t usbd_control_buffer[128]; + +usbd_device *usbd_dev; + + + +static int cdcacm_control_request (usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, + uint16_t *len, + usbd_control_complete_callback *complete) +{ + (void) complete; + (void) buf; + (void) usbd_dev; +#ifdef INCLUDE_DFU_INTERFACE + + if (dfu_control_request (usbd_dev, req, buf, len, complete)) + return 1; + +#endif + + switch (req->bRequest) { + case USB_CDC_REQ_SET_CONTROL_LINE_STATE: { + /* + * This Linux cdc_acm driver requires this to be implemented + * even though it's optional in the CDC spec, and we don't + * advertise it in the ACM functional descriptor. + */ + char local_buf[10]; + struct usb_cdc_notification *notif = (void *) local_buf; + /* We echo signals back to host as notification. */ + notif->bmRequestType = 0xA1; + notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE; + notif->wValue = 0; + notif->wIndex = 0; + notif->wLength = 2; + local_buf[8] = req->wValue & 3; + local_buf[9] = 0; + // usbd_ep_write_packet(0x83, buf, 10); + return 1; + } + + case USB_CDC_REQ_SET_LINE_CODING: + + if (*len < sizeof (struct usb_cdc_line_coding)) + return 0; + + return 1; + } + + return 0; +} + + +void cdcacm_tick (void) +{ + unsigned ep = 0x82; + uint8_t buf[16]; + uint8_t *ptr = buf; + size_t n = 0; + + if (ring_empty (&cdcacm_tx_ring)) + return; + + if ((*USB_EP_REG (ep & 0x7f) & USB_EP_TX_STAT) == USB_EP_TX_STAT_VALID) + return; + + while ((!ring_read_byte (&cdcacm_tx_ring, ptr++)) && (n < sizeof (buf))) + n++; + + usbd_ep_write_packet (usbd_dev, ep, buf, n); +} + + +static void cdcacm_data_rx_cb (usbd_device *usbd_dev, uint8_t ep) +{ + (void) ep; + uint8_t buf[64]; + int len = usbd_ep_read_packet (usbd_dev, 0x01, buf, 64); + + if (len) { + ring_write (&cdcacm_rx_ring, buf, len); + ring_write (&timex_ring, buf, len); + } +} + +static void cdcacm_set_config (usbd_device *usbd_dev, uint16_t wValue) +{ + (void) wValue; + usbd_ep_setup (usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_rx_cb); + usbd_ep_setup (usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL); + usbd_ep_setup (usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); + usbd_register_control_callback (usbd_dev, + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + cdcacm_control_request); +} + +void usb_init (void) +{ + ring_init (&cdcacm_rx_ring, cdcacm_rx_ring_buf, sizeof (cdcacm_rx_ring_buf)); + ring_init (&cdcacm_tx_ring, cdcacm_tx_ring_buf, sizeof (cdcacm_tx_ring_buf)); + usbd_dev = usbd_init (&stm32f103_usb_driver, + &dev, + &config, + usb_strings, +#ifdef INCLUDE_DFU_INTERFACE + 4, +#else + 3, +#endif + usbd_control_buffer, + sizeof (usbd_control_buffer)); + usbd_register_set_config_callback (usbd_dev, cdcacm_set_config); +} + + + diff --git a/app/dfu.c b/app/dfu.c new file mode 100644 index 0000000..d79b474 --- /dev/null +++ b/app/dfu.c @@ -0,0 +1,80 @@ +#include "project.h" + +#ifdef INCLUDE_DFU_INTERFACE + +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 = 2, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = 0xFE, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 1, + .iInterface = 4, + + .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 1; +} + +int +dfu_control_request (usbd_device *usbd_dev, struct usb_setup_data *req, + uint8_t **buf, uint16_t *len, + usbd_control_complete_callback *complete) +{ + (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; +} +#endif diff --git a/app/main.c b/app/main.c new file mode 100644 index 0000000..06644bd --- /dev/null +++ b/app/main.c @@ -0,0 +1,34 @@ +#include "project.h" + + + + + +int main (void) +{ + /*set up pll */ + rcc_clock_setup_in_hse_8mhz_out_72mhz(); + /*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_USART1); + rcc_periph_clock_enable (RCC_AFIO); + nvic_set_priority (NVIC_SYSTICK_IRQ, 0x80); + nvic_set_priority (NVIC_USART1_IRQ, 0x40); + gpio_set_mode (LED_BANK, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, LED_GPIO); + + timex_init(); + ticker_init(); + usart_init(); + + usb_init(); + + printf ("Morning chaps!\r\n"); + + for (;;) + usbd_poll (usbd_dev); + + return 0; +} + diff --git a/app/project.h b/app/project.h new file mode 100644 index 0000000..5731f0d --- /dev/null +++ b/app/project.h @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define INCLUDE_DFU_INTERFACE + +#ifdef INCLUDE_DFU_INTERFACE +#include +#include +#endif + +#include +#include + +#define LED_GPIO GPIO13 +#define LED_BANK GPIOC + +#include "ring.h" + +#include "prototypes.h" diff --git a/app/prototypes.h b/app/prototypes.h new file mode 100644 index 0000000..f153902 --- /dev/null +++ b/app/prototypes.h @@ -0,0 +1,35 @@ +/* main.c */ +extern int main(void); +/* cdcacm.c */ +extern ring_t cdcacm_rx_ring; +extern ring_t cdcacm_tx_ring; +extern uint8_t usbd_control_buffer[128]; +extern usbd_device *usbd_dev; +extern void cdcacm_tick(void); +extern void usb_init(void); +/* 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, usbd_control_complete_callback *complete); +/* 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_empty(ring_t *r); +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 ring_t usart_rx_ring; +extern ring_t usart_tx_ring; +extern void usart1_isr(void); +extern void usart_kick(void); +extern int _write(int file, char *ptr, int len); +extern void usart_init(void); +/* ticker.c */ +extern unsigned led; +extern void delay_us(uint32_t d); +extern void sys_tick_handler(void); +extern void ticker_init(void); +/* timex.c */ +extern ring_t timex_ring; +extern void timex_tick(void); +extern void timex_init(void); diff --git a/app/ring.c b/app/ring.c new file mode 100644 index 0000000..26bba3a --- /dev/null +++ b/app/ring.c @@ -0,0 +1,64 @@ +#include "project.h" + + +static inline size_t +ring_next (ring_t *r, size_t p) +{ + p++; + + if (p >= r->size) + p -= r->size; + + return p; +} + +void +ring_init (ring_t *r, uint8_t *buf, size_t len) +{ + r->data = buf; + r->size = len; + r->write = 0; + r->read = 0; +} + +int +ring_write_byte (ring_t *r, uint8_t c) +{ + size_t n = ring_next (r, r->write); + + if (n == r->read) + return -1; + + r->data[r->write] = c; + r->write = n; + return 0; +} + +int ring_empty (ring_t *r) +{ + return (r->read == r->write); +} + +int +ring_read_byte (ring_t *r, uint8_t *c) +{ + size_t n = ring_next (r, r->read); + + if (r->read == r->write) + return -1; + + *c = r->data[r->read]; + r->read = n; + return 0; +} + +int +ring_write (ring_t *r, uint8_t *buf, size_t len) +{ + while (len--) { + if (ring_write_byte (r, * (buf++))) + return -1; + } + + return 0; +} diff --git a/app/ring.h b/app/ring.h new file mode 100644 index 0000000..ba8887b --- /dev/null +++ b/app/ring.h @@ -0,0 +1,7 @@ +typedef struct ring +{ + uint8_t *data; + size_t size; + size_t write; + size_t read; +} ring_t; diff --git a/app/ticker.c b/app/ticker.c new file mode 100644 index 0000000..ea832c8 --- /dev/null +++ b/app/ticker.c @@ -0,0 +1,60 @@ +#include "project.h" + + +static volatile uint32_t ticks; +static uint32_t scale = 30; + +unsigned led = 32000; + +void +delay_us (uint32_t d) +{ + d *= scale; + + while (d--) + __asm__ ("nop"); +} + +void +sys_tick_handler (void) +{ + timex_tick(); + cdcacm_tick(); + + ticks++; + + if (led) { + gpio_clear (LED_BANK, LED_GPIO); + led--; + } else + gpio_set (LED_BANK, LED_GPIO); + +} + + +void +ticker_init (void) +{ + uint32_t v, w; + /*Start periodic timer */ + systick_set_clocksource (STK_CSR_CLKSOURCE_AHB); + systick_set_reload (2288); + /* 72MHz / 2288 => 31.469531kHz (we wanted 31.46875) */ + systick_interrupt_enable(); + systick_counter_enable(); + + /*Calibrate the delay loop */ + do { + scale--; + v = ticks; + + while (v == ticks) + ; + + delay_us (32); + w = ticks; + v++; + w -= v; + } while (w); +} + diff --git a/app/timex.c b/app/timex.c new file mode 100644 index 0000000..40f43ad --- /dev/null +++ b/app/timex.c @@ -0,0 +1,248 @@ +#include "project.h" + +/* + * VGA 640x480 mode timings are + * + * 48 640 16 96 + * 10 480 33 2 + * + * at 25.175 Hz + * + */ + +/* + * Two bytes are shown per video frame one starting at + * scanline 70, the other at 255, and there are 15 + * scanlines between bits. + * + */ + +#define SL_BYTE_1_START 70 +#define SL_BIT 15 +#define SL_BYTE_2_START 255 + +#undef PAD +#undef EX + +#define SL_ON(byte,bit) ((SL_BYTE_ ## byte ## _START) + (SL_BIT * (bit))) +#define SL_OFF(byte,bit) (SL_ON(byte,bit) + 1) + + +#define SEND_BIT(byte,bit,data) \ + case SL_ON(byte,bit): \ + timex_led((data) & 1); \ + break; \ + case SL_OFF(byte,bit): \ + timex_led(1); \ + break + +#define SEND_BIT_SHIFT(byte,bit,data) \ + case SL_ON(byte,bit): \ + timex_led((data) & 1); \ + data>>=1; \ + break; \ + case SL_OFF(byte,bit): \ + timex_led(1); \ + break + +#define SEND_BYTE(byte, start, data) \ + SEND_BIT(byte,0,start); \ + SEND_BIT_SHIFT(byte,1,data); \ + SEND_BIT_SHIFT(byte,2,data); \ + SEND_BIT_SHIFT(byte,3,data); \ + SEND_BIT_SHIFT(byte,4,data); \ + SEND_BIT_SHIFT(byte,5,data); \ + SEND_BIT_SHIFT(byte,6,data); \ + SEND_BIT_SHIFT(byte,7,data); \ + SEND_BIT_SHIFT(byte,8,data) + + + +/* + * We ignore the horizontal front/back/sync and drive the system timer at + * the horizontal sync frequency of 31.46875kHz or as close as we can manage + */ + + +#define BUFFER_SIZE 512 + +#define TIMEX_BANK GPIOB +#define TIMEX_GPIO GPIO9 + +ring_t timex_ring; +static uint8_t timex_ring_buf[BUFFER_SIZE]; + + +static inline void timex_led (int v) +{ + if (v) + gpio_set (TIMEX_BANK, TIMEX_GPIO); + else + gpio_clear (TIMEX_BANK, TIMEX_GPIO); +} + + +#define SYNCS 200 +typedef enum { + STATE_MAGIC1, + STATE_MAGIC2, + STATE_MAGIC3, + STATE_MAGIC4, + STATE_IDLE, + STATE_SYNC1, + STATE_SYNC2, + STATE_PACKET_HEADER, + STATE_PACKET_DATA, + STATE_PACKET_PAD, + STATE_PACKET_RECOVERY, + +} Timex_state; + + + +static int get_data (uint8_t *start, uint8_t *data) +{ + static Timex_state state = STATE_MAGIC1; + static unsigned len; + static unsigned pad; + + + *start = 0; + + switch (state) { + case STATE_MAGIC1: + if (ring_empty (&timex_ring)) + return 1; + + case STATE_IDLE: + if (ring_empty (&timex_ring)) + return 1; + + state = STATE_SYNC1; + len = SYNCS; + break; + + case STATE_SYNC1: + *data = 0x55; + len--; + + if (!len) state = STATE_SYNC2; + + break; + + case STATE_SYNC2: + *data = 0xaa; + state = STATE_PACKET_HEADER; + break; + + case STATE_PACKET_HEADER: + if (ring_read_byte (&timex_ring, data)) { + /*No more data*/ + state = STATE_MAGIC1; + return 1; + } + len = *data -1 ; + state = STATE_PACKET_DATA; +#ifdef PAD + pad =(*data &1); +#else + pad=0; +#endif + break; + + case STATE_PACKET_DATA: + ring_read_byte (&timex_ring, data); + len--; + + if (!len) { +#ifdef PAD + len = 20; +#else + len = 10; +#endif + + if (pad) + state = STATE_PACKET_PAD; + else + state = STATE_PACKET_RECOVERY; + } + + break; + + case STATE_PACKET_PAD: + *data=0x00; + state = STATE_PACKET_RECOVERY; + break; + + + case STATE_PACKET_RECOVERY: + *start = 1; + *data = 0xff; + len--; + + if (!len) state = STATE_PACKET_HEADER; + + break; + } + + + return 0; +} + +void timex_tick (void) +{ + static unsigned line = 0; + static uint8_t data, start; + + + switch (line) { + case (SL_BYTE_1_START-2): + if (get_data (&start, &data)) { + line = 0; + return; + } + break; + + SEND_BYTE (1, start, data); + +#ifdef PAD + case (SL_BYTE_2_START-2): + if (get_data (&start, &data)) { + line = 0; + return; + } + break; + SEND_BYTE (2, start, data); +#endif + + + } + + + line++; + + if (line == 525) + line = 0; +} + +#ifdef EX +uint8_t ex[]={ +#include "/root/projects/timex_datalink/datalink-1.0.1/fish.h" +}; +#endif + + + + +void +timex_init (void) +{ + ring_init (&timex_ring, timex_ring_buf, sizeof (timex_ring_buf)); +#ifdef EX + ring_write(&timex_ring,ex,sizeof(ex)); +#endif + gpio_set_mode (TIMEX_BANK, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, TIMEX_GPIO); + + + timex_led (1); +} diff --git a/app/timex.ld b/app/timex.ld new file mode 100644 index 0000000..d30f63f --- /dev/null +++ b/app/timex.ld @@ -0,0 +1,43 @@ +/* + * 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 Olimex STM32-H103 (STM32F103RBT6, 128K flash, 20K RAM). */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08002000, LENGTH = 60K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f1.ld + +dfu_shared_location = ORIGIN(ram) + LENGTH(ram) - 1024; + +/* PROVIDE(_stack = dfu_shared_location ); */ + +SECTIONS +{ + .dfu_shared dfu_shared_location :{ + dfu_flag = .; + } +} + + diff --git a/app/usart.c b/app/usart.c new file mode 100644 index 0000000..4ba8da2 --- /dev/null +++ b/app/usart.c @@ -0,0 +1,87 @@ +#include "project.h" + +#define BUFFER_SIZE 512 + +ring_t usart_rx_ring; +static uint8_t usart_rx_ring_buf[BUFFER_SIZE]; + +ring_t usart_tx_ring; +static uint8_t usart_tx_ring_buf[BUFFER_SIZE]; + +void +usart1_isr (void) +{ + uint8_t data; + + /* Check if we were called because of RXNE. */ + if (((USART_CR1 (USART1) & USART_CR1_RXNEIE) != 0) && + ((USART_SR (USART1) & USART_SR_RXNE) != 0)) { + /* Retrieve the data from the peripheral. */ + data = usart_recv (USART1); + ring_write_byte (&usart_rx_ring, data); + } + + /* Check if we were called because of TXE. */ + if (((USART_CR1 (USART1) & USART_CR1_TXEIE) != 0) && + ((USART_SR (USART1) & USART_SR_TXE) != 0)) { + if (ring_read_byte (&usart_tx_ring, &data)) { + /*No more data, Disable the TXE interrupt, it's no longer needed. */ + USART_CR1 (USART1) &= ~USART_CR1_TXEIE; + } else + usart_send (USART1, data); + } +} + +void usart_kick (void) +{ + if (!ring_empty (&usart_tx_ring)) + USART_CR1 (USART1) |= USART_CR1_TXEIE; +} + + +int +_write (int file, char *ptr, int len) +{ + int ret; + + if (file == 1) { + ret = ring_write (&usart_tx_ring, (uint8_t *) ptr, len); + usart_kick(); + + if (ret < 0) + ret = -ret; + + return ret; + } + + errno = EIO; + return -1; +} + + + + +void +usart_init (void) +{ + ring_init (&usart_rx_ring, usart_rx_ring_buf, sizeof (usart_rx_ring_buf)); + ring_init (&usart_tx_ring, usart_tx_ring_buf, sizeof (usart_tx_ring_buf)); + /* Enable the USART1 interrupt. */ + nvic_enable_irq (NVIC_USART1_IRQ); + /* Map pins */ + gpio_set_mode (GPIOA, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX); + gpio_set_mode (GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, + GPIO_USART1_RX); + /* Setup UART1 parameters. */ + usart_set_baudrate (USART1, 115200); + usart_set_databits (USART1, 8); + usart_set_stopbits (USART1, USART_STOPBITS_1); + usart_set_parity (USART1, USART_PARITY_NONE); + usart_set_flow_control (USART1, USART_FLOWCONTROL_NONE); + usart_set_mode (USART1, USART_MODE_TX_RX); + /* Enable USART1 Receive interrupt. */ + USART_CR1 (USART1) |= USART_CR1_RXNEIE; + /* Finally enable USART1. */ + usart_enable (USART1); +} 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..d538234 --- /dev/null +++ b/boot/usbdfu.c @@ -0,0 +1,290 @@ +/* + * 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 + +#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 = ID_VENDOR, + .idProduct = ID_PRODUCT, + .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[] = { + "Cabbages are good for you", + "fish", + "soup", + /* 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..d9b3301 --- /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 Olimex STM32-H103 (STM32F103RBT6, 128K flash, 20K RAM). */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K +} + +/* 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/id.h b/id.h new file mode 100644 index 0000000..2f03cd4 --- /dev/null +++ b/id.h @@ -0,0 +1,3 @@ +#define ID_VENDOR 0x1929 +#define ID_PRODUCT 0x9291 + diff --git a/libopencm3 b/libopencm3 new file mode 160000 index 0000000..5c73d60 --- /dev/null +++ b/libopencm3 @@ -0,0 +1 @@ +Subproject commit 5c73d601763dd140bff020be8d6d06f03c2bea78 diff --git a/oocd/board/STM32F103R_BOARD.cfg b/oocd/board/STM32F103R_BOARD.cfg new file mode 100644 index 0000000..11217d2 --- /dev/null +++ b/oocd/board/STM32F103R_BOARD.cfg @@ -0,0 +1,6 @@ +# + +source [find target/stm32f1x.cfg] + +adapter_khz 500 + diff --git a/oocd/interface/j-link.cfg b/oocd/interface/j-link.cfg new file mode 100644 index 0000000..3e95768 --- /dev/null +++ b/oocd/interface/j-link.cfg @@ -0,0 +1,5 @@ +# +telnet_port 4444 +gdb_port 3333 + +source [find interface/jlink.cfg] diff --git a/oocd/interface/stlink-v2.cfg b/oocd/interface/stlink-v2.cfg new file mode 100644 index 0000000..39fe1bb --- /dev/null +++ b/oocd/interface/stlink-v2.cfg @@ -0,0 +1,17 @@ +# +telnet_port 4444 +gdb_port 3333 + +interface hla +transport select hla_swd + +#hla_layout stlink +#hla_device_desc "ST-LINK/V2" +#hla_vid_pid 0x0483 0x3748 + + +source [find interface/stlink-v2.cfg] + +reset_config connect_assert_srst + + -- cgit v1.2.3