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/gpio.h>
20 #include <libopencm3/stm32/flash.h>
21 #include <libopencm3/stm32/usart.h>
22 #include <libopencm3/stm32/desig.h>
23 #include <libopencm3/usb/usbd.h>
24 #include <libopencm3/usb/dfu.h>
28 #ifdef BOOTLOADER_DEBUG
29 #define DEBUG(x...) debug_printf(x)
31 #define DEBUG(x...) do { } while (0)
34 byte usbd_control_buffer[1024];
36 static enum dfu_state usbdfu_state = STATE_DFU_IDLE;
39 byte buf[sizeof(usbd_control_buffer)];
44 static struct prog_info prog_page;
46 // The first page of application code is programmed last,
47 // so that we are able to detect incompletely uploaded firmware.
48 static struct prog_info prog_header;
50 static char usb_serial_number[13];
58 static const char *usb_strings[] = {
64 const struct usb_device_descriptor dev = {
65 .bLength = USB_DT_DEVICE_SIZE,
66 .bDescriptorType = USB_DT_DEVICE,
71 .bMaxPacketSize0 = 64,
72 .idVendor = BOOTLOADER_MFG_ID,
73 .idProduct = BOOTLOADER_PROD_ID,
74 .bcdDevice = BOOTLOADER_PROD_VERSION,
75 .iManufacturer = STR_MANUFACTURER,
76 .iProduct = STR_PRODUCT,
77 .iSerialNumber = STR_SERIAL,
78 .bNumConfigurations = 1,
81 const struct usb_dfu_descriptor dfu_function = {
82 .bLength = sizeof(struct usb_dfu_descriptor),
83 .bDescriptorType = DFU_FUNCTIONAL,
84 .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
85 .wDetachTimeout = 255,
86 .wTransferSize = 1024,
87 .bcdDFUVersion = 0x0100,
90 const struct usb_interface_descriptor iface = {
91 .bLength = USB_DT_INTERFACE_SIZE,
92 .bDescriptorType = USB_DT_INTERFACE,
93 .bInterfaceNumber = 0,
94 .bAlternateSetting = 0,
96 .bInterfaceClass = 0xFE, /* Device Firmware Upgrade */
97 .bInterfaceSubClass = 1,
98 .bInterfaceProtocol = 2,
99 .extra = &dfu_function,
100 .extralen = sizeof(dfu_function),
103 const struct usb_interface ifaces[] = {{
105 .altsetting = &iface,
108 const struct usb_config_descriptor config = {
109 .bLength = USB_DT_CONFIGURATION_SIZE,
110 .bDescriptorType = USB_DT_CONFIGURATION,
113 .bConfigurationValue = 1,
115 .bmAttributes = USB_CONFIG_ATTR_DEFAULT, // bus-powered
116 .bMaxPower = 50, // multiplied by 2 mA
121 static u32 adhoc_checksum(u32 start, uint len)
123 u32 end = start + len;
125 while (start < end) {
127 sum += *(volatile u32 *)start;
134 static byte usbdfu_getstatus(usbd_device *usbd_dev UNUSED, u32 *bwPollTimeout)
136 switch (usbdfu_state) {
137 case STATE_DFU_DNLOAD_SYNC:
138 usbdfu_state = STATE_DFU_DNBUSY;
139 *bwPollTimeout = 100;
140 return DFU_STATUS_OK;
141 case STATE_DFU_MANIFEST_SYNC:
142 /* Device will reset when read is complete. */
143 usbdfu_state = STATE_DFU_MANIFEST;
144 return DFU_STATUS_OK;
146 return DFU_STATUS_OK;
150 static void program_page(struct prog_info *prog, bool need_erase)
153 u32 baseaddr = BOOTLOADER_APP_START + prog->blocknum * dfu_function.wTransferSize;
154 DEBUG("DFU: Block %u -> %08x + %u\n", prog->blocknum, (uint) baseaddr, prog->len);
156 flash_erase_page(baseaddr);
157 for (uint i = 0; i < prog->len; i += 2) {
158 u16 data = *(u16 *)(prog->buf + i);
159 flash_program_half_word(baseaddr + i, data);
163 u32 s1 = adhoc_checksum((u32) prog->buf, prog->len);
164 u32 s2 = adhoc_checksum(baseaddr, prog->len);
165 DEBUG("\t%08x %08x\n", (uint) s1, (uint) s2);
167 DEBUG("\t!!!!!!!!!!!!!!!!!!!!!!!!!\n");
171 static void usbdfu_getstatus_complete(usbd_device *usbd_dev UNUSED, struct usb_setup_data *req UNUSED)
173 switch (usbdfu_state) {
174 case STATE_DFU_DNBUSY:
175 if (prog_page.blocknum == 0) {
176 // The first block will be programmed last
177 prog_header = prog_page;
179 flash_erase_page(BOOTLOADER_APP_START);
182 program_page(&prog_page, true);
183 usbdfu_state = STATE_DFU_DNLOAD_IDLE;
185 case STATE_DFU_MANIFEST:
186 // At the very end, program the first page
187 program_page(&prog_header, false);
188 usbdfu_state = STATE_DFU_MANIFEST_WAIT_RESET;
189 return; /* Will never return. */
195 static enum usbd_request_return_codes usbdfu_control_request(usbd_device *usbd_dev,
196 struct usb_setup_data *req,
199 void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
201 if ((req->bmRequestType & 0x7F) != 0x21)
202 return USBD_REQ_NOTSUPP; /* Only accept class request. */
204 DEBUG("DFU: Request %02x in state %d\n", req->bRequest, usbdfu_state);
206 switch (req->bRequest) {
208 if (len == NULL || *len == 0) {
209 usbdfu_state = STATE_DFU_MANIFEST_SYNC;
211 /* Copy download data for use on GET_STATUS. */
212 prog_page.blocknum = req->wValue;
213 prog_page.len = *len;
214 memcpy(prog_page.buf, *buf, *len);
215 usbdfu_state = STATE_DFU_DNLOAD_SYNC;
217 return USBD_REQ_HANDLED;
219 /* Clear error and return to dfuIDLE. */
220 if (usbdfu_state == STATE_DFU_ERROR)
221 usbdfu_state = STATE_DFU_IDLE;
222 return USBD_REQ_HANDLED;
224 /* Abort returns to dfuIDLE state. */
225 usbdfu_state = STATE_DFU_IDLE;
226 return USBD_REQ_HANDLED;
228 /* Upload not supported for now. */
229 return USBD_REQ_NOTSUPP;
230 case DFU_GETSTATUS: {
231 u32 bwPollTimeout = 0; /* 24-bit number of milliseconds */
232 (*buf)[0] = usbdfu_getstatus(usbd_dev, &bwPollTimeout);
233 (*buf)[1] = bwPollTimeout & 0xFF;
234 (*buf)[2] = (bwPollTimeout >> 8) & 0xFF;
235 (*buf)[3] = (bwPollTimeout >> 16) & 0xFF;
236 (*buf)[4] = usbdfu_state;
237 (*buf)[5] = 0; /* iString not used here */
239 *complete = usbdfu_getstatus_complete;
240 return USBD_REQ_HANDLED;
243 /* Return state with no state transition. */
244 *buf[0] = usbdfu_state;
246 return USBD_REQ_HANDLED;
249 return USBD_REQ_NOTSUPP;
252 static void usbdfu_set_config(usbd_device *usbd_dev, u16 wValue UNUSED)
254 usbd_register_control_callback(
256 USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
257 USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
258 usbdfu_control_request);
261 static void usbdfu_reset(void)
263 usbdfu_state = STATE_DFU_IDLE;
267 * This is a modified version of rcc_clock_setup_in_hsi_out_48mhz(),
268 * which properly turns off the PLL before setting its parameters.
270 static void my_rcc_clock_setup_in_hsi_out_48mhz(void)
272 /* Enable internal high-speed oscillator. */
274 rcc_wait_for_osc_ready(RCC_HSI);
276 /* Select HSI as SYSCLK source. */
277 rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
280 rcc_osc_off(RCC_PLL);
283 * Set prescalers for AHB, ADC, ABP1, ABP2.
284 * Do this before touching the PLL (TODO: why?).
286 rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV); /*Set.48MHz Max.72MHz */
287 rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV8); /*Set. 6MHz Max.14MHz */
288 rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_DIV2); /*Set.24MHz Max.36MHz */
289 rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV); /*Set.48MHz Max.72MHz */
290 rcc_set_usbpre(RCC_CFGR_USBPRE_PLL_CLK_NODIV); /*Set.48MHz Max.48MHz */
293 * Sysclk runs with 48MHz -> 1 waitstates.
298 flash_set_ws(FLASH_ACR_LATENCY_1WS);
301 * Set the PLL multiplication factor to 12.
302 * 8MHz (internal) * 12 (multiplier) / 2 (PLLSRC_HSI_CLK_DIV2) = 48MHz
304 rcc_set_pll_multiplication_factor(RCC_CFGR_PLLMUL_PLL_CLK_MUL12);
306 /* Select HSI/2 as PLL source. */
307 rcc_set_pll_source(RCC_CFGR_PLLSRC_HSI_CLK_DIV2);
309 /* Enable PLL oscillator and wait for it to stabilize. */
311 rcc_wait_for_osc_ready(RCC_PLL);
313 /* Select PLL as SYSCLK source. */
314 rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_PLLCLK);
316 /* Set the peripheral clock frequencies used */
317 rcc_ahb_frequency = 48000000;
318 rcc_apb1_frequency = 24000000;
319 rcc_apb2_frequency = 48000000;
322 static void clock_plain_hsi(void)
324 // Select HSI as SYSCLK source
325 rcc_set_sysclk_source(RCC_CFGR_SW_SYSCLKSEL_HSICLK);
328 rcc_osc_off(RCC_PLL);
330 // Set prescalers for AHB, ADC, ABP1, ABP2, USB to defaults
331 rcc_set_hpre(RCC_CFGR_HPRE_SYSCLK_NODIV);
332 rcc_set_adcpre(RCC_CFGR_ADCPRE_PCLK2_DIV2);
333 rcc_set_ppre1(RCC_CFGR_PPRE1_HCLK_NODIV);
334 rcc_set_ppre2(RCC_CFGR_PPRE2_HCLK_NODIV);
335 rcc_set_usbpre(RCC_CFGR_USBPRE_PLL_VCO_CLK_DIV3);
340 usbd_device *usbd_dev;
342 // Flash programming requires running on the internal oscillator
343 my_rcc_clock_setup_in_hsi_out_48mhz();
345 rcc_periph_clock_enable(RCC_GPIOA);
346 rcc_periph_clock_enable(RCC_GPIOC);
347 rcc_periph_clock_enable(RCC_USB);
349 rcc_periph_reset_pulse(RST_GPIOA);
350 rcc_periph_reset_pulse(RST_GPIOC);
351 rcc_periph_reset_pulse(RST_USB);
354 // Currently, only USART1 is supported
355 rcc_periph_clock_enable(RCC_USART1);
356 rcc_periph_reset_pulse(RST_USART1);
357 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9);
359 usart_set_baudrate(USART1, 115200);
360 usart_set_databits(USART1, 8);
361 usart_set_stopbits(USART1, USART_STOPBITS_1);
362 usart_set_mode(USART1, USART_MODE_TX);
363 usart_set_parity(USART1, USART_PARITY_NONE);
364 usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
366 usart_enable(USART1);
369 #ifdef DEBUG_LED_BLUEPILL
371 gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
375 // Systick: set to overflow in 1 ms, will use only the overflow flag, no interrupts
376 systick_set_frequency(1000, CPU_CLOCK_MHZ * 1000000);
378 systick_counter_enable();
380 desig_get_unique_id_as_dfu(usb_serial_number);
382 DEBUG("DFU: Entered boot-loader (SN %s)\n", usb_serial_number);
384 // Simulate USB disconnect
385 gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO11 | GPIO12);
386 gpio_clear(GPIOA, GPIO11 | GPIO12);
387 for (uint i=0; i<100; i++) {
388 while (!systick_get_countflag())
392 DEBUG("DFU: Ready\n");
395 usbd_dev = usbd_init(&st_usbfs_v1_usb_driver, &dev, &config, usb_strings, ARRAY_SIZE(usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer));
396 usbd_register_reset_callback(usbd_dev, usbdfu_reset);
397 usbd_register_set_config_callback(usbd_dev, usbdfu_set_config);
404 if (systick_get_countflag()) {
406 if (!(timeout & 0x3f))
411 volatile u32 *app = (volatile u32 *) BOOTLOADER_APP_START;
417 u32 sum = adhoc_checksum(BOOTLOADER_APP_START, len);
418 DEBUG("DFU: Checksum=%08x, len=%u\n", (uint) sum, len);
421 DEBUG("DFU: Starting application (sp=%08x, pc=%08x)\n", (uint) sp, (uint) pc);
422 if ((sp & 0x2ffe0000) != 0x20000000) {
423 DEBUG("DFU: Suspicious SP, refusing to start\n");
428 while (!usart_get_flag(DEBUG_USART, USART_FLAG_TC))
433 rcc_periph_clock_disable(RCC_GPIOA);
434 rcc_periph_clock_disable(RCC_GPIOC);
435 rcc_periph_clock_disable(RCC_USB);
436 rcc_periph_clock_disable(RCC_USART1);
438 rcc_periph_reset_pulse(RST_GPIOA);
439 rcc_periph_reset_pulse(RST_GPIOC);
440 rcc_periph_reset_pulse(RST_USB);
441 rcc_periph_reset_pulse(RST_USART1);
445 /* Set vector table base address. */
446 SCB_VTOR = BOOTLOADER_APP_START;
448 /* Initialize master stack pointer. */
449 asm volatile("msr msp, %0"::"g" (sp));
451 /* Jump to application. */
452 ((void (*)(void)) pc)();