From 64f632692fe2a164830a363f8db158a8a2ae33de Mon Sep 17 00:00:00 2001 From: root Date: Sun, 21 Nov 2021 17:27:02 +0000 Subject: first workingish cut --- .gitmodules | 3 + dial/base.jpg | Bin 0 -> 32541 bytes dial/base.svg | 851 ++++++++++++++++++++++++++++++++ dial/try1.svg | 860 +++++++++++++++++++++++++++++++++ dial/try2.svg | 299 ++++++++++++ dial/try3.svg | 328 +++++++++++++ stm32/.gitignore | 10 + stm32/Makefile.include | 45 ++ stm32/Makefile.rules | 251 ++++++++++ stm32/app/Makefile | 80 +++ stm32/app/asm_fns.h | 4 + stm32/app/board.h | 15 + stm32/app/cdcacm.c | 221 +++++++++ stm32/app/clock.ld | 43 ++ stm32/app/dfu.c | 86 ++++ stm32/app/dummy_kb.c | 26 + stm32/app/events.c | 101 ++++ stm32/app/gdb.script | 2 + stm32/app/hands.c | 90 ++++ stm32/app/main.c | 50 ++ stm32/app/motor.c | 75 +++ stm32/app/pins.h | 54 +++ stm32/app/project.h | 50 ++ stm32/app/prototypes.h | 81 ++++ stm32/app/ring.c | 64 +++ stm32/app/ring.h | 7 + stm32/app/rtc.c | 170 +++++++ stm32/app/ticker.c | 74 +++ stm32/app/time_fn.c | 650 +++++++++++++++++++++++++ stm32/app/time_fn.h | 47 ++ stm32/app/usart.c | 88 ++++ stm32/app/usb.c | 148 ++++++ stm32/boot/Makefile | 48 ++ stm32/boot/gdb.script | 2 + stm32/boot/project.h | 23 + stm32/boot/prototypes.h | 18 + stm32/boot/usbdfu.c | 334 +++++++++++++ stm32/boot/usbdfu.ld | 40 ++ stm32/docs/Astronomical Algorithms.pdf | Bin 0 -> 17207937 bytes stm32/docs/rm0008.pdf | Bin 0 -> 13016697 bytes stm32/id.h | 4 + stm32/libopencm3 | 1 + stm32/oocd/board/STM32F103R_BOARD.cfg | 6 + stm32/oocd/interface/j-link.cfg | 5 + stm32/oocd/interface/stlink-v2.cfg | 11 + stm32/oocd/stm32-f103.cfg | 6 + stm32/tools/dfuse-pack.py | 256 ++++++++++ 47 files changed, 5627 insertions(+) create mode 100644 .gitmodules create mode 100644 dial/base.jpg create mode 100644 dial/base.svg create mode 100644 dial/try1.svg create mode 100644 dial/try2.svg create mode 100644 dial/try3.svg create mode 100644 stm32/.gitignore create mode 100644 stm32/Makefile.include create mode 100644 stm32/Makefile.rules create mode 100644 stm32/app/Makefile create mode 100644 stm32/app/asm_fns.h create mode 100644 stm32/app/board.h create mode 100644 stm32/app/cdcacm.c create mode 100644 stm32/app/clock.ld create mode 100644 stm32/app/dfu.c create mode 100644 stm32/app/dummy_kb.c create mode 100644 stm32/app/events.c create mode 100644 stm32/app/gdb.script create mode 100644 stm32/app/hands.c create mode 100644 stm32/app/main.c create mode 100644 stm32/app/motor.c create mode 100644 stm32/app/pins.h create mode 100644 stm32/app/project.h create mode 100644 stm32/app/prototypes.h create mode 100644 stm32/app/ring.c create mode 100644 stm32/app/ring.h create mode 100644 stm32/app/rtc.c create mode 100644 stm32/app/ticker.c create mode 100644 stm32/app/time_fn.c create mode 100644 stm32/app/time_fn.h create mode 100644 stm32/app/usart.c create mode 100644 stm32/app/usb.c create mode 100644 stm32/boot/Makefile create mode 100644 stm32/boot/gdb.script create mode 100644 stm32/boot/project.h create mode 100644 stm32/boot/prototypes.h create mode 100644 stm32/boot/usbdfu.c create mode 100644 stm32/boot/usbdfu.ld create mode 100644 stm32/docs/Astronomical Algorithms.pdf create mode 100644 stm32/docs/rm0008.pdf create mode 100644 stm32/id.h create mode 160000 stm32/libopencm3 create mode 100644 stm32/oocd/board/STM32F103R_BOARD.cfg create mode 100644 stm32/oocd/interface/j-link.cfg create mode 100644 stm32/oocd/interface/stlink-v2.cfg create mode 100644 stm32/oocd/stm32-f103.cfg create mode 100755 stm32/tools/dfuse-pack.py diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..981d79a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "stm32/libopencm3"] + path = stm32/libopencm3 + url = git://git.panaceas.org/stm32/libopencm3 diff --git a/dial/base.jpg b/dial/base.jpg new file mode 100644 index 0000000..adaa1ef Binary files /dev/null and b/dial/base.jpg differ diff --git a/dial/base.svg b/dial/base.svg new file mode 100644 index 0000000..3866756 --- /dev/null +++ b/dial/base.svg @@ -0,0 +1,851 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dial/try1.svg b/dial/try1.svg new file mode 100644 index 0000000..9cfb1a7 --- /dev/null +++ b/dial/try1.svg @@ -0,0 +1,860 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dial/try2.svg b/dial/try2.svg new file mode 100644 index 0000000..fd61d07 --- /dev/null +++ b/dial/try2.svg @@ -0,0 +1,299 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dial/try3.svg b/dial/try3.svg new file mode 100644 index 0000000..fe0f89c --- /dev/null +++ b/dial/try3.svg @@ -0,0 +1,328 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/stm32/.gitignore b/stm32/.gitignore new file mode 100644 index 0000000..ac9bbcd --- /dev/null +++ b/stm32/.gitignore @@ -0,0 +1,10 @@ +*.o +*.a +*.d +*.elf +*.map +*.hex +*~ +*.dfu +*.bin +*.orig diff --git a/stm32/Makefile.include b/stm32/Makefile.include new file mode 100644 index 0000000..389aa68 --- /dev/null +++ b/stm32/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/stm32/Makefile.rules b/stm32/Makefile.rules new file mode 100644 index 0000000..6e9fe6c --- /dev/null +++ b/stm32/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/stm32/app/Makefile b/stm32/app/Makefile new file mode 100644 index 0000000..997011f --- /dev/null +++ b/stm32/app/Makefile @@ -0,0 +1,80 @@ +## +## 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=clock + +LDLIBS+=-lm + +V=1 +default: ${PROG}.elf + +CSRCS= main.c cdcacm.c dfu.c ring.c usart.c ticker.c dummy_kb.c usb.c rtc.c time_fn.c events.c hands.c motor.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.. + + +%.bin: %.elf + $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).bin + +%.dfu:%.bin + ../tools/dfuse-pack.py -D 0x483:0xff03 -b 0x08002000:$< $@ + +dfu:${PROG}.bin + dfu-util -R -a 0 -d 0483:ff03,0483:df11 -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 + +ds: + $(Q)$(OOCD) -f $(OOCD_INTERFACE) \ + -f $(OOCD_BOARD) \ + +debug: ${PROG}.elf + ${PREFIX}-gdb -x gdb.script ${PROG}.elf + +reset: + $(Q)$(OOCD) -f $(OOCD_INTERFACE) \ + -f $(OOCD_BOARD) \ + -c "init" -c "reset run" \ + -c shutdown + + + + +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/stm32/app/asm_fns.h b/stm32/app/asm_fns.h new file mode 100644 index 0000000..b0d10d9 --- /dev/null +++ b/stm32/app/asm_fns.h @@ -0,0 +1,4 @@ +static inline void compiler_mb(void) { +asm volatile (""); +} + diff --git a/stm32/app/board.h b/stm32/app/board.h new file mode 100644 index 0000000..41eeafc --- /dev/null +++ b/stm32/app/board.h @@ -0,0 +1,15 @@ + +#define LED1 GPIO8 +#define LED1_PORT GPIOB + +#define LED2 GPIO9 +#define LED2_PORT GPIOB + + +#define USART1_TX GPIO_USART1_TX +#define USART1_TX_PORT GPIOA + +#define USART1_RX GPIO_USART1_RX +#define USART1_RX_PORT GPIOA + + diff --git a/stm32/app/cdcacm.c b/stm32/app/cdcacm.c new file mode 100644 index 0000000..0b4a4e3 --- /dev/null +++ b/stm32/app/cdcacm.c @@ -0,0 +1,221 @@ +#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 int cdcacm_ready = 0; + +#define COMM_EP 0x83 +#define DATA_IN 0x01 +#define DATA_OUT 0x82 + +static const struct usb_endpoint_descriptor comm_endp[] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = COMM_EP, + .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 = DATA_IN, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = DATA_OUT, + .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 = 3, + }, + .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 = 2, + .bSubordinateInterface0 = 3, + } +}; + +const struct usb_interface_descriptor comm_iface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 2, + .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) +}; + +const struct usb_interface_descriptor data_iface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 3, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + .endpoint = data_endp, +}; + + +const struct usb_iface_assoc_descriptor cdc_iface_assoc = { + .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, + .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, + .bFirstInterface = 2, + .bInterfaceCount = 2, + .bFunctionClass = USB_CLASS_CDC, + .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, + .bFunctionProtocol = USB_CDC_PROTOCOL_AT, + .iFunction = 6, +}; + + + +enum usbd_request_return_codes +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; + + + 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. + */ + return USBD_REQ_HANDLED; + } + + case USB_CDC_REQ_SET_LINE_CODING: + if (*len < sizeof (struct usb_cdc_line_coding)) + return USBD_REQ_NOTSUPP; + + return USBD_REQ_HANDLED; + } + + return USBD_REQ_NEXT_CALLBACK; +} + + + +void cdcacm_tick (void) +{ + unsigned ep = DATA_OUT; + uint8_t buf[16]; + uint8_t *ptr = buf; + size_t n = 0; + + if (!cdcacm_ready) + return; + + if (ring_empty (&cdcacm_tx_ring)) + return; + + /* Return if endpoint is already enabled. */ + 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++; + + if (n == sizeof (buf)) break; + } + + usbd_ep_write_packet (usb_device, ep, buf, n); +} + +int cdcacm_write (char *ptr, int len) +{ + int ret; + + ret = ring_write (&cdcacm_tx_ring, (uint8_t *) ptr, len); + return ret; +} + + + +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, DATA_IN, buf, 64); + + if (len) + ring_write (&cdcacm_rx_ring, buf, len); +} + +void cdcacm_set_config (usbd_device *usbd_dev, uint16_t wValue) +{ + (void) wValue; + + usbd_ep_setup (usbd_dev, DATA_IN, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_rx_cb); + usbd_ep_setup (usbd_dev, DATA_OUT, USB_ENDPOINT_ATTR_BULK, 64, NULL); + usbd_ep_setup (usbd_dev, COMM_EP, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); + cdcacm_ready = 1; +} + +void cdcacm_rings_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)); +} + + diff --git a/stm32/app/clock.ld b/stm32/app/clock.ld new file mode 100644 index 0000000..20cbff9 --- /dev/null +++ b/stm32/app/clock.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 = 120K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K +} + +/* Include the common ld script. */ +INCLUDE cortex-m-generic.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/stm32/app/dfu.c b/stm32/app/dfu.c new file mode 100644 index 0000000..29a2428 --- /dev/null +++ b/stm32/app/dfu.c @@ -0,0 +1,86 @@ +#include "project.h" + +const struct usb_dfu_descriptor dfu_function = { + .bLength = sizeof (struct usb_dfu_descriptor), + .bDescriptorType = DFU_FUNCTIONAL, + .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH, + .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 = 4, + .extra = &dfu_function, + .extralen = sizeof (dfu_function), +}; + + +const struct usb_iface_assoc_descriptor dfu_iface_assoc = { + .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, + .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, + .bFirstInterface = 1, + .bInterfaceCount = 1, + .bFunctionClass = 0xfe, + .bFunctionSubClass = 1, + .bFunctionProtocol = 1, + .iFunction = 5, +}; + + +static void +dfu_detach_complete (usbd_device *usbd_dev, struct usb_setup_data *req) +{ + (void) req; + (void) usbd_dev; + dfu_flag = 0xfee1dead; + + scb_reset_core(); +} + +enum usbd_request_return_codes +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 USBD_REQ_NEXT_CALLBACK; + + 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 USBD_REQ_HANDLED; + } + + case DFU_GETSTATE: + /* Return state with no state transision. */ + *buf[0] = STATE_APP_IDLE; + *len = 1; + return USBD_REQ_HANDLED; + + case DFU_DETACH: + *complete = dfu_detach_complete; + return USBD_REQ_HANDLED; + } + + return USBD_REQ_NEXT_CALLBACK; +} + diff --git a/stm32/app/dummy_kb.c b/stm32/app/dummy_kb.c new file mode 100644 index 0000000..a1d61c7 --- /dev/null +++ b/stm32/app/dummy_kb.c @@ -0,0 +1,26 @@ +#include "project.h" + +const struct usb_interface_descriptor dummy_kb_iface = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, +}; + + +const struct usb_iface_assoc_descriptor dummy_kb_iface_assoc = { + .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, + .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, + .bFirstInterface = 0, + .bInterfaceCount = 1, + .bFunctionClass = 0xff, + .bFunctionSubClass = 0, + .bFunctionProtocol = 0, + .iFunction = 4, +}; + diff --git a/stm32/app/events.c b/stm32/app/events.c new file mode 100644 index 0000000..2ad9b47 --- /dev/null +++ b/stm32/app/events.c @@ -0,0 +1,101 @@ +#include "project.h" + +#define D2R(a) ((a)*(M_PI/180.)) + + + + +// shamelessly stolen from Meeus Astronmical Algorithms Chapter 27 table 27.B +// chapter 25 is probably more tractable, but this is easier to code up + +static double mean_vernal_equinox (unsigned year) +{ + double y = year; + y -= 2000; + y *= 0.001; + return 2451623.80984 + 365242.37404 * y + 0.05169 * (y * y) - 0.00411 * (y * y * y) - 0.00057 * (y * y * y * y); +} + +static double mean_summer_solstice (unsigned year) +{ + double y = year; + y -= 2000; + y *= 0.001; + return 2451716.56767 + 365241.62603 * y + 0.00325 * (y * y) + 0.00888 * (y * y * y) - 0.00030 * (y * y * y * y); +} + +static double mean_autumnal_equinox (unsigned year) +{ + double y = year; + y -= 2000; + y *= 0.001; + return 2451810.21715 + 365242.01767 * y - 0.11575 * (y * y) + 0.00337 * (y * y * y) + 0.00078 * (y * y * y * y); +} + +static double mean_winter_solstice (unsigned year) +{ + double y = year; + y -= 2000; + y *= 0.001; + return 2451900.05952 + 365242.74049 * y - 0.06223 * (y * y) - 0.00823 * (y * y * y) + 0.00032 * (y * y * y * y); +} + + +static double orbital_periodic_terms (double t) +{ +#define N 24 + const double A[N] = {485, 203, 199, 182, 156, 136, 77, 74, 70, 58, 52, 50, 45, + 44, 29, 18, 17, 16, 14, 12, 12, 12, 9, 8 + }; + const double B[N] = {D2R (324.96), D2R (337.23), D2R (342.08), D2R (27.85), + D2R (73.14), D2R (171.52), D2R (222.54), D2R (296.72), + D2R (243.58), D2R (119.81), D2R (297.17), D2R (21.02), + D2R (247.54), D2R (325.15), D2R (60.93), D2R (155.12), + D2R (288.79), D2R (198.04), D2R (199.76), D2R (95.39), + D2R (287.11), D2R (320.81), D2R (227.73), D2R (15.45) + }; + const double C[N] = {D2R (1934.136), D2R (32964.467), D2R (20.186), + D2R (445267.112), D2R (45036.886), D2R (22518.443), + D2R (65928.934), D2R (3034.906), D2R (9037.513), + D2R (33718.147), D2R (150.678), D2R (2281.226), + D2R (29929.562), D2R (31555.956), D2R (4443.417), + D2R (67555.328), D2R (4562.452), D2R (62894.029), + D2R (31436.921), D2R (14577.848), D2R (31931.756), + D2R (34777.259), D2R (1222.114), D2R (16859.074) + }; + double s = 0; + unsigned i; + + for (i = 0; i < N; ++i) + s += A[i] * cos (B[i] + (C[i] * t)); + + return s; +} + + +static double mean_to_real (double j0) +{ + + double t = (j0 - 2451545.) / 36525.; + double w = D2R ((35999.373 * t) - 2.47); + double dl = 1 + 0.0334 * cos (w) + 0.0007 * cos (2. * w); + double s = orbital_periodic_terms (t); + +#if 0 + printf ("j0=%.6f\r\n", j0); + printf ("t=%.6f\r\n", t); + printf ("w=%.6f\r\n", w); + printf ("dl=%.6f\r\n", dl); + printf ("s=%.6f\r\n", s); +#endif + + return j0 + ((0.00001 * s) / dl); +} + + + +double autumnal_equinox (unsigned y) +{ + return mean_to_real (mean_autumnal_equinox (y)); + // return mean_to_real (mean_summer_solstice (y)); +} diff --git a/stm32/app/gdb.script b/stm32/app/gdb.script new file mode 100644 index 0000000..7cf9d09 --- /dev/null +++ b/stm32/app/gdb.script @@ -0,0 +1,2 @@ +target remote localhost:3333 +cont diff --git a/stm32/app/hands.c b/stm32/app/hands.c new file mode 100644 index 0000000..5414d9e --- /dev/null +++ b/stm32/app/hands.c @@ -0,0 +1,90 @@ +#include "project.h" + + +unsigned hands_pos[HANDS]; +unsigned hands_ready; + + +static unsigned calc_minute_pos (MTIME *m) +{ + uint64_t p; + + p = m->minute; + p *= 100; + p += m->second; + p *= 1000; + p += m->nanosecond / 1000000; + + p *= MOTOR_STEPS; + p /= 10000000; + + + + return (unsigned) p; + +} + +static unsigned calc_hour_pos (MTIME *m) +{ + uint64_t p; + + p = m->hour; + p *= 100; + p += m->minute; + p *= 100; + p += m->second; + p *= 1000; + p += m->nanosecond / 1000000; + + p *= MOTOR_STEPS; + p /= 100000000; + + + + return (unsigned) p; +} + + + + +void hands_tick (void) +{ + EPOCH e; + UTC u; + MTIME m; + static unsigned old_pos[HANDS]; + unsigned i, p; + + + static uint32_t last; + + if ((ticks - last) < 100) return; + + last = ticks; + + if (!rtc_ready) return; + + + e = rtc_get(); + u = time_epoch_to_utc (e); + m = time_to_metric (e, u); + + + hands_pos[0] = calc_hour_pos (&m); + hands_pos[1] = calc_minute_pos (&m); + hands_ready = 1; + + for (i = 0, p = 0; i < HANDS; ++i) { + if (hands_pos[i] != old_pos[i]) p++; + + old_pos[i] = hands_pos[i]; + + } + + if (p) { + time_print_utc ("UTC: ", &u, NULL); + time_print_metric ("Metric: ", &m, NULL); + printf ("Hands: hour %4d/%4d min %4d/%4d\r\n", hands_pos[0], MOTOR_STEPS, hands_pos[1], MOTOR_STEPS); + } + +} diff --git a/stm32/app/main.c b/stm32/app/main.c new file mode 100644 index 0000000..4722479 --- /dev/null +++ b/stm32/app/main.c @@ -0,0 +1,50 @@ +#include "project.h" + + + + + +int main (void) +{ + /*set up pll */ + rcc_clock_setup_pll (&rcc_hse_configs[RCC_HSE_CONFIG]); + + /*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); + rcc_periph_clock_enable (RCC_PWR); + rcc_periph_clock_enable (RCC_BKP); + pwr_disable_backup_domain_write_protect(); + DWT_CTRL |= DWT_CTRL_CYCCNTENA; + + + nvic_set_priority (NVIC_SYSTICK_IRQ, 0x80); + nvic_set_priority (NVIC_USART1_IRQ, 0x40); + nvic_set_priority (NVIC_USB_HP_CAN_TX_IRQ, 0x40); + nvic_set_priority (NVIC_USB_LP_CAN_RX0_IRQ, 0x40); + nvic_set_priority (NVIC_RTC_IRQ, 0x10); + + MAP_OUTPUT_OD (LED1); + MAP_OUTPUT_OD (LED2); + + + usart_init(); + cdcacm_rings_init(); + rtc_init(); + + printf ("Startup:\r\n"); + + motor_init(); + ticker_init(); + usb_init(); + + + for (;;); + + + return 0; +} + diff --git a/stm32/app/motor.c b/stm32/app/motor.c new file mode 100644 index 0000000..392089b --- /dev/null +++ b/stm32/app/motor.c @@ -0,0 +1,75 @@ +#include "project.h" + + +static unsigned motor_pos[HANDS]; + + +static void coils (unsigned m, int a, int b, int c, int d) +{ + printf ("Motor %d: %+d %+d\r\n", m, a - b, c - d); +} + +static void step (unsigned m, int d) +{ + unsigned s = motor_pos[m]; + + if (d < 0) d += MOTOR_STEPS; + + s += d; + s %= MOTOR_STEPS; + + coils (m, !! ((s + 6) & 4), !! ((s + 1) & 4), !! ((s + 4) & 4), !! ((s + 7) & 4)); + + if (!m) + BKP_DR8 = motor_pos[0] = s; + else + BKP_DR9 = motor_pos[1] = s; + + +} + + + + + +void motor_tick (void) +{ + static uint32_t last; + unsigned i, d; + + if ((ticks - last) < 10) return; + + last = ticks; + + if (!hands_ready) return; + + //printf("HANDS: %d -> %d %d -> %d\r\n",hands_pos[0],motor_pos[0],hands_pos[1],motor_pos[1]); + + + for (i = 0; i < HANDS; ++i) { + d = MOTOR_STEPS + hands_pos[i]; + d -= motor_pos[i]; + d %= MOTOR_STEPS; + + if (d) { + if (d < (MOTOR_STEPS / 2)) + step (i, 1); + else + step (i, -1); + } + } +} + + + + +void motor_init (void) +{ + + motor_pos[0] = BKP_DR8; + motor_pos[1] = BKP_DR9; + + step (0, 0); + step (1, 0); + +} diff --git a/stm32/app/pins.h b/stm32/app/pins.h new file mode 100644 index 0000000..954396f --- /dev/null +++ b/stm32/app/pins.h @@ -0,0 +1,54 @@ +#ifndef _PINS_H_ +#define _PINS_H_ + +/* st seem to change these with every chip revision */ + +#define MAP_ANA(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_ANALOG, a ); \ + } while (0) + +#define MAP_AF(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, a ); \ + } while (0) + +/* STM32F1 doesn't have AF pull up, but also doesn't disconnect af inputs so just use regular pull up */ +#define MAP_AF_PU(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, a); \ + gpio_set( a ## _PORT, a); \ + } while (0) + +#define MAP_AF_OD(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, a ); \ + } while (0) + + +#define MAP_OUTPUT_PP(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, a ); \ + } while (0) + + +#define MAP_OUTPUT_OD(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, a ); \ + } while (0) + + +/* STM32F1 madly uses the output register to drive the other end of the resistor, so pull up */ +/* requires us to write a 1 there */ + +#define MAP_INPUT_PU(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, a); \ + gpio_set( a ## _PORT, a); \ + } while (0) + + +#define MAP_INPUT(a) do { \ + gpio_set_mode( a ## _PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, a); \ + } while (0) + + +#define CLEAR(a) gpio_clear( a ## _PORT, a) +#define SET(a) gpio_set( a ## _PORT, a) +#define GET(a) gpio_get( a ## _PORT, a) +#define TOGGLE(a) gpio_toggle( a ## _PORT, a) + +#endif diff --git a/stm32/app/project.h b/stm32/app/project.h new file mode 100644 index 0000000..fd71876 --- /dev/null +++ b/stm32/app/project.h @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +#define RCC_HSE_CONFIG RCC_CLOCK_HSE8_72MHZ +#define US (72) +#define MS (US * 1000) +#define HZ (MS * 1000) +#define MS_TO_TICKS(a) ((a) *2) + +#define TRACE do { printf("%s:%d\r\n",__FILE__,__LINE__); } while (0) + +#define DWT_FREQ 48000000 + +#define HANDS 2 +#define MOTOR_STEPS (1080 * 2) + +#include "board.h" +#include "ring.h" +#include "pins.h" +#include "time_fn.h" +#include "asm_fns.h" + +#include "prototypes.h" + + + +extern uint32_t dfu_flag; diff --git a/stm32/app/prototypes.h b/stm32/app/prototypes.h new file mode 100644 index 0000000..751ba25 --- /dev/null +++ b/stm32/app/prototypes.h @@ -0,0 +1,81 @@ +/* main.c */ +extern int main(void); +/* cdcacm.c */ +extern ring_t cdcacm_rx_ring; +extern ring_t cdcacm_tx_ring; +extern const struct usb_interface_descriptor comm_iface; +extern const struct usb_interface_descriptor data_iface; +extern const struct usb_iface_assoc_descriptor cdc_iface_assoc; +extern enum usbd_request_return_codes cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete); +extern void cdcacm_tick(void); +extern int cdcacm_write(char *ptr, int len); +extern void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue); +extern void cdcacm_rings_init(void); +/* dfu.c */ +extern const struct usb_dfu_descriptor dfu_function; +extern const struct usb_interface_descriptor dfu_iface; +extern const struct usb_iface_assoc_descriptor dfu_iface_assoc; +extern enum usbd_request_return_codes 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 volatile uint32_t ticks; +extern unsigned led2; +extern void delay_us(uint32_t d); +extern void sys_tick_handler(void); +extern void ticker_init(void); +extern void delay_ms(uint32_t d); +/* dummy_kb.c */ +extern const struct usb_interface_descriptor dummy_kb_iface; +extern const struct usb_iface_assoc_descriptor dummy_kb_iface_assoc; +/* usb.c */ +extern uint8_t usbd_control_buffer[128]; +extern usbd_device *usb_device; +extern void usb_hp_can_tx_isr(void); +extern void usb_lp_can_rx0_isr(void); +extern void usb_init(void); +/* rtc.c */ +extern volatile unsigned rtc_ready; +extern void rtc_isr(void); +extern EPOCH rtc_get(void); +extern void rtc_init(void); +/* time_fn.c */ +extern EPOCH time_epoch_sub(EPOCH a, EPOCH b); +extern EPOCH time_epoch_add(EPOCH a, EPOCH b); +extern UTC time_epoch_to_utc(EPOCH epoch); +extern EPOCH time_utc_to_epoch(UTC u); +extern void utc_to_str(char *dst, UTC *u); +extern void time_print_utc(const char *p, UTC *u, const char *t); +extern void time_print_epoch(const char *p, EPOCH e, const char *t); +extern double time_utc_to_tjd(UTC u); +extern EPOCH time_tjd_to_epoch(double tjd); +extern UTC time_tjd_to_utc(double tjd); +extern RA ra_normalize(RA r); +extern RA time_utc_to_ra(UTC u); +extern RA time_st_to_ra(ST st); +extern ST time_ra_to_st(RA r); +extern ST time_utc_to_lst(UTC u, double lon); +extern MTIME time_to_metric(EPOCH e, UTC u); +extern MTIME time_utc_to_metric(UTC u); +extern MTIME time_epoch_to_metric(EPOCH e); +extern void time_print_metric(const char *p, MTIME *m, const char *t); +/* events.c */ +extern double autumnal_equinox(unsigned y); +/* hands.c */ +extern unsigned hands_pos[2]; +extern unsigned hands_ready; +extern void hands_tick(void); +/* motor.c */ +extern void motor_tick(void); +extern void motor_init(void); diff --git a/stm32/app/ring.c b/stm32/app/ring.c new file mode 100644 index 0000000..26bba3a --- /dev/null +++ b/stm32/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/stm32/app/ring.h b/stm32/app/ring.h new file mode 100644 index 0000000..ba8887b --- /dev/null +++ b/stm32/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/stm32/app/rtc.c b/stm32/app/rtc.c new file mode 100644 index 0000000..0030cfd --- /dev/null +++ b/stm32/app/rtc.c @@ -0,0 +1,170 @@ +#include "project.h" + +static volatile uint32_t hz = HZ; +static volatile uint32_t cycle_ref; +static volatile uint32_t rtc_ref; + +#define RTC_IN_LH 0x21f7 +#define RTC_IN_UH 0x6a6d + +static EPOCH rtc_offset; +static uint16_t rtc_half; + +volatile unsigned rtc_ready; + + + + +static EPOCH bkp_read_off (void) +{ + EPOCH e; + uint64_t v; + + v = BKP_DR1 & 0xffff; + v <<= 16; + v |= (BKP_DR2 & 0xffff); + v <<= 16; + v |= (BKP_DR3 & 0xffff); + v <<= 16; + v |= (BKP_DR4 & 0xffff); + + e.s = (int64_t) v; + + v = BKP_DR5 & 0xffff; + v <<= 16; + v |= (BKP_DR6 & 0xffff); + + e.ns = (int64_t) v; + + return e; +} + +static void bkp_write_off (EPOCH e) +{ + uint64_t v; + + v = (uint64_t) e.s; + + BKP_DR4 = (uint16_t) (v & 0xffff); + v >>= 16; + BKP_DR3 = (uint16_t) (v & 0xffff); + v >>= 16; + BKP_DR2 = (uint16_t) (v & 0xffff); + v >>= 16; + BKP_DR1 = (uint16_t) (v & 0xffff); + + v = (uint64_t) e.ns; + + BKP_DR6 = (uint16_t) (v & 0xffff); + v >>= 16; + BKP_DR5 = (uint16_t) (v & 0xffff); + +} + + + +void rtc_isr (void) +{ + uint32_t now; + static uint32_t then; + uint32_t v; + static int warm_up = 3; + + + now = DWT_CYCCNT; + compiler_mb(); + rtc_clear_flag (RTC_SEC); + + v = rtc_get_counter_val(); + + TOGGLE (LED1); + + cycle_ref = now; + + if (warm_up) warm_up--; + else hz = now - then; + + + switch (rtc_half) { + case RTC_IN_LH: + if (! (v & 0x8000000)) break; + + BKP_DR7 = rtc_half = RTC_IN_UH; + break; + + case RTC_IN_UH: + if (v & 0x8000000) break; + + BKP_DR7 = rtc_half = RTC_IN_LH; + rtc_offset.s += 0x100000000ULL; + bkp_write_off (rtc_offset); + break; + + default: + if (v & 0x8000000) + BKP_DR7 = rtc_half = RTC_IN_UH; + else + BKP_DR7 = rtc_half = RTC_IN_LH; + } + + + compiler_mb(); + rtc_ref = v; + rtc_ready = 1; + + + // printf ("Ctr %d %u %u\r\n", (int) v, (int) (now - then),(unsigned) rtc_offset.s); + + then = now; +} + + +EPOCH rtc_get (void) +{ + EPOCH e, o; + uint32_t h, c, r1, r2; + uint32_t now = DWT_CYCCNT; + + do { + r1 = rtc_ref; + compiler_mb(); + c = cycle_ref; + h = hz; + o = rtc_offset; + compiler_mb(); + r2 = rtc_ref; + } while (r1 != r2); + + now -= c; + + e.ns = now; + e.ns *= 1000000000ULL; + + if (h) e.ns /= h; + else e.ns /= HZ; + + e.s = r1; + + return time_epoch_add (e, o); +} + + +void rtc_init (void) +{ + rtc_offset = bkp_read_off(); + rtc_half = BKP_DR7; + +#if 1 + rtc_offset.s = 1637490753; + rtc_offset.ns = 498866999; + bkp_write_off (rtc_offset); +#endif + + + rtc_auto_awake (RCC_LSE, 0x7fff); //32768Hz + rtc_interrupt_enable (RTC_SEC); + nvic_enable_irq (NVIC_RTC_IRQ); + +} + + diff --git a/stm32/app/ticker.c b/stm32/app/ticker.c new file mode 100644 index 0000000..f124307 --- /dev/null +++ b/stm32/app/ticker.c @@ -0,0 +1,74 @@ +#include "project.h" + + +volatile uint32_t ticks; +static uint32_t scale = 7; + +unsigned led2 = 1000; + + + +void +delay_us (uint32_t d) +{ + d *= scale; + + while (d--) + __asm__ ("nop"); +} + +void +sys_tick_handler (void) +{ + ticks++; + cdcacm_tick(); + hands_tick(); + motor_tick(); + + if (led2) + led2--; + + if (led2) + CLEAR (LED2); + + else + SET (LED2); +} + +void +ticker_init (void) +{ + uint32_t v, w; + /*Start periodic timer */ + systick_set_clocksource (STK_CSR_CLKSOURCE_AHB_DIV8); + /* 72MHz / 8 = > 9Mhz */ + systick_set_reload (9000); + /* 9MHz / 9000 => 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); + +} + + +void delay_ms (uint32_t d) +{ + uint32_t v = ticks; + + while ((ticks - v) < d); +} + + diff --git a/stm32/app/time_fn.c b/stm32/app/time_fn.c new file mode 100644 index 0000000..825d90f --- /dev/null +++ b/stm32/app/time_fn.c @@ -0,0 +1,650 @@ +#include +#include "project.h" + +static int is_leap (unsigned year) +{ + if (year % 4) + return 0; + + if (year % 100) + return 1; + + if (year % 400) + return 0; + + return 1; +} + +EPOCH time_epoch_sub (EPOCH a, EPOCH b) +{ + EPOCH ret; + + ret.ns = a.ns - b.ns; + ret.s = a.s - b.s; + + if (!ret.s) return ret; + + if (ret.ns < 0) { + ret.s--; + ret.ns += 1000000000; + } + + return ret; +} + + +EPOCH time_epoch_add (EPOCH a, EPOCH b) +{ + EPOCH ret; + + ret.ns = a.ns + b.ns; + ret.s = a.s + b.s; + + while (ret.ns > 1000000000) { + ret.s++; + ret.ns -= 1000000000; + } + + return ret; +} + + +UTC time_epoch_to_utc (EPOCH epoch) +{ + UTC u = {0}; + uint64_t day; + unsigned y400, y100, y4; + + day = epoch.s / 86400; + epoch.s -= day * 86400; + + day += 134774; + + u.wday = day % 7; + u.wday++; + + + y400 = day / 146097; /*146097 days in 400 years */ + day -= (y400 * 146097); + + y100 = day / 36524; /*36524 days in 100 years */ + day -= (y100 * 36524); + + y4 = day / 1461; /*1461 days in 4 years */ + day -= (y4 * 1461); + + /* This may look redundant but 31 Dec in year 4 is special case */ + if (day < 1095) { /*1095 days in 3 years */ + u.year = day / 365; /*365 days in a year */ + day -= (365 * u.year); + } else { + u.year = 3; + day -= 1095; + } + + + /* Now put it all back together */ + u.year += 1601; + u.year += 4 * y4; + u.year += 100 * y100; + u.year += 400 * y400; + + + u.jday = day + 1; + + u.is_leap = is_leap (u.year); + + + if (!u.is_leap) { + /*Days and months for ordinary years */ + if (u.jday < 32) { + u.month = 1; + u.mday = u.jday; + } else if (u.jday < 60) { + u.month = 2; + u.mday = u.jday - 31; + } else if (u.jday < 91) { + u.month = 3; + u.mday = u.jday - 59; + } else if (u.jday < 121) { + u.month = 4; + u.mday = u.jday - 90; + } else if (u.jday < 152) { + u.month = 5; + u.mday = u.jday - 120; + } else if (u.jday < 182) { + u.month = 6; + u.mday = u.jday - 151; + } else if (u.jday < 213) { + u.month = 7; + u.mday = u.jday - 181; + } else if (u.jday < 244) { + u.month = 8; + u.mday = u.jday - 212; + } else if (u.jday < 274) { + u.month = 9; + u.mday = u.jday - 243; + } else if (u.jday < 305) { + u.month = 10; + u.mday = u.jday - 273; + } else if (u.jday < 335) { + u.month = 11; + u.mday = u.jday - 304; + } else { + u.month = 12; + u.mday = u.jday - 334; + } + } else { + /*And leap years */ + if (u.jday < 32) { + u.month = 1; + u.mday = u.jday; + } else if (u.jday < 61) { + u.month = 2; + u.mday = u.jday - 31; + } else if (u.jday < 92) { + u.month = 3; + u.mday = u.jday - 60; + } else if (u.jday < 122) { + u.month = 4; + u.mday = u.jday - 91; + } else if (u.jday < 153) { + u.month = 5; + u.mday = u.jday - 121; + } else if (u.jday < 183) { + u.month = 6; + u.mday = u.jday - 152; + } else if (u.jday < 214) { + u.month = 7; + u.mday = u.jday - 182; + } else if (u.jday < 245) { + u.month = 8; + u.mday = u.jday - 213; + } else if (u.jday < 275) { + u.month = 9; + u.mday = u.jday - 244; + } else if (u.jday < 306) { + u.month = 10; + u.mday = u.jday - 274; + } else if (u.jday < 336) { + u.month = 11; + u.mday = u.jday - 305; + } else { + u.month = 12; + u.mday = u.jday - 335; + } + } + + u.hour = epoch.s / 3600; + epoch.s -= u.hour * 3600; + u.minute = epoch.s / 60; + epoch.s -= u.minute * 60; + u.second = epoch.s; + + u.nanosecond = epoch.ns; + + return u; +} + +EPOCH time_utc_to_epoch (UTC u) +{ + unsigned y400; + unsigned y100; + unsigned y4; + + EPOCH ret; + + static int const mdays[] = + { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + static int const lmdays[] = + { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; + + u.is_leap = is_leap (u.year); + + if (u.year < 100) u.year += 2000; + + + if (!u.jday) { + if (u.is_leap) + u.jday = u.mday + lmdays[u.month]; + else + u.jday = u.mday + mdays[u.month]; + } + + u.year -= 1601; + y400 = u.year / 400; + u.year -= y400 * 400; + y100 = u.year / 100; + u.year -= y100 * 100; + y4 = u.year / 4; + u.year -= y4 * 4; + + + + ret.s = u.jday - 1; + ret.s += u.year * 365; + ret.s += y4 * 1461; + ret.s += y100 * 36524; + ret.s += y400 * 146097; + + ret.s -= 134774; + + ret.s *= 86400; + + ret.s += u.second; + ret.s += u.minute * 60; + ret.s += u.hour * 3600; + + ret.ns = u.nanosecond; + + return ret; +} + +void utc_to_str (char *dst, UTC *u) +{ + const char *dname[] = {"Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat", "Sun"}; + const char *mname[] = {"", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + sprintf (dst, "%s %04d-%s-%02d %02d:%02d:%02d.%09d", dname[u->wday], u->year, mname[u->month], u->mday, u->hour, u->minute, u->second, u->nanosecond); +} + + +void time_print_utc (const char *p, UTC *u, const char *t) +{ + const char *dname[] = {"Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat", "Sun"}; + const char *mname[] = {"", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + printf ("%s%s %04d-%s-%02d %02d:%02d:%02d.%09d %s\r\n", p ? p : "", dname[u->wday], u->year, mname[u->month], u->mday, u->hour, u->minute, u->second, u->nanosecond, t ? t : ""); +} + +void time_print_epoch (const char *p, EPOCH e, const char *t) +{ + UTC u = time_epoch_to_utc (e); + time_print_utc (p, &u, t); +} + + +double +time_utc_to_tjd (UTC u) +{ + unsigned y400; + unsigned y100; + unsigned y4; + + double ret; + unsigned jd; + + static int const mdays[] = + { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + static int const lmdays[] = + { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; + + u.is_leap = is_leap (u.year); + + if (u.year < 100) + u.year += 2000; + + + if (!u.jday) { + if (u.is_leap) + u.jday = u.mday + lmdays[u.month]; + else + u.jday = u.mday + mdays[u.month]; + } + + u.year -= 1601; + y400 = u.year / 400; + u.year -= y400 * 400; + y100 = u.year / 100; + u.year -= y100 * 100; + y4 = u.year / 4; + u.year -= y4 * 4; + + jd = u.jday - 1; + jd += u.year * 365; + jd += y4 * 1461; + jd += y100 * 36524; + jd += y400 * 146097; + + + jd += 2305813; + jd -= 2451545; + + + + ret = (double) u.nanosecond; + ret /= 1000000000.; + ret += (double) u.second; + ret /= 60.; + ret += (double) u.minute; + ret /= 60.; + ret += (double) u.hour; + ret /= 24.; + + ret += .5; + + ret += (double) jd; + + return ret; +} + + +EPOCH time_tjd_to_epoch (double tjd) +{ + EPOCH e; + + + tjd -= 2440587.5; + + tjd *= 86400.; + e.s = (uint64_t) floor (tjd); + + tjd -= (double) e.s; + + tjd *= 1000000000.; + e.ns = (unsigned) floor (tjd); + + return e; +} + +UTC time_tjd_to_utc (double tjd) +{ + return time_epoch_to_utc (time_tjd_to_epoch (tjd)); +} + + + +RA ra_normalize (RA r) +{ + + while (r.ra < 0.) { + r.ra += 360.; + r.days--; + } + + if (r.ra >= 3600.0) { + r.days = (unsigned) (floor (r.ra / 360.) + .5); + r.ra = remainder (r.ra, 360.); + } else while (r.ra >= 360.0) { + r.ra -= 360.; + r.days++; + } + + return r; +} + + +RA time_utc_to_ra (UTC u) +{ + RA r; + double tjd = time_utc_to_tjd (u); + double T = tjd / 36525.; + + r.ra = + 280.46061837 + (360.98564736629 * tjd) + (0.000387933 * T * T) - + (T * T * T / 38710000.0); + + r.days = 0; + + return ra_normalize (r); +} + + + +RA time_st_to_ra (ST st) +{ + RA r; + unsigned i; + + r.days = st.days; + + i = st.hour; + i *= 60; + i += st.minute; + i *= 60; + i += st.second; + + r.ra = (double) st.nanosecond; + r.ra /= 1000000000.; + r.ra += (double) i; + + r.ra /= 240.; + + return r; +} + + + +ST +time_ra_to_st (RA r) +{ + ST ret; + unsigned i; + + r = ra_normalize (r); + + ret.days = r.days; + + r.ra *= 240.0; + + i = (int) (floor (r.ra) + .5); + r.ra -= (double) i; + r.ra *= 1000000000.; + + ret.nanosecond = (unsigned) (r.ra + .5); + ret.second = i % 60; + i /= 60; + ret.minute = i % 60; + i /= 60; + ret.hour = i; + + + return ret; +} + + + +ST time_utc_to_lst (UTC u, double lon) +{ + RA r; + + r = time_utc_to_ra (u); + + r.ra += lon; + + return time_ra_to_st (r); +} + + + +#if 0 +int time_ra_cmp (double a, double b) +{ + return (ra_normalize (a - b) < 180.) ? -1 : 1;; +} + + +/*Find the next occuring time for RA tra */ + +static int test_side (EPOCH m, double tra) +{ + + double ra; + UTC u; + + u = time_epoch_to_utc (m); + ra = time_utc_to_ra (u); + + return time_ra_cmp (ra, tra); +} + + +EPOCH time_ra_to_next_epoch (EPOCH l, double tra) +{ + EPOCH r, m; + unsigned n; + + int dog = 48; + + printf ("time_ra_to_next_epoch %.9f\n", tra); + + /* XXX: we should use newton raphson, but */ + /* 1) we're on team hooke */ + /* 2) we want to limit the domain of solutions */ + /* So IB works better */ + + + while ((test_side (l, tra) != 1) && dog--) + l.s += 3600; + + r = l; + + while ((test_side (r, tra) != -1) && dog--) + r.s += 3600; + + for (n = 0; n < 64; ++n) { + + m = time_epoch_sub (r, l); + + if (m.s < 0) { + m.s = 0; + m.ns = 0; + break; + } + + if (m.s & 1) + m.ns += 1000000000; + + m.s /= 2; + m.ns /= 2; + + m = time_epoch_add (l, m); + + if (test_side (m, tra) < 0) + r = m; + else + l = m; + } + + return m; +} + +#endif + + + + + +/* + * Returns the EPOCH for the start of the metric year which + * starts in the custumary year y + * + * the metric year begins on the autumnal equinox (at the paris observatory natch.) + */ +static EPOCH start_of_year (unsigned y) +{ + double tjd = autumnal_equinox (y); + UTC u; + + tjd += (2.3372305555 / 360); /* Offset of paris meridian from greenwich */ + + u = time_tjd_to_utc (tjd); + + u.hour = + u.minute = + u.second = + u.nanosecond = 0; + + return time_utc_to_epoch (u); +} + +MTIME time_to_metric (EPOCH e, UTC u) +{ + MTIME ret; + + static EPOCH year_start, year_end; + static unsigned year; + + unsigned s; + unsigned d; + + double fd; + + EPOCH equinox; + + if ((e.s > year_end.s) || (e.s < year_start.s)) { + /*calculate the equinox in this customary year */ + + equinox = start_of_year (u.year); + + if (e.s < equinox.s) { + year_start = start_of_year (u.year - 1); + year_end = equinox; + year = u.year - 1792; + } else { + year_start = equinox; + year_end = start_of_year (u.year + 1); + year = u.year - 1791; + } + } + + ret.year = year; + + e = time_epoch_sub (e, year_start); + s = e.s; + d = s / 86400; + s -= d * 86400; + + ret.jday = d; + + ret.month = (d / 30) + 1; + ret.mday = (d % 30) + 1; + ret.wday = d % 10; + + /* Now for the horror of time of day */ + + fd = (double) e.ns; + fd /= 1000000000.; + fd += (double) s; + fd /= 86400.; + fd *= 100000; + + s = (int) fd; + fd -= (double) s; + fd *= 1000000000.; + + ret.nanosecond = (int) fd; + + ret.second = s % 100; + s -= ret.second; + s /= 100; + + ret.minute = s % 100; + s -= ret.minute; + s /= 100; + + ret.hour = s; + + return ret; +} + + +MTIME time_utc_to_metric (UTC u) +{ + return time_to_metric (time_utc_to_epoch (u), u); +} + + +MTIME time_epoch_to_metric (EPOCH e) +{ + return time_to_metric (e, time_epoch_to_utc (e)); +} + + + +void time_print_metric (const char *p, MTIME *m, const char *t) +{ + const char *dname[] = {"Pri", "Duo", "Tri", "Qua", "Qui", "Sex", "Sep", "Oct", "Non", "Dec" }; + const char *mname[] = {"", "Ven", "Bru", "Fri", "Niv", "Plu", "Ven", "Ger", "Flo", "Pra", "Mes", "The", "Fru", "San"}; + printf ("%s%s %03d-%s-%02d %01d:%02d:%02d.%09d %s\r\n", p ? p : "", dname[m->wday], m->year, mname[m->month], m->mday, m->hour, m->minute, m->second, m->nanosecond, t ? t : ""); +} + + diff --git a/stm32/app/time_fn.h b/stm32/app/time_fn.h new file mode 100644 index 0000000..0775a0f --- /dev/null +++ b/stm32/app/time_fn.h @@ -0,0 +1,47 @@ +typedef struct { + unsigned year; + unsigned is_leap; + unsigned jday; + unsigned month; + unsigned mday; + unsigned wday; + unsigned hour; + unsigned minute; + unsigned second; + unsigned nanosecond; +} UTC; + +typedef struct { + int64_t s; + int64_t ns; +} EPOCH; + + +typedef struct { + unsigned days; + double ra; +} RA; + +typedef struct { + unsigned days; + unsigned hour; + unsigned minute; + unsigned second; + unsigned nanosecond; +} ST; + + +typedef struct { + unsigned year; + unsigned is_leap; + unsigned jday; + unsigned month; + unsigned mday; + unsigned wday; + unsigned hour; + unsigned minute; + unsigned second; + unsigned nanosecond; +} MTIME; + + diff --git a/stm32/app/usart.c b/stm32/app/usart.c new file mode 100644 index 0000000..6b44656 --- /dev/null +++ b/stm32/app/usart.c @@ -0,0 +1,88 @@ +#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(); + ring_write (&cdcacm_tx_ring, (uint8_t *) ptr, len); + + 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_AF (USART1_TX); + MAP_AF_PU (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/stm32/app/usb.c b/stm32/app/usb.c new file mode 100644 index 0000000..e644270 --- /dev/null +++ b/stm32/app/usb.c @@ -0,0 +1,148 @@ +#include "project.h" + +#define USB_DM GPIO11 +#define USB_DM_PORT GPIOA +#define USB_DP GPIO12 +#define USB_DP_PORT GPIOA + +/* Buffer to be used for control requests. */ +uint8_t usbd_control_buffer[128]; +usbd_device *usb_device; + +static const struct usb_device_descriptor dev = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = 0xef, + .bDeviceSubClass = 0x02, + .bDeviceProtocol = 0x01, + .bMaxPacketSize0 = 64, + .idVendor = 0x0483, + .idProduct = 0xff03, + .bcdDevice = 0x0200, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + + +static const struct usb_interface ifaces[] = { + { + .num_altsetting = 1, + .altsetting = &dummy_kb_iface, + .iface_assoc = &dummy_kb_iface_assoc, + }, + { + .num_altsetting = 1, + .altsetting = &dfu_iface, + .iface_assoc = &dfu_iface_assoc, + }, + { + .num_altsetting = 1, + .altsetting = &comm_iface, + .iface_assoc = &cdc_iface_assoc, + }, + { + .num_altsetting = 1, + .altsetting = &data_iface, + }, +}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 4, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + .interface = ifaces, +}; +#define N_USB_STRINGS (sizeof(usb_strings)/sizeof(usb_strings[0])) + +static const char *usb_strings[] = { + VENDOR_NAME, /*1*/ + PRODUCT_NAME, /*2*/ + SERIAL_NUMBER, /*3*/ + "dummy device", /*4*/ + "DFU interface", /*5*/ + "Debug interface", /*6*/ +}; + +void usb_hp_can_tx_isr (void) +{ + usbd_poll (usb_device); +} + +void usb_lp_can_rx0_isr (void) +{ + usbd_poll (usb_device); +} + +static enum usbd_request_return_codes control_request (usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, + uint16_t *len, + usbd_control_complete_callback *complete) +{ + enum usbd_request_return_codes ret; + + ret = dfu_control_request (usbd_dev, req, buf, len, complete); + + if (ret != USBD_REQ_NEXT_CALLBACK) + return ret; + + ret = cdcacm_control_request (usbd_dev, req, buf, len, complete); + + if (ret != USBD_REQ_NEXT_CALLBACK) + return ret; + + return USBD_REQ_NOTSUPP; +} + +static void set_config (usbd_device *usbd_dev, uint16_t wValue) +{ + + cdcacm_set_config (usbd_dev, wValue); + + usbd_register_control_callback (usbd_dev, + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + control_request); + +} + + + +void usb_init (void) +{ + /*Force USB reset */ + gpio_set_mode (GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO11); + gpio_set_mode (GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO12); + gpio_clear (GPIOA, GPIO12); + gpio_clear (GPIOA, GPIO13); + delay_us (50000); + gpio_set_mode (GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO11); + gpio_set_mode (GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO12); + + + usb_device = usbd_init (&st_usbfs_v1_usb_driver, + &dev, + &config, + usb_strings, + N_USB_STRINGS, + usbd_control_buffer, + sizeof (usbd_control_buffer)); + + usbd_register_set_config_callback (usb_device, set_config); + + nvic_enable_irq (NVIC_USB_HP_CAN_TX_IRQ); + nvic_enable_irq (NVIC_USB_LP_CAN_RX0_IRQ); + + + +} + + diff --git a/stm32/boot/Makefile b/stm32/boot/Makefile new file mode 100644 index 0000000..4891184 --- /dev/null +++ b/stm32/boot/Makefile @@ -0,0 +1,48 @@ +## +## 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.. + +ds: + $(Q)$(OOCD) -f $(OOCD_INTERFACE) \ + -f $(OOCD_BOARD) \ + +debug: ${PROG}.elf + ${PREFIX}-gdb -x gdb.script ${PROG}.elf + +reset: + $(Q)$(OOCD) -f $(OOCD_INTERFACE) \ + -f $(OOCD_BOARD) \ + -c "init" -c "reset run" \ + -c shutdown + +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/stm32/boot/gdb.script b/stm32/boot/gdb.script new file mode 100644 index 0000000..7cf9d09 --- /dev/null +++ b/stm32/boot/gdb.script @@ -0,0 +1,2 @@ +target remote localhost:3333 +cont diff --git a/stm32/boot/project.h b/stm32/boot/project.h new file mode 100644 index 0000000..0323569 --- /dev/null +++ b/stm32/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/stm32/boot/prototypes.h b/stm32/boot/prototypes.h new file mode 100644 index 0000000..45d399c --- /dev/null +++ b/stm32/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/stm32/boot/usbdfu.c b/stm32/boot/usbdfu.c new file mode 100644 index 0000000..7cba7f9 --- /dev/null +++ b/stm32/boot/usbdfu.c @@ -0,0 +1,334 @@ +/* + * 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 = 0x0483, + .idProduct = 0xdf11, + .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 | USB_DFU_WILL_DETACH, + .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[] = { + VENDOR_NAME, + PRODUCT_NAME " (dfu mode)", + SERIAL_NUMBER, + /* This string is used by ST Microelectronics' DfuSe utility. */ + "@Internal Flash /0x08000000/8*001Ka,56*001Kg", +}; +#define N_USB_STRINGS (sizeof(usb_strings)/sizeof(usb_strings[0])) + +static void +delay_us (uint32_t d) +{ + d *= 7; + + while (d--) + __asm__ ("nop"); +} + + +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); + } + break; + + 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: + ; + } + +} + +static enum usbd_request_return_codes usbdfu_control_request (usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, + uint16_t *len, usbd_control_complete_callback *complete) +{ + + if ((req->bmRequestType & 0x7F) != 0x21) + return USBD_REQ_NEXT_CALLBACK; + + switch (req->bRequest) { + case DFU_DNLOAD: + if ((len == NULL) || (*len == 0)) { + usbdfu_state = STATE_DFU_MANIFEST_SYNC; + } 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 USBD_REQ_HANDLED; + + case DFU_CLRSTATUS: + + /* Clear error and return to dfuIDLE. */ + if (usbdfu_state == STATE_DFU_ERROR) + usbdfu_state = STATE_DFU_IDLE; + + return USBD_REQ_HANDLED; + + case DFU_ABORT: + /* Abort returns to dfuIDLE state. */ + usbdfu_state = STATE_DFU_IDLE; + return USBD_REQ_HANDLED; + + case DFU_UPLOAD: + /* Upload not supported for now. */ + return USBD_REQ_NOTSUPP; + + 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 USBD_REQ_HANDLED; + } + + case DFU_GETSTATE: + /* Return state with no state transision. */ + *buf[0] = usbdfu_state; + *len = 1; + return USBD_REQ_HANDLED; + } + + return USBD_REQ_NEXT_CALLBACK; +} + +static void usb_reset (void) +{ + /*Force USB reset */ + gpio_set_mode (GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO11); + gpio_set_mode (GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO12); + gpio_clear (GPIOA, GPIO11); + gpio_clear (GPIOA, GPIO12); + + delay_us (5000); + gpio_set_mode (GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO11); + gpio_set_mode (GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO12); +} + + +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); + rcc_periph_reset_pulse (RST_USB); + + 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))(); + } + } + + usb_reset(); + + dfu_flag = 0; + + rcc_clock_setup_pll(&rcc_hsi_configs[RCC_CLOCK_HSI_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 (&st_usbfs_v1_usb_driver, &dev, &config, usb_strings, N_USB_STRINGS, 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/stm32/boot/usbdfu.ld b/stm32/boot/usbdfu.ld new file mode 100644 index 0000000..498bcea --- /dev/null +++ b/stm32/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 = 128K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K +} + +/* Include the common ld script. */ +INCLUDE cortex-m-generic.ld + +dfu_shared_location = ORIGIN(ram) + LENGTH(ram) - 1024; + +SECTIONS +{ + .dfu_shared dfu_shared_location :{ + dfu_flag = .; + } +} + diff --git a/stm32/docs/Astronomical Algorithms.pdf b/stm32/docs/Astronomical Algorithms.pdf new file mode 100644 index 0000000..52cc63a Binary files /dev/null and b/stm32/docs/Astronomical Algorithms.pdf differ diff --git a/stm32/docs/rm0008.pdf b/stm32/docs/rm0008.pdf new file mode 100644 index 0000000..8f3d0e1 Binary files /dev/null and b/stm32/docs/rm0008.pdf differ diff --git a/stm32/id.h b/stm32/id.h new file mode 100644 index 0000000..d27ecf7 --- /dev/null +++ b/stm32/id.h @@ -0,0 +1,4 @@ +#define VENDOR_NAME "HP" +#define PRODUCT_NAME "DDC Debug Dongle" +#define SERIAL_NUMBER "Serialy McSerialFace" + diff --git a/stm32/libopencm3 b/stm32/libopencm3 new file mode 160000 index 0000000..a9cc695 --- /dev/null +++ b/stm32/libopencm3 @@ -0,0 +1 @@ +Subproject commit a9cc6953817e0de1cad06662ce58a81607cd796b diff --git a/stm32/oocd/board/STM32F103R_BOARD.cfg b/stm32/oocd/board/STM32F103R_BOARD.cfg new file mode 100644 index 0000000..11217d2 --- /dev/null +++ b/stm32/oocd/board/STM32F103R_BOARD.cfg @@ -0,0 +1,6 @@ +# + +source [find target/stm32f1x.cfg] + +adapter_khz 500 + diff --git a/stm32/oocd/interface/j-link.cfg b/stm32/oocd/interface/j-link.cfg new file mode 100644 index 0000000..3e95768 --- /dev/null +++ b/stm32/oocd/interface/j-link.cfg @@ -0,0 +1,5 @@ +# +telnet_port 4444 +gdb_port 3333 + +source [find interface/jlink.cfg] diff --git a/stm32/oocd/interface/stlink-v2.cfg b/stm32/oocd/interface/stlink-v2.cfg new file mode 100644 index 0000000..0985230 --- /dev/null +++ b/stm32/oocd/interface/stlink-v2.cfg @@ -0,0 +1,11 @@ +# +telnet_port 4444 +gdb_port 3333 + +#interface hla +#hla_layout stlink +#hla_device_desc "ST-LINK/V2" +#hla_vid_pid 0x0483 0x3748 + +source [find interface/stlink-v2.cfg] + diff --git a/stm32/oocd/stm32-f103.cfg b/stm32/oocd/stm32-f103.cfg new file mode 100644 index 0000000..0809223 --- /dev/null +++ b/stm32/oocd/stm32-f103.cfg @@ -0,0 +1,6 @@ +# +telnet_port 4444 +gdb_port 3333 + +source [find interface/jlink.cfg] +source [find target/stm32f1x.cfg] diff --git a/stm32/tools/dfuse-pack.py b/stm32/tools/dfuse-pack.py new file mode 100755 index 0000000..c0a5f0a --- /dev/null +++ b/stm32/tools/dfuse-pack.py @@ -0,0 +1,256 @@ +#!/usr/bin/python + +# Written by Antonio Galea - 2010/11/18 +# Distributed under Gnu LGPL 3.0 +# see http://www.gnu.org/licenses/lgpl-3.0.txt + +import sys,struct,zlib,os +import binascii +from optparse import OptionParser + +try: + from intelhex import IntelHex +except ImportError: + IntelHex = None + +DEFAULT_DEVICE="0x0483:0xdf11" +DEFAULT_NAME=b'ST...' + +# Prefix and Suffix sizes are derived from ST's DfuSe File Format Specification (UM0391), DFU revision 1.1a +PREFIX_SIZE=11 +SUFFIX_SIZE=16 + +def named(tuple,names): + return dict(list(zip(names.split(),tuple))) +def consume(fmt,data,names): + n = struct.calcsize(fmt) + return named(struct.unpack(fmt,data[:n]),names),data[n:] +def cstring(bytestring): + return bytestring.partition(b'\0')[0] +def compute_crc(data): + return 0xFFFFFFFF & -zlib.crc32(data) -1 + +def parse(file,dump_images=False): + print('File: "%s"' % file) + data = open(file,'rb').read() + crc = compute_crc(data[:-4]) + prefix, data = consume('<5sBIB',data,'signature version size targets') + print('%(signature)s v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix) + for t in range(prefix['targets']): + tprefix, data = consume('<6sBI255s2I',data,'signature altsetting named name size elements') + tprefix['num'] = t + if tprefix['named']: + tprefix['name'] = cstring(tprefix['name']) + else: + tprefix['name'] = '' + print('%(signature)s %(num)d, alt setting: %(altsetting)s, name: "%(name)s", size: %(size)d, elements: %(elements)d' % tprefix) + tsize = tprefix['size'] + target, data = data[:tsize], data[tsize:] + for e in range(tprefix['elements']): + eprefix, target = consume('<2I',target,'address size') + eprefix['num'] = e + print(' %(num)d, address: 0x%(address)08x, size: %(size)d' % eprefix) + esize = eprefix['size'] + image, target = target[:esize], target[esize:] + if dump_images: + out = '%s.target%d.image%d.bin' % (file,t,e) + open(out,'wb').write(image) + print(' DUMPED IMAGE TO "%s"' % out) + if len(target): + print("target %d: PARSE ERROR" % t) + suffix = named(struct.unpack('<4H3sBI',data[:SUFFIX_SIZE]),'device product vendor dfu ufd len crc') + print('usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x' % suffix) + if crc != suffix['crc']: + print("CRC ERROR: computed crc32 is 0x%08x" % crc) + data = data[SUFFIX_SIZE:] + if data: + print("PARSE ERROR") + +def checkbin(binfile): + data = open(binfile,'rb').read() + if (len(data) < SUFFIX_SIZE): + return + crc = compute_crc(data[:-4]) + suffix = named(struct.unpack('<4H3sBI',data[-SUFFIX_SIZE:]),'device product vendor dfu ufd len crc') + if crc == suffix['crc'] and suffix['ufd'] == b'UFD': + print('usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x' % suffix) + print("It looks like the file %s has a DFU suffix!" % binfile) + print("Please remove any DFU suffix and retry.") + sys.exit(1) + +def build(file,targets,name=DEFAULT_NAME,device=DEFAULT_DEVICE): + data = b'' + for t,target in enumerate(targets): + tdata = b'' + for image in target: + tdata += struct.pack('<2I',image['address'],len(image['data']))+image['data'] + ealt = image['alt'] + tdata = struct.pack('<6sBI255s2I',b'Target',ealt,1,name,len(tdata),len(target)) + tdata + data += tdata + data = struct.pack('<5sBIB',b'DfuSe',1,PREFIX_SIZE + len(data) + SUFFIX_SIZE,len(targets)) + data + v,d=[int(x,0) & 0xFFFF for x in device.split(':',1)] + data += struct.pack('<4H3sB',0,d,v,0x011a,b'UFD',SUFFIX_SIZE) + crc = compute_crc(data) + data += struct.pack('