2 * Generic DFU Bootloader
4 * (c) 2020 Martin Mareš <mj@ucw.cz>
6 * Based on example code from the libopencm3 project, which is
7 * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
9 * Licensed under the GNU LGPL v3 or any later version.
14 #include <libopencm3/cm3/cortex.h>
15 #include <libopencm3/cm3/nvic.h>
16 #include <libopencm3/cm3/scb.h>
17 #include <libopencm3/cm3/systick.h>
18 #include <libopencm3/stm32/rcc.h>
19 #include <libopencm3/stm32/crc.h>
20 #include <libopencm3/stm32/gpio.h>
21 #include <libopencm3/stm32/flash.h>
22 #include <libopencm3/stm32/usart.h>
23 #include <libopencm3/stm32/desig.h>
24 #include <libopencm3/usb/usbd.h>
25 #include <libopencm3/usb/dfu.h>
29 #ifdef BOOTLOADER_DEBUG
30 #define DEBUG(x...) debug_printf(x)
32 #define DEBUG(x...) do { } while (0)
35 // Offsets to firmware header fields (see tools/dfu-sign.c)
36 #define HDR_LENGTH 0x1c
37 #define HDR_FLASH_IN_PROGRESS 0x20
39 // DFU blocks should be equal to erase blocks of the flash
40 #define BLOCK_SIZE 1024
41 byte usbd_control_buffer[BLOCK_SIZE];
43 static enum dfu_state dfu_state = STATE_DFU_IDLE;
45 #define DEFAULT_TIMEOUT 5000 // ms
46 #define DFU_TIMEOUT 2000
49 byte buf[sizeof(usbd_control_buffer)];
54 static char usb_serial_number[13];
62 static const char *usb_strings[] = {
68 const struct usb_device_descriptor dev = {
69 .bLength = USB_DT_DEVICE_SIZE,
70 .bDescriptorType = USB_DT_DEVICE,
75 .bMaxPacketSize0 = 64,
76 .idVendor = BOOTLOADER_MFG_ID,
77 .idProduct = BOOTLOADER_PROD_ID,
78 .bcdDevice = BOOTLOADER_PROD_VERSION,
79 .iManufacturer = STR_MANUFACTURER,
80 .iProduct = STR_PRODUCT,
81 .iSerialNumber = STR_SERIAL,
82 .bNumConfigurations = 1,
85 const struct usb_dfu_descriptor dfu_function = {
86 .bLength = sizeof(struct usb_dfu_descriptor),
87 .bDescriptorType = DFU_FUNCTIONAL,
88 .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
89 .wDetachTimeout = 255,
90 .wTransferSize = BLOCK_SIZE,
91 .bcdDFUVersion = 0x0100,
94 const struct usb_interface_descriptor iface = {
95 .bLength = USB_DT_INTERFACE_SIZE,
96 .bDescriptorType = USB_DT_INTERFACE,
97 .bInterfaceNumber = 0,
98 .bAlternateSetting = 0,
100 .bInterfaceClass = 0xFE, /* Device Firmware Upgrade */
101 .bInterfaceSubClass = 1,
102 .bInterfaceProtocol = 2,
103 .extra = &dfu_function,
104 .extralen = sizeof(dfu_function),
107 const struct usb_interface ifaces[] = {{
109 .altsetting = &iface,
112 const struct usb_config_descriptor config = {
113 .bLength = USB_DT_CONFIGURATION_SIZE,
114 .bDescriptorType = USB_DT_CONFIGURATION,
117 .bConfigurationValue = 1,
119 .bmAttributes = USB_CONFIG_ATTR_DEFAULT, // bus-powered
120 .bMaxPower = 50, // multiplied by 2 mA
124 static inline u32 get_u32(u32 addr)
129 static inline u16 get_u16(u32 addr)
134 static bool verify_firmware(void)
136 u32 len = get_u32(BOOTLOADER_APP_START + HDR_LENGTH);
137 u16 flash_in_progress = get_u16(BOOTLOADER_APP_START + HDR_FLASH_IN_PROGRESS);
139 // FIXME: Should check if len is reasonable
142 u32 crc = crc_calculate_block((u32 *)BOOTLOADER_APP_START, len/4);
143 u32 want_crc = get_u32(BOOTLOADER_APP_START + len);
144 DEBUG("DFU: fip=%04x crc=%08x/%08x len=%u\n", (uint) flash_in_progress, (uint) crc, (uint) want_crc, (uint) len);
145 if (flash_in_progress || crc != want_crc) {
146 DEBUG("DFU: Bad firmware\n");
153 static byte dfu_getstatus(usbd_device *usbd_dev UNUSED, u32 *bwPollTimeout)
156 case STATE_DFU_DNLOAD_SYNC:
157 dfu_state = STATE_DFU_DNBUSY;
158 *bwPollTimeout = 100;
159 return DFU_STATUS_OK;
160 case STATE_DFU_MANIFEST_SYNC:
161 /* Device will reset when read is complete. */
162 dfu_state = STATE_DFU_MANIFEST;
163 return DFU_STATUS_OK;
164 case STATE_DFU_ERROR:
165 return DFU_STATUS_ERR_VERIFY;
167 return DFU_STATUS_OK;
171 static void dfu_getstatus_complete(usbd_device *usbd_dev UNUSED, struct usb_setup_data *req UNUSED)
174 case STATE_DFU_DNBUSY:
175 if (prog.blocknum == 0) {
176 // The "flash in progress" word is programmed as 0xffff first and reset later
177 *(u16*)(prog.buf + HDR_FLASH_IN_PROGRESS) = 0xffff;
179 u32 baseaddr = BOOTLOADER_APP_START + prog.blocknum * BLOCK_SIZE;
180 DEBUG("DFU: Block %u -> %08x + %u\n", prog.blocknum, (uint) baseaddr, prog.len);
182 flash_erase_page(baseaddr);
183 for (uint i = 0; i < prog.len; i += 2)
184 flash_program_half_word(baseaddr + i, *(u16*)(prog.buf + i));
186 for (uint i = 0; i < prog.len; i++) {
187 if (*(byte *)(baseaddr + i) != prog.buf[i]) {
188 DEBUG("DFU: Verification failed\n");
189 dfu_state = STATE_DFU_ERROR;
192 dfu_state = STATE_DFU_DNLOAD_IDLE;
194 case STATE_DFU_MANIFEST:
195 // At the very end, re-flash the "flash in progress" word
197 flash_program_half_word(BOOTLOADER_APP_START + 0x20, 0);
199 if (verify_firmware())
200 dfu_state = STATE_DFU_MANIFEST_WAIT_RESET;
202 dfu_state = STATE_DFU_ERROR;
209 static enum usbd_request_return_codes dfu_control_request(usbd_device *usbd_dev,
210 struct usb_setup_data *req,
213 void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
215 if ((req->bmRequestType & 0x7F) != 0x21)
216 return USBD_REQ_NOTSUPP; /* Only accept class request. */
218 DEBUG("DFU: Request %02x in state %d\n", req->bRequest, dfu_state);
219 timeout = DFU_TIMEOUT;
221 switch (req->bRequest) {
223 if (len == NULL || *len == 0) {
224 dfu_state = STATE_DFU_MANIFEST_SYNC;
226 /* Copy download data for use on GET_STATUS. */
227 prog.blocknum = req->wValue;
229 memcpy(prog.buf, *buf, *len);
230 dfu_state = STATE_DFU_DNLOAD_SYNC;
232 return USBD_REQ_HANDLED;
234 /* Clear error and return to dfuIDLE. */
235 if (dfu_state == STATE_DFU_ERROR)
236 dfu_state = STATE_DFU_IDLE;
237 return USBD_REQ_HANDLED;
239 /* Abort returns to dfuIDLE state. */
240 dfu_state = STATE_DFU_IDLE;
241 return USBD_REQ_HANDLED;
243 /* Upload not supported for now. */
244 return USBD_REQ_NOTSUPP;
245 case DFU_GETSTATUS: {
246 u32 bwPollTimeout = 0; /* 24-bit number of milliseconds */
247 (*buf)[0] = dfu_getstatus(usbd_dev, &bwPollTimeout);
248 (*buf)[1] = bwPollTimeout & 0xFF;
249 (*buf)[2] = (bwPollTimeout >> 8) & 0xFF;
250 (*buf)[3] = (bwPollTimeout >> 16) & 0xFF;
251 (*buf)[4] = dfu_state;
252 (*buf)[5] = 0; /* iString not used here */
254 *complete = dfu_getstatus_complete;
255 return USBD_REQ_HANDLED;
258 /* Return state with no state transition. */
261 return USBD_REQ_HANDLED;
264 return USBD_REQ_NOTSUPP;
267 static void dfu_set_config(usbd_device *usbd_dev, u16 wValue UNUSED)
269 usbd_register_control_callback(
271 USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
272 USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
273 dfu_control_request);
276 static void dfu_reset(void)
278 dfu_state = STATE_DFU_IDLE;
282 * This is a modified version of rcc_clock_setup_in_hsi_out_48mhz(),
283 * which properly turns off the PLL before setting its parameters.
285 static void my_rcc_clock_setup_in_hsi_out_48mhz(void)
287 /* Enable internal high-speed oscillator. */
289 rcc_wait_for_osc_ready(RCC_HSI);
291 /* Select HSI as SYSCLK source. */
292 rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
295 rcc_osc_off(RCC_PLL);
298 * Set prescalers for AHB, ADC, ABP1, ABP2.
299 * Do this before touching the PLL (TODO: why?).
301 rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /*Set.48MHz Max.72MHz */
302 rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV8); /*Set. 6MHz Max.14MHz */
303 rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2); /*Set.24MHz Max.36MHz */
304 rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /*Set.48MHz Max.72MHz */
305 rcc_set_usbpre(RCC_CFGR_USBPRE_PLL_CLK_NODIV); /*Set.48MHz Max.48MHz */
308 * Sysclk runs with 48MHz -> 1 waitstates.
313 flash_set_ws(FLASH_ACR_LATENCY_1WS);
316 * Set the PLL multiplication factor to 12.
317 * 8MHz (internal) * 12 (multiplier) / 2 (PLLSRC_HSI_CLK_DIV2) = 48MHz
319 rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL12);
321 /* Select HSI/2 as PLL source. */
322 rcc_set_pll_source(RCC_CFGR_PLLSRC_HSI_CLK_DIV2);
324 /* Enable PLL oscillator and wait for it to stabilize. */
326 rcc_wait_for_osc_ready(RCC_PLL);
328 /* Select PLL as SYSCLK source. */
329 rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
331 /* Set the peripheral clock frequencies used */
332 rcc_ahb_frequency = 48000000;
333 rcc_apb1_frequency = 24000000;
334 rcc_apb2_frequency = 48000000;
337 static void clock_plain_hsi(void)
339 // Select HSI as SYSCLK source
340 rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
343 rcc_osc_off(RCC_PLL);
345 // Set prescalers for AHB, ADC, ABP1, ABP2, USB to defaults
346 rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV);
347 rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2);
348 rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_NODIV);
349 rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV);
350 rcc_set_usbpre(RCC_CFGR_USBPRE_PLL_VCO_CLK_DIV3);
353 static void reset_peripherals(void)
355 // Turn off clock to all peripherals and reset them
356 RCC_AHBENR = 0x00000014;
359 RCC_APB1RSTR = 0x22fec9ff;
360 RCC_APB2RSTR = 0x0038fffd;
365 static void configure_hardware(void)
367 rcc_periph_clock_enable(RCC_GPIOA);
368 rcc_periph_clock_enable(RCC_GPIOC);
369 rcc_periph_clock_enable(RCC_USB);
370 rcc_periph_clock_enable(RCC_CRC);
373 // Currently, only USART1 is supported
374 rcc_periph_clock_enable(RCC_USART1);
375 rcc_periph_reset_pulse(RST_USART1);
376 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9);
378 usart_set_baudrate(USART1, 115200);
379 usart_set_databits(USART1, 8);
380 usart_set_stopbits(USART1, USART_STOPBITS_1);
381 usart_set_mode(USART1, USART_MODE_TX);
382 usart_set_parity(USART1, USART_PARITY_NONE);
383 usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
385 usart_enable(USART1);
388 #ifdef DEBUG_LED_BLUEPILL
390 gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
394 // Systick: set to overflow in 1 ms, will use only the overflow flag, no interrupts
395 systick_set_frequency(1000, CPU_CLOCK_MHZ * 1000000);
397 systick_counter_enable();
400 static void usb_disconnect(void)
402 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO11 | GPIO12);
403 gpio_clear(GPIOA, GPIO11 | GPIO12);
404 for (uint i=0; i<100; i++) {
405 while (!systick_get_countflag())
412 usbd_device *usbd_dev;
416 // Flash programming requires running on the internal oscillator
417 my_rcc_clock_setup_in_hsi_out_48mhz();
419 configure_hardware();
420 desig_get_unique_id_as_dfu(usb_serial_number);
422 DEBUG("DFU: Started (SN %s)\n", usb_serial_number);
426 DEBUG("DFU: Ready\n");
429 usbd_dev = usbd_init(&st_usbfs_v1_usb_driver, &dev, &config, usb_strings, ARRAY_SIZE(usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer));
430 usbd_register_reset_callback(usbd_dev, dfu_reset);
431 usbd_register_set_config_callback(usbd_dev, dfu_set_config);
435 timeout = DEFAULT_TIMEOUT;
436 while (timeout || (dfu_state != STATE_DFU_IDLE && dfu_state != STATE_DFU_MANIFEST_WAIT_RESET)) {
438 if (timeout && systick_get_countflag()) {
440 // FIXME: Blink LED even after timeout
441 if (!(timeout & 0x3f))
446 if (!verify_firmware())
449 u32 sp = get_u32(BOOTLOADER_APP_START);
450 u32 pc = get_u32(BOOTLOADER_APP_START + 4);
451 DEBUG("DFU: Boot (sp=%08x pc=%08x)\n", (uint) sp, (uint) pc);
454 while (!usart_get_flag(DEBUG_USART, USART_FLAG_TC))
462 /* Set vector table base address. */
463 SCB_VTOR = BOOTLOADER_APP_START;
465 /* Initialize master stack pointer. */
466 asm volatile("msr msp, %0"::"g" (sp));
468 /* Jump to application. */
469 ((void (*)(void)) pc)();