summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorroot <root@lab.ourano.james.local>2021-02-26 12:12:38 +0000
committerroot <root@lab.ourano.james.local>2021-02-26 12:12:38 +0000
commit3d48137c00511b3f2d35511482d1a76f8d06382d (patch)
treed75c88220cc847007869b0795a240c5077948262
parent6d3a824e1cdae6e28146b7de380724b49488f3c2 (diff)
downloadclock-3d48137c00511b3f2d35511482d1a76f8d06382d.tar.gz
clock-3d48137c00511b3f2d35511482d1a76f8d06382d.tar.bz2
clock-3d48137c00511b3f2d35511482d1a76f8d06382d.zip
works
-rw-r--r--.gitignore2
-rw-r--r--app/Makefile35
-rw-r--r--app/cdcacm.c213
-rw-r--r--app/dcf77.c2
-rw-r--r--app/dfu.c81
-rw-r--r--app/gps.c44
-rw-r--r--app/lwip/lwipopts.h5
-rw-r--r--app/lwip_glue.c36
-rw-r--r--app/main.c31
-rw-r--r--app/max7219.c44
-rw-r--r--app/project.h13
-rw-r--r--app/prototypes.h14
-rw-r--r--app/roofclock.ld20
-rw-r--r--app/stdio.c1
-rw-r--r--app/steth.c31
-rw-r--r--app/steth.h2
-rw-r--r--app/sysclk.c81
-rw-r--r--app/usart.c11
-rw-r--r--app/usb.c99
-rw-r--r--boot/Makefile49
-rw-r--r--boot/bootloader.c139
-rw-r--r--boot/bootloader.ld38
-rw-r--r--boot/delay.c42
-rw-r--r--boot/dfu.c197
-rw-r--r--boot/gdb.script2
-rw-r--r--boot/max7219.c124
-rw-r--r--boot/pins.h55
-rw-r--r--boot/project.h29
-rw-r--r--boot/prototypes.h27
-rw-r--r--boot/usart.c68
-rw-r--r--boot/usb.c94
-rw-r--r--id.h7
32 files changed, 1562 insertions, 74 deletions
diff --git a/.gitignore b/.gitignore
index ac3f06d..1077c0a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,5 @@
.*.swp
almanac.c
almanac.alp
+*.img
+*.dfu
diff --git a/app/Makefile b/app/Makefile
index f38aea4..4a007a6 100644
--- a/app/Makefile
+++ b/app/Makefile
@@ -17,15 +17,16 @@
## along with this library. If not, see <http://www.gnu.org/licenses/>.
##
-LDSCRIPT = ../arch_max.ld
CPROTO=cproto
-PROG=msf
+PROG=roofclock
+
+LDSCRIPT = ${PROG}.ld
V=1
default: ${PROG}.elf
-CSRCS=led.c ticker.c ring.c usart.c stdio.c lwip_glue.c steth.c msf.c abs.c pll.c main.c time_fn.c ntp.c dcf77.c util.c stats.c gps.c hexdump.c bits.c max7219.c report.c sysclk.c cdcacm.c usb.c
+CSRCS=led.c ticker.c ring.c usart.c stdio.c lwip_glue.c steth.c msf.c abs.c pll.c main.c time_fn.c ntp.c dcf77.c util.c stats.c gps.c hexdump.c bits.c max7219.c report.c sysclk.c cdcacm.c usb.c dfu.c
HSRCS= events.h gps.h project.h ring.h steth.h time_fn.h ubx.h
@@ -69,7 +70,7 @@ OBJS=${MYOBJS} ${LWIP_OBJS}
include ../Makefile.include
CFLAGS+=-Wno-redundant-decls -Wno-unused-parameter
-CPPFLAGS += -I../libopencm3-local -I${LWIP_PATH}/${LWIP}/src/include -Ilwip -I${LWIP_PATH}/${LWIP}/src/include/ipv4 -I${LWIP_LOCAL}/port/stm32f4x7 -I.
+CPPFLAGS += -I.. -I../libopencm3-local -I${LWIP_PATH}/${LWIP}/src/include -Ilwip -I${LWIP_PATH}/${LWIP}/src/include/ipv4 -I${LWIP_LOCAL}/port/stm32f4x7 -I.
LDLIBS+= -lm
@@ -90,9 +91,35 @@ reset:
-c shutdown
+
+test-dfu: ${PROG}.dfu
+ ../dfu-util/src/dfu-util -v -R -a 0 -d ${VID}:${DID} -s 0x08004000:leave -D $<
+ $(Q)$(OOCD) -f ../oocd/interface/$(OOCD_INTERFACE).cfg \
+ -f ../oocd/board/$(OOCD_BOARD).cfg \
+ -c "init" -c "dump_image readback.img 0x8004000 0x7c000" \
+ -c shutdown
+
+ hexdump -C ${PROG}.dfu > a
+ hexdump -C readback.img> b
+ diff -uN a b > c
+
+
fl: ${PROG}.hex
ssh ${HOST} flash_stm32 < ${PROG}.hex
+
+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 ^\# )
+
+
+%.dfu: %.elf
+ @#printf " OBJCOPY $(*).dfu\n"
+ $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).dfu
+
+dfu:${PROG}.dfu
+ dfu-util -R -a 0 -d ${VID}:${DID} -s 0x08004000:leave -D $<
+
+
program: ${PROG}.hex
scp $< ${HOST}:/tmp/img.hex
echo init | nc -t ${HOST} 4444
diff --git a/app/cdcacm.c b/app/cdcacm.c
new file mode 100644
index 0000000..213592e
--- /dev/null
+++ b/app/cdcacm.c
@@ -0,0 +1,213 @@
+#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;
+
+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,
+ }
+};
+
+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)
+};
+
+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 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;
+
+ if (dfu_control_request (usbd_dev, req, buf, len, complete))
+ return 1;
+
+
+ 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 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 (!cdcacm_ready)
+ return;
+
+
+ if (ring_empty (&cdcacm_tx_ring))
+ return;
+
+ /* Return if endpoint is already enabled. */
+ if (OTG_FS_DIEPTSIZ (ep & 0x7f) & OTG_DIEPSIZ0_PKTCNT)
+ 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 blocking)
+{
+ int ret;
+
+ ret = ring_write (&cdcacm_tx_ring, (uint8_t *) ptr, len, blocking);
+ 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, 0x01, buf, 64);
+
+ if (len)
+ ring_write (&cdcacm_rx_ring, buf, len, 0);
+}
+
+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);
+
+ 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/app/dcf77.c b/app/dcf77.c
index 124eea5..71c227c 100644
--- a/app/dcf77.c
+++ b/app/dcf77.c
@@ -124,7 +124,7 @@ void dcf77_dispatch (void)
{
static uint32_t last_0, last_1, last_s;
static int second, bit, had_m;
- uint32_t pulse_w,offset ;
+ uint32_t pulse_w, offset ;
static uint64_t abs;
int is_s = 0;
diff --git a/app/dfu.c b/app/dfu.c
new file mode 100644
index 0000000..c505585
--- /dev/null
+++ b/app/dfu.c
@@ -0,0 +1,81 @@
+#include "project.h"
+
+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_VTOR=0;
+
+ //SCB_AIRCR = SCB_AIRCR_VECTKEY | SCB_AIRCR_VECTRESET;
+ //SCB_AIRCR= SCB_AIRCR_SYSRESETREQ;
+
+ 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;
+}
+
diff --git a/app/gps.c b/app/gps.c
index 101413f..206f0c0 100644
--- a/app/gps.c
+++ b/app/gps.c
@@ -138,7 +138,7 @@ ubx_recv_nav_status (uint8_t *ptr, unsigned len)
uint8_t gps_fix, flags, fix_stat, flags2;
uint32_t d;
- unsigned kick_off_survey_mode=300;
+ unsigned kick_off_survey_mode = 300;
if ((!ptr) || (len != 16))
return -1;
@@ -175,7 +175,7 @@ ubx_recv_nav_status (uint8_t *ptr, unsigned len)
case 5:
fix = 'T';
gps_locked = 1;
- kick_off_survey_mode=0;
+ kick_off_survey_mode = 0;
break;
default:
@@ -205,6 +205,8 @@ ubx_recv_nav_status (uint8_t *ptr, unsigned len)
fix2 = '?';
}
+ max7219_report_fix (fix, fix2);
+
// printf ("fix: %c%c happy %d Fix %02x flags %02x fix_stat %02x flags2 %02x \r\n",fix,fix2,gps_happy, gps_fix, flags,fix_stat,flags2);
@@ -215,13 +217,13 @@ ubx_recv_nav_status (uint8_t *ptr, unsigned len)
gps_happy = 0;
- if (kick_off_survey_mode>0) {
- kick_off_survey_mode--;
+ if (kick_off_survey_mode > 0) {
+ kick_off_survey_mode--;
- if (!kick_off_survey_mode) {
- printf("GPS no time fix - kicking off survey mode\n");
- ubx_cfg_tmode (1, 0, 0, 0, 0, 3600, 3600); // 1 hour and 6cm
- }
+ if (!kick_off_survey_mode) {
+ printf ("GPS no time fix - kicking off survey mode\n");
+ ubx_cfg_tmode (1, 0, 0, 0, 0, 3600, 3600); // 1 hour and 6cm
+ }
}
return 0;
@@ -371,6 +373,7 @@ static int ubx_recv_nav_sbas (uint8_t *ptr, unsigned len)
int8_t sys;
uint8_t n;
+ if (!chatty_gps) return0 ;
ptr += ubx_get_u32 (ptr, &d4);
ptr += ubx_get_u8 (ptr, &prn);
@@ -381,7 +384,7 @@ static int ubx_recv_nav_sbas (uint8_t *ptr, unsigned len)
ptr += ubx_get_u8 (ptr, &n);
ptr += 3;
-// printf ("GPS SBAS PRN:%d M:%d S:%d SVC:%02x SVS:", prn, mode, sys, service);
+ printf ("GPS SBAS PRN:%d M:%d S:%d SVC:%02x SVS:", prn, mode, sys, service);
while (n--) {
ptr += ubx_get_u8 (ptr, &prn);
@@ -401,7 +404,7 @@ static int ubx_recv_nav_svinfo (uint8_t *ptr, unsigned len)
uint8_t n, flags, cflags;
const char *st;
- return 0;
+ if (!chatty_gps) return 0;
ptr += ubx_get_u32 (ptr, &d4);
ptr += ubx_get_u8 (ptr, &n);
@@ -485,6 +488,8 @@ static int ubx_recv_tim_svin (uint8_t *ptr, unsigned len)
printf ("TIM-SVIN dur %u var %u obs %u valid %02x active %02x\r\n",
(unsigned) dur, (unsigned) var, (unsigned) obs, valid, active);
+ max7219_report_svin (valid, active);
+
return 0;
}
@@ -750,6 +755,7 @@ static void gps_pps_dispatch (void)
if (gps_happy)
led3_set (v);
+
gps_ring.rx_ptr = (gps_ring.rx_ptr + 1) & ERING_MASK;
@@ -815,7 +821,8 @@ ubx_send (uint8_t class, uint8_t id, const void *_payload, unsigned len)
static int
ubx_handshake (uint8_t class, uint8_t id, const void *payload, unsigned len)
{
- uint32_t timeout=4000;
+ uint32_t timeout = 4000;
+ unsigned tries = 4;
ubx_ack = 0;
ubx_nack = 0;
@@ -825,15 +832,24 @@ ubx_handshake (uint8_t class, uint8_t id, const void *payload, unsigned len)
if (!timeout) {
printf ("GPS timeout resending packet\r\n");
+
+ if (!tries) {
+ printf ("GPS 3 timesout - resetting system\r\n");
+ usart2_drain();
+ scb_reset_system();
+ }
+
usart1_drain();
ubx_send (class, id, payload, len);
- timeout = 40000;
+ timeout = 4000;
+ tries--;
}
+
timeout--;
gps_dispatch();
- delay_ms(1);
+ delay_ms (1);
}
return !!ubx_nack;
@@ -1176,7 +1192,7 @@ gps_init (void)
ubx_cfg_poll (0x6, 0x16);
-// ubx_aid_ini (522202400, 1279080, 2900, 20000);
+ // ubx_aid_ini (522202400, 1279080, 2900, 20000);
printf ("GNSS ready\r\n");
#else
diff --git a/app/lwip/lwipopts.h b/app/lwip/lwipopts.h
index 3358cad..c590df9 100644
--- a/app/lwip/lwipopts.h
+++ b/app/lwip/lwipopts.h
@@ -86,7 +86,7 @@ a lot of data that needs to be copied, this should be set high. */
#define MEMP_NUM_TCP_SEG 12
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
timeouts. */
-#define MEMP_NUM_SYS_TIMEOUT 3
+#define MEMP_NUM_SYS_TIMEOUT 4
#define PBUF_POOL_FREE_OOSEQ 0
@@ -130,8 +130,9 @@ a lot of data that needs to be copied, this should be set high. */
/* Define LWIP_DHCP to 1 if you want DHCP configuration of
interfaces. DHCP is not implemented in lwIP 0.5.1, however, so
turning this on does currently not work. */
-#define LWIP_DHCP 0
+#define LWIP_DHCP 1
#define LWIP_AUTOIP 0
+#define LWIP_DHCP_BOOTP_FILE 0
/* ---------- UDP options ---------- */
diff --git a/app/lwip_glue.c b/app/lwip_glue.c
index 1e69fc0..9fed1e6 100644
--- a/app/lwip_glue.c
+++ b/app/lwip_glue.c
@@ -11,6 +11,11 @@ uint32_t sys_now (void)
void dispatch_lwip (void)
{
#if 0
+ static uint32_t fine_timer,coarse_timer;
+ uint32_t now=ticks;
+#endif
+
+#if 0
if (link_lost())
netif_set_down (&if0);
@@ -23,15 +28,14 @@ void dispatch_lwip (void)
sys_check_timeouts();
#if 0
-
/* Fine DHCP periodic process every 500ms */
- if (localtime - DHCPfineTimer >= DHCP_FINE_TIMER_MSECS) {
- DHCPfineTimer = localtime;
+ if (now - fine_timer >= DHCP_FINE_TIMER_MSECS) {
+ fine_timer = now;
dhcp_fine_tmr();
if ((DHCP_state != DHCP_ADDRESS_ASSIGNED) && (DHCP_state != DHCP_TIMEOUT)) {
/* toggle LED1 to indicate DHCP on-going process */
- STM_EVAL_LEDToggle (LED1);
+ //STM_EVAL_LEDToggle (LED1);
/* process DHCP state machine */
LwIP_DHCP_Process_Handle();
@@ -39,43 +43,31 @@ void dispatch_lwip (void)
}
/* DHCP Coarse periodic process every 60s */
- if (localtime - DHCPcoarseTimer >= DHCP_COARSE_TIMER_MSECS) {
- DHCPcoarseTimer = localtime;
+ if (now - coarse_timer >= DHCP_COARSE_TIMER_MSECS) {
+ coarse_timer = now;
dhcp_coarse_tmr();
}
-
#endif
+
}
void start_lwip (void)
{
- struct ip_addr ipaddr;
- struct ip_addr netmask;
- struct ip_addr gw;
-
- // uint8_t macaddress[6]={0,0,0,0,0,1};
lwip_init();
-#if 0
- IP4_ADDR (&ipaddr, 10, 32, 99, 73);
- IP4_ADDR (&netmask, 255, 255, 255, 0);
- IP4_ADDR (&gw, 10, 32, 99, 1);
-#else
- IP4_ADDR (&ipaddr, 10, 32, 96, 47);
- IP4_ADDR (&netmask, 255, 255, 255, 0);
- IP4_ADDR (&gw, 10, 32, 96, 1);
-#endif
- netif_add (&if0, &ipaddr, &netmask, &gw, NULL, steth_lwip_init, ethernet_input);
+ netif_add (&if0, NULL,NULL,NULL, NULL, steth_lwip_init, ethernet_input);
/* Registers the default network interface.*/
netif_set_default (&if0);
netif_set_up (&if0);
+ dhcp_start(&if0);
+
}
diff --git a/app/main.c b/app/main.c
index 22ee23e..d5b5ec4 100644
--- a/app/main.c
+++ b/app/main.c
@@ -221,7 +221,7 @@ static void ptp_clock_start (void)
static void clock_setup (void)
{
-static uint32_t fail;
+ static uint32_t fail;
/*
* Caution, The PLL is somewhat rubbish, and causes all sorts of misery
* so sysclk isn't really a reference, if we use it, however not using it
@@ -240,16 +240,16 @@ static uint32_t fail;
/* confiure HSE as input not oscillator */
- rcc_osc_bypass_enable (HSE);
+ rcc_osc_bypass_enable (HSE);
rcc_osc_on (HSE);
while ((RCC_CR & RCC_CR_HSERDY) == 0) {
- if (fail++ == 4000000) {
- /*No external clock, try seeing if we have a crystal */
- rcc_osc_off (HSE);
- rcc_osc_bypass_disable (HSE);
- rcc_osc_on (HSE);
- }
+ if (fail++ == 4000000) {
+ /*No external clock, try seeing if we have a crystal */
+ rcc_osc_off (HSE);
+ rcc_osc_bypass_disable (HSE);
+ rcc_osc_on (HSE);
+ }
}
/* turn off SSC */
@@ -372,6 +372,7 @@ board_setup (void)
nvic_set_priority (NVIC_USART2_IRQ, 0x30);
nvic_set_priority (NVIC_ETH_IRQ, 0x40);
nvic_set_priority (NVIC_SYSTICK_IRQ, 0x50);
+ nvic_set_priority (NVIC_OTG_FS_IRQ, 0x60);
// nvic_enable_irq (NVIC_EXTI15_10_IRQ);
@@ -382,32 +383,42 @@ board_setup (void)
static void
system_init (void)
{
+ cdcacm_rings_init();
+ usart_rings_init();
board_setup();
timer_setup();
led_init();
+
ticker_init();
usart_init();
+ usb_init();
+
msf_init();
dcf77_init();
+
+ steth_calculate_mac();
printf ("LWIP\r\n");
start_lwip();
printf ("STETH\r\n");
+
+
steth_init();
ptp_clock_start();
max7219_init (1, 8);
+
gps_init();
ntp_init();
- usb_init();
+
}
@@ -456,7 +467,7 @@ main (void)
dispatch_lwip();
max7219_dispatch();
- cdcacm_dispatch();
+
}
diff --git a/app/max7219.c b/app/max7219.c
index 8c1c859..85e66a7 100644
--- a/app/max7219.c
+++ b/app/max7219.c
@@ -115,10 +115,10 @@ write_regs (uint8_t reg, uint8_t data1, uint8_t data2, uint8_t data3)
unlock();
}
-static void write_pair (uint8_t reg, int d1, int d2, int d3)
+static void write_triad (uint8_t reg, int d1, int d2, int d3, unsigned dm)
{
- write_regs (reg, d1 / 10, d2 / 10, d3 / 10);
- write_regs (reg - 1, (d1 % 10) | 0x80, (d2 % 10) | 0x80, (d3 % 10) | 0x80);
+ write_regs (reg++, (d1 % 10) | ((dm & 0x1) ? 0x80 : 0), (d2 % 10) | ((dm & 0x4) ? 0x80 : 0), (d3 % 10) | ((dm & 0x10) ? 0x80 : 0));
+ write_regs (reg, (d1 / 10) | ((dm & 0x2) ? 0x80 : 0), (d2 / 10) | ((dm & 0x8) ? 0x80 : 0), (d3 / 10) | ((dm & 0x20) ? 0x80 : 0));
}
@@ -153,6 +153,29 @@ static void st_test (void)
#endif
+unsigned fix_dots, fix_dots_even;
+
+void max7219_report_fix (char fix, char fix2)
+{
+ fix_dots = 0;
+
+
+ if (fix == 'L')
+ fix_dots |= 0x1;
+
+ if (fix2 == 'D') fix_dots |= 0x4;
+
+ if (fix == 'T') fix_dots |= 0x11;
+}
+
+void max7219_report_svin (int valid, int active)
+{
+ fix_dots_even = 0;
+
+ if (active || valid) fix_dots_even |= 0x10;
+}
+
+
void max7219_dispatch (void)
{
uint32_t now = HW_CLOCK_REG;
@@ -162,6 +185,8 @@ void max7219_dispatch (void)
UTC u;
UTC gu;
ST l;
+ unsigned last_dots;
+
e = pll_decompose (abs);
@@ -171,10 +196,15 @@ void max7219_dispatch (void)
e.s += gps_utc_diff;
gu = time_epoch_to_utc (e);
- write_pair (8, u.hour, l.hour, gps_wday);
- write_pair (6, u.minute, l.minute, gu.hour);
- write_pair (4, u.second, l.second, gu.minute);
- write_pair (2, u.nanosecond / 10000000, l.nanosecond / 10000000, gu.second);
+ last_dots = fix_dots;
+
+ if (u.nanosecond < 500000000) last_dots |= fix_dots_even;
+
+
+ write_triad (1, u.nanosecond / 10000000, l.nanosecond / 10000000, gu.second, last_dots);
+ write_triad (3, u.second, l.second, gu.minute, 0x15);
+ write_triad (5, u.minute, l.minute, gu.hour, 0x15);
+ write_triad (7, u.hour, l.hour, gps_wday, 0x15);
if (u.minute == m) return;
diff --git a/app/project.h b/app/project.h
index 5785628..ca623de 100644
--- a/app/project.h
+++ b/app/project.h
@@ -27,14 +27,16 @@
#include <libopencm3/stm32/syscfg.h>
#include <libopencm3/stm32/otg_common.h>
#include <libopencm3/stm32/otg_fs.h>
+#include <libopencm3/stm32/desig.h>
/* Drivers */
#include <libopencm3/ethernet/mac_stm32fxx7.h>
#include <libopencm3/ethernet/phy.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/cdc.h>
-#ifdef INCLUDE_DFU_INTERFACE
#include <libopencm3/usb/dfu.h>
-#endif
+
+#include "id.h"
+
@@ -44,7 +46,7 @@
#include <lwip/mem.h>
#include <lwip/memp.h>
#include <lwip/timers.h>
-#include <lwip/timers.h>
+#include <lwip/dhcp.h>
#include <netif/etharp.h>
#include "time_fn.h"
@@ -84,5 +86,6 @@
extern const unsigned char almanac_alp[];
extern unsigned int almanac_alp_len;
-#define ID_VENDOR 0x0483
-#define ID_PRODUCT 0x5740
+extern uint32_t dfu_flag;
+
+
diff --git a/app/prototypes.h b/app/prototypes.h
index f409da8..4b20c86 100644
--- a/app/prototypes.h
+++ b/app/prototypes.h
@@ -33,6 +33,7 @@ extern void usart1_isr(void);
extern void usart1_queue(uint8_t d);
extern void usart1_drain(void);
extern int usart1_write(char *ptr, int len, int blocking);
+extern void usart_rings_init(void);
extern void usart_init(void);
/* stdio.c */
extern int _open(const char *name, int flags, int mode);
@@ -49,6 +50,7 @@ extern uint32_t sys_now(void);
extern void dispatch_lwip(void);
extern void start_lwip(void);
/* steth.c */
+extern void steth_calculate_mac(void);
extern void eth_isr(void);
extern void steth_isr(void);
extern err_t steth_lwip_init(struct netif *netif);
@@ -119,6 +121,10 @@ extern void hexdump(void *_d, int len);
/* bits.c */
extern void dump_bits(char *wot, uint8_t *bits);
/* max7219.c */
+extern unsigned fix_dots;
+extern unsigned fix_dots_even;
+extern void max7219_report_fix(char fix, char fix2);
+extern void max7219_report_svin(int valid, int active);
extern void max7219_dispatch(void);
extern void max7219_init(int on, int brightness);
/* report.c */
@@ -133,11 +139,15 @@ extern ring_t cdcacm_tx_ring;
extern const struct usb_interface_descriptor comm_iface;
extern const struct usb_interface_descriptor data_iface;
extern void cdcacm_tick(void);
+extern int cdcacm_write(char *ptr, int len, int blocking);
extern void cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue);
-extern void cdcacm_init(void);
-extern void cdcacm_dispatch(void);
+extern void cdcacm_rings_init(void);
/* usb.c */
extern uint8_t usbd_control_buffer[128];
extern usbd_device *usb_device;
extern void otg_fs_isr(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);
diff --git a/app/roofclock.ld b/app/roofclock.ld
new file mode 100644
index 0000000..325e7ce
--- /dev/null
+++ b/app/roofclock.ld
@@ -0,0 +1,20 @@
+/* Linker script for STM32F407VET6, 512K flash, 192K RAM. */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08004000, LENGTH = 496K
+ ram (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f4.ld
+
+dfu_shared_location = ORIGIN(ram) + LENGTH(ram) - 1024;
+
+SECTIONS
+{
+ .dfu_shared dfu_shared_location :{
+ dfu_flag = .;
+ }
+}
diff --git a/app/stdio.c b/app/stdio.c
index 9a8c74a..c1015dc 100644
--- a/app/stdio.c
+++ b/app/stdio.c
@@ -28,6 +28,7 @@ _write (int file,
ret = usart2_write (buf, nbytes, 1);
+ cdcacm_write (buf, nbytes, 0);
if (ret < 0) {
errno = -ret;
diff --git a/app/steth.c b/app/steth.c
index 26429aa..5b94e1d 100644
--- a/app/steth.c
+++ b/app/steth.c
@@ -14,7 +14,7 @@ static int ready;
static uint8_t __attribute__ ((aligned (4))) eth_buf[ETH_BUF_LEN];
-static uint8_t sa[ETHARP_HWADDR_LEN] = { 0xc0, 0xf1, 0xee, 0xc0, 0xff, 0xdd };
+static uint8_t sa[ETHARP_HWADDR_LEN];
extern uint32_t TxBD;
extern uint32_t RxBD;
@@ -32,6 +32,29 @@ extern uint32_t RxBD;
+void steth_calculate_mac(void)
+{
+ uint32_t uid[3];
+ uint8_t *ptr;
+ unsigned i;
+ desig_get_unique_id (uid);
+
+ ptr=(uint8_t *)uid;
+
+ for (i=0;i<ETHARP_HWADDR_LEN;++i)
+ sa[i]^=*(ptr++);
+ for (i=0;i<ETHARP_HWADDR_LEN;++i)
+ sa[i]^=*(ptr++);
+
+ sa[0]&=0xfe; /*Clear I/G */
+ sa[0]|=0x2; /*Set U/L */
+
+printf("MAC ADDRESS is %02x:%02x:%02x:%02x:%02x:%02x\r\n",sa[0],sa[1],sa[2],sa[3],sa[4],sa[5]);
+}
+
+
+
+
static void mac_stat (void)
{
//uint32_t d, s;
@@ -122,6 +145,7 @@ steth_rx (void)
struct pbuf *p;
uint32_t len;
+
p = pbuf_alloc (PBUF_RAW, MTU, PBUF_POOL);
if (!p) return ERR_MEM;
@@ -166,6 +190,7 @@ steth_lwip_init (struct netif *netif)
{
LWIP_ASSERT ("netif != NULL", (netif != NULL));
+
#if LWIP_NETIF_HOSTNAME
/* Initialize interface hostname */
netif->hostname = "lwip";
@@ -297,8 +322,8 @@ static void eth_reset (void)
phy_stat();
eth_set_mac (sa);
- eth_enable_checksum_offload();
eth_desc_init (eth_buf, TX_BUFS, RX_BUFS, FRAME_SZ, FRAME_SZ, 1);
+ // eth_enable_checksum_offload();
eth_irq_enable (ETH_DMAIER_NISE);
eth_irq_enable (ETH_DMAIER_RIE);
@@ -314,6 +339,8 @@ static void eth_start_an (void)
phy_autoneg_enable (PHY);
}
+
+
void
steth_init (void)
{
diff --git a/app/steth.h b/app/steth.h
index ca752a7..f4efee1 100644
--- a/app/steth.h
+++ b/app/steth.h
@@ -1,5 +1,5 @@
-#define PHY PHY0
+#define PHY PHY1
#define TXEN GPIO11
#define TXEN_PORT GPIOG
diff --git a/app/sysclk.c b/app/sysclk.c
new file mode 100644
index 0000000..1847c28
--- /dev/null
+++ b/app/sysclk.c
@@ -0,0 +1,81 @@
+#include "project.h"
+
+
+
+static Event_ring sysclk_ring;
+
+void sysclk_event (void)
+{
+ uint32_t refclk_now = HW_CLOCK_REG;
+ uint32_t sysclk_now = SCS_DWT_CYCCNT;
+
+
+ sysclk_ring.events[sysclk_ring.tx_ptr].when = refclk_now;
+ sysclk_ring.events[sysclk_ring.tx_ptr].value = sysclk_now;
+ sysclk_ring.tx_ptr = (sysclk_ring.tx_ptr + 1) & ERING_MASK;
+
+}
+
+static uint32_t high_tick;
+
+#define QUARTER (1UL << 29)
+#define HALF (1UL << 30)
+#define THREE_QUARTERS (HALF+QUARTER)
+#define ONE (~(uint32_t)0)
+
+uint64_t sysclk_extend (uint32_t now)
+{
+ static int m;
+ uint64_t ret;
+
+
+ if (!m) {
+ ret = high_tick;
+ ret <<= 32;
+ ret |= now;
+
+
+ if ((now > THREE_QUARTERS) && (now <= ONE)) {
+ high_tick++;
+ m = 1;
+ }
+
+ } else {
+ if (now < HALF) {
+ ret = high_tick;
+ ret <<= 32;
+ ret |= now;
+ } else {
+ ret = high_tick - 1;
+ ret <<= 32;
+ ret |= now;
+ }
+
+ if ((now > QUARTER) && (now < HALF))
+ m = 0;
+ }
+
+ return ret;
+}
+void sysclk_dispatch (void)
+{
+ //char buf[80];
+ uint64_t refclk_abs;
+ uint32_t refclk_now, sysclk_now;
+ EPOCH e;
+ //UTC u;
+
+ if (sysclk_ring.rx_ptr == sysclk_ring.tx_ptr) return;
+
+ sysclk_now = sysclk_ring.events[sysclk_ring.rx_ptr].value;
+ refclk_now = sysclk_ring.events[sysclk_ring.rx_ptr].when;
+ sysclk_ring.rx_ptr = (sysclk_ring.rx_ptr + 1) & ERING_MASK;
+
+ refclk_abs = abs_extend (refclk_now);
+ e.s = sysclk_extend (sysclk_now);
+ e.ns = 0;
+
+ report_time ("SYS", e, refclk_abs, "");
+}
+
+
diff --git a/app/usart.c b/app/usart.c
index 5d5614d..26616da 100644
--- a/app/usart.c
+++ b/app/usart.c
@@ -137,13 +137,18 @@ usart1_write (char *ptr, int len, int blocking)
return ret;
}
+void usart_rings_init (void)
+{
+ ring_init (&rx1_ring, rx1_ring_buf, sizeof (rx1_ring_buf));
+ ring_init (&tx1_ring, tx1_ring_buf, sizeof (tx1_ring_buf));
+ ring_init (&rx2_ring, rx2_ring_buf, sizeof (rx2_ring_buf));
+ ring_init (&tx2_ring, tx2_ring_buf, sizeof (tx2_ring_buf));
+}
void
usart_init (void)
{
- ring_init (&rx2_ring, rx2_ring_buf, sizeof (rx2_ring_buf));
- ring_init (&tx2_ring, tx2_ring_buf, sizeof (tx2_ring_buf));
MAP_OUTPUT_PP (RX2_EN);
SET (RX2_EN);
@@ -166,8 +171,6 @@ usart_init (void)
nvic_enable_irq (NVIC_USART2_IRQ);
- ring_init (&rx1_ring, rx1_ring_buf, sizeof (rx1_ring_buf));
- ring_init (&tx1_ring, tx1_ring_buf, sizeof (tx1_ring_buf));
MAP_INPUT (RX1);
MAP_AF (TX1, GPIO_AF7);
diff --git a/app/usb.c b/app/usb.c
new file mode 100644
index 0000000..053f126
--- /dev/null
+++ b/app/usb.c
@@ -0,0 +1,99 @@
+#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 = 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_interface ifaces[] = {
+ {
+ .num_altsetting = 1,
+ .altsetting = &comm_iface,
+ },
+ {
+ .num_altsetting = 1,
+ .altsetting = &data_iface,
+ },
+ {
+ .num_altsetting = 1,
+ .altsetting = &dfu_iface,
+ },
+};
+
+static const struct usb_config_descriptor config = {
+ .bLength = USB_DT_CONFIGURATION_SIZE,
+ .bDescriptorType = USB_DT_CONFIGURATION,
+ .wTotalLength = 0,
+ .bNumInterfaces = 3,
+ .bConfigurationValue = 1,
+ .iConfiguration = 0,
+ .bmAttributes = 0x80,
+ .bMaxPower = 0x32,
+ .interface = ifaces,
+};
+
+static const char *usb_strings[] = {
+ VENDOR_NAME,
+ PRODUCT_NAME,
+ SERIAL_NUMBER,
+ "DFU",
+};
+
+void otg_fs_isr (void)
+{
+ usbd_poll (usb_device);
+}
+
+
+
+
+void usb_init (void)
+{
+ MAP_AF_100 (USB_DP, GPIO_AF10);
+ MAP_AF_100 (USB_DM, GPIO_AF10);
+
+
+ usb_device = usbd_init (&otgfs_usb_driver,
+ &dev,
+ &config,
+ usb_strings,
+ 4,
+ usbd_control_buffer,
+ sizeof (usbd_control_buffer));
+
+ /* Disable VBUS sensing */
+
+ OTG_FS_GCCFG |= OTG_GCCFG_NOVBUSSENS;
+ OTG_FS_GCCFG &= ~OTG_GCCFG_VBUSASEN;
+ OTG_FS_GCCFG &= ~OTG_GCCFG_VBUSBSEN;
+
+ usbd_register_set_config_callback (usb_device, cdcacm_set_config);
+
+
+ nvic_enable_irq (NVIC_OTG_FS_IRQ);
+
+}
+
+
diff --git a/boot/Makefile b/boot/Makefile
new file mode 100644
index 0000000..e744d9a
--- /dev/null
+++ b/boot/Makefile
@@ -0,0 +1,49 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## 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 <http://www.gnu.org/licenses/>.
+##
+
+
+CSRCS=bootloader.c usb.c dfu.c delay.c usart.c max7219.c
+PROG = bootloader
+
+CPROTO=cproto
+V=1
+BINARY = ${PROG}
+OBJS = ${CSRCS:%.c=%.o}
+
+include ../Makefile.include
+
+CPPFLAGS += -I..
+CFLAGS += ${CPPFLAGS}
+CFLAGS+=-Wno-redundant-decls -Wno-unused-parameter
+
+ds:
+ $(Q)$(OOCD) -f ../oocd/interface/$(OOCD_INTERFACE).cfg \
+ -f ../oocd/board/$(OOCD_BOARD).cfg
+
+debug: ${PROG}.elf
+ ${PREFIX}-gdb -x gdb.script ${PROG}.elf
+
+protos: ${CSRCS}
+ echo -n > prototypes.h
+ ${CPROTO} -E "${CPP} $(CPPFLAGS)" -e -v ${CSRCS} > prototypes.h.tmp
+ /bin/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}
diff --git a/boot/bootloader.c b/boot/bootloader.c
new file mode 100644
index 0000000..27b6b98
--- /dev/null
+++ b/boot/bootloader.c
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "project.h"
+
+
+#define BOOTLOADER_BUTTON GPIO15
+#define BOOTLOADER_BUTTON_PORT GPIOE
+
+
+static const clock_scale_t hsi_16mhz_3v3_48 = {
+ /* 48MHz */
+ .pllm = 16,
+ .plln = 96,
+ .pllp = 2,
+ .pllq = 2,
+ .hpre = RCC_CFGR_HPRE_DIV_NONE,
+ .ppre1 = RCC_CFGR_PPRE_DIV_4,
+ .ppre2 = RCC_CFGR_PPRE_DIV_2,
+ .power_save = 1,
+ .flash_config = FLASH_ACR_ICE | FLASH_ACR_DCE |
+ FLASH_ACR_LATENCY_3WS,
+ .apb1_frequency = 12000000,
+ .apb2_frequency = 24000000,
+};
+
+static void rcc_clock_setup_hsi_3v3 (const clock_scale_t *clock)
+{
+
+ /* Enable internal high-speed oscillator. */
+ rcc_osc_on (HSI);
+ rcc_wait_for_osc_ready (HSI);
+
+ /* Select HSI as SYSCLK source. */
+ rcc_set_sysclk_source (RCC_CFGR_SW_HSI);
+ rcc_wait_for_sysclk_status (HSI);
+
+ rcc_osc_off (PLL);
+
+ while (RCC_CR & RCC_CR_PLLRDY);
+
+ pwr_set_vos_scale (SCALE1);
+
+ /*
+ * Set prescalers for AHB, ADC, ABP1, ABP2.
+ * Do this before touching the PLL (TODO: why?).
+ */
+ rcc_set_hpre (clock->hpre);
+ rcc_set_ppre1 (clock->ppre1);
+ rcc_set_ppre2 (clock->ppre2);
+
+ rcc_set_main_pll_hsi (clock->pllm, clock->plln,
+ clock->pllp, clock->pllq);
+
+ /* Enable PLL oscillator and wait for it to stabilize. */
+ rcc_osc_on (PLL);
+ rcc_wait_for_osc_ready (PLL);
+
+ /* Configure flash settings. */
+ flash_set_ws (clock->flash_config);
+
+ /* Select PLL as SYSCLK source. */
+ rcc_set_sysclk_source (RCC_CFGR_SW_PLL);
+
+ /* Wait for PLL clock to be selected. */
+ rcc_wait_for_sysclk_status (PLL);
+
+ /* Set the peripheral clock frequencies used. */
+ rcc_apb1_frequency = clock->apb1_frequency;
+ rcc_apb2_frequency = clock->apb2_frequency;
+
+}
+
+
+int main (void)
+{
+
+ rcc_periph_clock_enable (RCC_GPIOE);
+ MAP_INPUT_PU (BOOTLOADER_BUTTON);
+
+
+ if ((dfu_flag != 0xfee1dead) && (GET(BOOTLOADER_BUTTON))) {
+ /* Boot the application if it's valid. */
+ if ((* (volatile uint32_t *)APP_ADDRESS & 0x2FFE0000) == 0x20020000) {
+ /* Set vector table base address. */
+ SCB_VTOR = APP_ADDRESS & 0xFFFF;
+ /* Initialise master stack pointer. */
+ asm volatile ("msr msp, %0\n"
+ "blx %1\n" ::
+ "g" (* (volatile uint32_t *)APP_ADDRESS),
+ "r" (* (uint32_t *) (APP_ADDRESS + 4))
+ : "memory");
+ }
+ }
+
+
+
+
+ dfu_flag = 0;
+
+ rcc_periph_clock_enable (RCC_SYSCFG);
+ rcc_periph_clock_enable (RCC_GPIOB);
+ rcc_periph_clock_enable (RCC_GPIOG);
+
+ rcc_clock_setup_hsi_3v3 (&hsi_16mhz_3v3_48);
+
+ RCC_AHB1RSTR |= RCC_AHB1RSTR_ETHMACRST;
+ RCC_AHB2RSTR |= RCC_AHB2RSTR_OTGFSRST;
+ asm ("nop":::"memory");
+ RCC_AHB2RSTR &= ~RCC_AHB2RSTR_OTGFSRST;
+ RCC_AHB1RSTR &= ~RCC_AHB1RSTR_ETHMACRST;
+
+ max7219_init();
+
+ usart_init();
+ usart2_xmit_str("\r\nDFU Bootloader\r\n");
+ delay_ms (100);
+ usart_init();
+ usart2_xmit_str ("Ready\r\n");
+
+
+ usb();
+}
diff --git a/boot/bootloader.ld b/boot/bootloader.ld
new file mode 100644
index 0000000..cedb886
--- /dev/null
+++ b/boot/bootloader.ld
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/* Linker script for Olimex STM32-H103 (STM32F103RBT6, 128K flash, 20K RAM). */
+
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 16K
+ ram (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f4.ld
+
+dfu_shared_location = ORIGIN(ram) + LENGTH(ram) - 1024;
+
+SECTIONS
+{
+ .dfu_shared dfu_shared_location :{
+ dfu_flag = .;
+ }
+}
diff --git a/boot/delay.c b/boot/delay.c
new file mode 100644
index 0000000..132081a
--- /dev/null
+++ b/boot/delay.c
@@ -0,0 +1,42 @@
+#include "project.h"
+
+
+
+static volatile uint32_t delay_ms_count;
+
+void
+sys_tick_handler (void)
+{
+ if (delay_ms_count)
+ delay_ms_count--;
+}
+void
+ticker_on (void)
+{
+ /*168MHz 1ms */
+ systick_set_reload (48000);
+ systick_set_clocksource (STK_CSR_CLKSOURCE_AHB);
+ systick_counter_enable();
+ /* this done last */
+ systick_interrupt_enable();
+}
+
+void
+ticker_off (void)
+{
+ systick_interrupt_disable();
+ systick_counter_disable();
+}
+
+
+void
+delay_ms (uint32_t d)
+{
+ ticker_on();
+ delay_ms_count = d;
+
+ while (delay_ms_count);
+ ticker_off();
+}
+
+
diff --git a/boot/dfu.c b/boot/dfu.c
new file mode 100644
index 0000000..f931a6e
--- /dev/null
+++ b/boot/dfu.c
@@ -0,0 +1,197 @@
+#include "project.h"
+
+/* Commands sent with wBlockNum == 0 as per ST implementation. */
+#define CMD_SETADDR 0x21
+#define CMD_ERASE 0x41
+
+
+/* We need a special large control buffer for this device: */
+
+static enum dfu_state usbdfu_state = STATE_DFU_IDLE;
+
+static uint32_t sector_bases[] = {
+ 0x08000000,
+ 0x08004000,
+ 0x08008000,
+ 0x0800C000,
+ 0x08010000,
+ 0x08020000,
+ 0x08040000,
+ 0x08060000,
+ 0x08080000,
+ 0x080A0000,
+ 0x080C0000,
+ 0x080E0000,
+};
+
+#define N_SECTORS (sizeof(sector_bases)/sizeof(sector_bases[0]))
+
+static struct {
+ uint8_t buf[sizeof (usbd_control_buffer)];
+ uint16_t len;
+ uint32_t addr;
+ uint16_t blocknum;
+} prog;
+
+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 = 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),
+};
+
+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 int usbdfu_getstatus_complete (usbd_device *usbd_dev, struct usb_setup_data *req)
+{
+ unsigned 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);
+
+ for (i = 0; i < N_SECTORS; ++i) {
+ if (*dat == sector_bases[i])
+ flash_erase_sector (i, FLASH_CR_PROGRAM_X32);
+ }
+ }
+
+ /*Fall through*/
+ 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 += 4) {
+ uint32_t *dat = (uint32_t *) (prog.buf + i);
+ flash_program_word (baseaddr + i, *dat);
+ }
+ }
+
+ flash_lock();
+
+ /* Jump straight to dfuDNLOAD-IDLE, skipping dfuDNLOAD-SYNC. */
+ usbdfu_state = STATE_DFU_DNLOAD_IDLE;
+ return 0;
+
+ case STATE_DFU_MANIFEST:
+ /* USB device must detach, we just reset... */
+ scb_reset_system();
+ return 0; /* Will never return. */
+
+ default:
+ return 0;
+ }
+}
+
+int usbdfu_control_request (usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
+ uint16_t *len, int (**complete) (usbd_device *usbd_dev, struct usb_setup_data *req))
+{
+
+ 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;
+}
+
+
diff --git a/boot/gdb.script b/boot/gdb.script
new file mode 100644
index 0000000..7cf9d09
--- /dev/null
+++ b/boot/gdb.script
@@ -0,0 +1,2 @@
+target remote localhost:3333
+cont
diff --git a/boot/max7219.c b/boot/max7219.c
new file mode 100644
index 0000000..3e06562
--- /dev/null
+++ b/boot/max7219.c
@@ -0,0 +1,124 @@
+#include "project.h"
+
+#define NCS (GPIO7)
+#define NCS_PORT GPIOG
+
+#define SCK (GPIO3)
+#define SCK_PORT GPIOB
+
+#define MOSI (GPIO5)
+#define MOSI_PORT GPIOB
+
+
+static void
+set (int sck, int ncs, int mosi)
+{
+ if (sck)
+ SET (SCK);
+ else
+ CLEAR (SCK);
+
+
+ if (ncs)
+ SET (NCS);
+ else
+ CLEAR (NCS);
+
+
+ if (mosi)
+ SET (MOSI);
+ else
+ CLEAR (MOSI);
+
+ // delay_us(1);
+ //delay_us(10);
+
+}
+
+static void
+spip_send_8 (uint8_t wot)
+{
+ int i;
+
+ for (i = 0; i < 8; ++i) {
+ set (0, 0, wot & 0x80);
+ set (1, 0, wot & 0x80);
+ set (0, 0, wot & 0x80);
+ wot <<= 1;
+ }
+}
+
+
+
+static void
+write_reg (uint8_t reg, uint8_t data)
+{
+
+ set (0, 1, 0);
+ set (0, 0, 0);
+
+ spip_send_8 (reg);
+ spip_send_8 (data);
+
+ spip_send_8 (reg);
+ spip_send_8 (data);
+
+ spip_send_8 (reg);
+ spip_send_8 (data);
+
+ set (0, 0, 0);
+ set (0, 1, 0);
+}
+
+
+static void
+write_regs (uint8_t reg, uint8_t data1, uint8_t data2, uint8_t data3)
+{
+
+ set (0, 1, 0);
+ set (0, 0, 0);
+
+ spip_send_8 (reg);
+ spip_send_8 (data3);
+
+ spip_send_8 (reg);
+ spip_send_8 (data2);
+
+ spip_send_8 (reg);
+ spip_send_8 (data1);
+
+ set (0, 0, 0);
+ set (0, 1, 0);
+}
+
+
+void
+max7219_init (void)
+{
+ MAP_OUTPUT_PP (SCK);
+ MAP_OUTPUT_PP (NCS);
+ MAP_OUTPUT_PP (MOSI);
+
+ set (0, 1, 0);
+
+
+ write_reg (0xc, 0x1); //Power up
+ write_reg (0xf, 0x0); //normal mode
+
+ write_reg (0x9, 0x0); //No decode
+ write_reg (0xb, 0x7); //8 digits
+ write_regs (0xa,15,15,15); //max brightness
+ write_reg (1,0);
+ write_reg (2,0);
+ write_reg (3,0);
+ write_reg (4,0);
+ write_reg (5,0);
+ write_regs (6,0xbe,0,0);
+ write_regs (7,0x47,0,0);
+ write_regs (8,0x3d,0,0);
+
+}
+
+
+
+
diff --git a/boot/pins.h b/boot/pins.h
new file mode 100644
index 0000000..723ca82
--- /dev/null
+++ b/boot/pins.h
@@ -0,0 +1,55 @@
+
+#define MAP_AF_100(a, af) do { \
+ gpio_mode_setup( a ## _PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, a ); \
+ gpio_set_output_options( a ## _PORT, GPIO_OTYPE_PP, GPIO_OSPEED_100MHZ, a); \
+ gpio_set_af( a ## _PORT, af, a); \
+ } while (0)
+
+#define MAP_AF(a, af) do { \
+ gpio_mode_setup( a ## _PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, a ); \
+ gpio_set_output_options( a ## _PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, a); \
+ gpio_set_af( a ## _PORT, af, a); \
+ } while (0)
+
+#define MAP_AF_PU(a, af) do { \
+ gpio_mode_setup( a ## _PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, a ); \
+ gpio_set_output_options( a ## _PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, a); \
+ gpio_set_af( a ## _PORT, af, a); \
+ } while (0)
+
+#define MAP_AF_OD(a, af) do { \
+ gpio_mode_setup( a ## _PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, a ); \
+ gpio_set_output_options( a ## _PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, a); \
+ gpio_set_af( a ## _PORT, af, a); \
+ } while (0)
+
+
+#define MAP_OUTPUT_PP(a) do { \
+ gpio_mode_setup( a ## _PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, a ); \
+ gpio_set_output_options( a ## _PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, a); \
+ } while (0)
+
+#define MAP_OUTPUT_PP_PU(a) do { \
+ gpio_mode_setup( a ## _PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, a ); \
+ gpio_set_output_options( a ## _PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, a); \
+ } while (0)
+
+#define MAP_OUTPUT_OD(a) do { \
+ gpio_mode_setup( a ## _PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, a ); \
+ gpio_set_output_options( a ## _PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, a); \
+ } while (0)
+
+
+#define MAP_INPUT_PU(a) do { \
+ gpio_mode_setup( a ## _PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, a ); \
+ } while (0)
+
+
+#define MAP_INPUT(a) do { \
+ gpio_mode_setup( a ## _PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, 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)
diff --git a/boot/project.h b/boot/project.h
new file mode 100644
index 0000000..5699389
--- /dev/null
+++ b/boot/project.h
@@ -0,0 +1,29 @@
+#include <string.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/gpio.h>
+#include <libopencm3/stm32/flash.h>
+#include <libopencm3/stm32/otg_common.h>
+#include <libopencm3/stm32/otg_fs.h>
+#include <libopencm3/stm32/pwr.h>
+#include <libopencm3/stm32/syscfg.h>
+#include <libopencm3/stm32/usart.h>
+
+
+#include <libopencm3/cm3/systick.h>
+#include <libopencm3/cm3/scb.h>
+#include <libopencm3/cm3/cortex.h>
+
+#include <libopencm3/usb/usbd.h>
+#include <libopencm3/usb/dfu.h>
+
+#include "pins.h"
+
+#include <id.h>
+
+
+
+#include "prototypes.h"
+extern uint32_t dfu_flag;
+
+
+#define APP_ADDRESS 0x08004000
diff --git a/boot/prototypes.h b/boot/prototypes.h
new file mode 100644
index 0000000..17cc0fa
--- /dev/null
+++ b/boot/prototypes.h
@@ -0,0 +1,27 @@
+/* bootloader.c */
+extern int main(void);
+/* usb.c */
+extern uint8_t usbd_control_buffer[1024];
+extern const struct usb_device_descriptor dev;
+extern const struct usb_interface ifaces[];
+extern const struct usb_config_descriptor config;
+extern void usb_set_config(usbd_device *usbd_dev, uint16_t wValue);
+extern void usb(void);
+/* dfu.c */
+extern const struct usb_dfu_descriptor dfu_function;
+extern const struct usb_interface_descriptor dfu_iface;
+extern int usbdfu_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, int (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req));
+/* delay.c */
+extern void sys_tick_handler(void);
+extern void ticker_on(void);
+extern void ticker_off(void);
+extern void delay_ms(uint32_t d);
+/* usart.c */
+extern void usart2_xmit_chr(char d);
+extern void usart2_xmit_str(const char *s);
+extern void usart2_xmit_nl(void);
+extern void usart2_xmit_xdigit(unsigned d);
+extern void usart2_xmit_uint32(uint32_t v);
+extern void usart_init(void);
+/* max7219.c */
+extern void max7219_init(void);
diff --git a/boot/usart.c b/boot/usart.c
new file mode 100644
index 0000000..c602710
--- /dev/null
+++ b/boot/usart.c
@@ -0,0 +1,68 @@
+#include "project.h"
+
+
+#define TX2 GPIO5
+#define TX2_PORT GPIOD
+
+#define RX2 GPIO6
+#define RX2_PORT GPIOD
+
+
+void
+usart2_xmit_chr (char d)
+{
+ usart_send_blocking (USART2, d);
+}
+
+
+void
+usart2_xmit_str (const char *s)
+{
+ while (*s)
+ usart_send_blocking (USART2, * (s++));
+}
+
+
+void usart2_xmit_nl (void)
+{
+ usart2_xmit_str ("\r\n");
+}
+
+void usart2_xmit_xdigit (unsigned d)
+{
+ if (d < 0xa) usart2_xmit_chr ('0' + d);
+ else usart2_xmit_chr ('a' + (d - 0xa));
+}
+
+void usart2_xmit_uint32 (uint32_t v)
+{
+ unsigned i;
+
+ for (i = 0; i < 8; ++i) {
+ usart2_xmit_xdigit (v >> 28);
+ v <<= 4;
+ }
+}
+
+
+void
+usart_init (void)
+{
+ rcc_periph_clock_enable (RCC_GPIOD);
+ rcc_periph_clock_enable (RCC_USART2);
+
+
+ MAP_INPUT (RX2);
+ MAP_AF (TX2, GPIO_AF7);
+ MAP_AF_PU (RX2, GPIO_AF7);
+
+
+ usart_set_baudrate (USART2, 38400);
+ usart_set_databits (USART2, 8);
+ usart_set_stopbits (USART2, USART_STOPBITS_1);
+ usart_set_parity (USART2, USART_PARITY_NONE);
+ usart_set_flow_control (USART2, USART_FLOWCONTROL_NONE);
+ usart_set_mode (USART2, USART_MODE_TX_RX);
+
+ usart_enable (USART2);
+}
diff --git a/boot/usb.c b/boot/usb.c
new file mode 100644
index 0000000..e8d2e20
--- /dev/null
+++ b/boot/usb.c
@@ -0,0 +1,94 @@
+#include "project.h"
+
+#define USB_DM GPIO11
+#define USB_DM_PORT GPIOA
+#define USB_DP GPIO12
+#define USB_DP_PORT GPIOA
+
+uint8_t usbd_control_buffer[1024];
+
+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_interface ifaces[] = {{
+ .num_altsetting = 1,
+ .altsetting = &dfu_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/04*016Kg,01*064Kg,07*128Kg",
+};
+
+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);
+
+}
+
+
+void usb (void)
+{
+ usbd_device *usbd_dev;
+
+
+ rcc_periph_clock_enable (RCC_GPIOA);
+ rcc_periph_clock_enable (RCC_OTGFS);
+
+ MAP_AF_100 (USB_DP, GPIO_AF10);
+ MAP_AF_100 (USB_DM, GPIO_AF10);
+
+
+ usbd_dev = usbd_init (&otgfs_usb_driver, &dev, &config, usb_strings, 4, usbd_control_buffer, sizeof (usbd_control_buffer));
+
+ OTG_FS_GCCFG |= OTG_GCCFG_NOVBUSSENS;
+ OTG_FS_GCCFG &= ~OTG_GCCFG_VBUSASEN;
+ OTG_FS_GCCFG &= ~OTG_GCCFG_VBUSBSEN;
+
+ usbd_register_set_config_callback (usbd_dev, usb_set_config);
+
+
+ while (1)
+ usbd_poll (usbd_dev);
+
+}
diff --git a/id.h b/id.h
new file mode 100644
index 0000000..6457b33
--- /dev/null
+++ b/id.h
@@ -0,0 +1,7 @@
+#define ID_VENDOR 0x0483
+#define ID_PRODUCT 0x5740
+
+#define VENDOR_NAME "Me!"
+#define PRODUCT_NAME "Clock thing"
+#define SERIAL_NUMBER "Serialy McSerialFace"
+