From 1ea8b44b2bf69d1c4435114c2579fc5e009aa877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Sat, 21 Dec 2019 19:48:00 +0100 Subject: [PATCH] bootloader: use magic value in RAM instead of peripheral --- application.ld | 7 +++++-- bootloader.c | 9 +++++++-- bootloader.ld | 5 ++++- global.h | 5 +++++ lib/usb_cdcacm.c | 8 ++++++-- 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/application.ld b/application.ld index f24486f..b6a4961 100644 --- a/application.ld +++ b/application.ld @@ -1,13 +1,14 @@ /* linker script for application running on STM32F103x8 micro-controller * the STM32F103xB has 128 KB of flash starting at 0x0800 0000, and 20 KB of RAM starting at 0x2000 0000 * the USB DFU bootloader will take the first 8 KB of flash, followed by the application + * the first 4 bytes of the RAM is reserved for the DFU magic word (DFU! to start DFU bootloader) */ /* Define memory regions. */ MEMORY { - rom (rx) : ORIGIN = 0x08000000 + 8K, LENGTH = 128K-8K - ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K + rom (rx) : ORIGIN = 0x08000000 + 8K, LENGTH = 64K - 8K + ram (rwx) : ORIGIN = 0x20000000 + 4, LENGTH = 20K - 4 } PROVIDE(__application_beginning = ORIGIN(rom)); /* only provide application_end and/or flash_end if you want to force a flash size @@ -21,5 +22,7 @@ PROVIDE(__flash_end = 0); PROVIDE(__application_end = ORIGIN(rom) + LENGTH(rom)); PROVIDE(__flash_end = ORIGIN(rom) + LENGTH(rom)); +PROVIDE(__dfu_magic = ORIGIN(ram) - 4); + /* include rest of the definitions for the STM32F1 family */ INCLUDE libopencm3_stm32f1.ld diff --git a/bootloader.c b/bootloader.c index 932e41c..a75944a 100644 --- a/bootloader.c +++ b/bootloader.c @@ -36,9 +36,14 @@ void main(void) { // check of DFU mode is forced bool dfu_force = false; // to remember if DFU mode is forced - // check if a soft boot has been used - if (0 == (RCC_CSR & 0xfc000000)) { // no reset flag present -> this was a soft reset using scb_reset_core() after clearing the flags using RCC_CSR_RMVF, very probably to start the DFU mode + // check if DFU magic DFU! has been written to RAM (e.g. by application to indicate we want to start the DFU bootloader) + if ('D' == __dfu_magic[0] && 'F' == __dfu_magic[1] && 'U' == __dfu_magic[2] && '!' == __dfu_magic[3]) { // verify if the DFU magic is set dfu_force = true; + // clear DFU magic + __dfu_magic[0] = 0; + __dfu_magic[1] = 0; + __dfu_magic[2] = 0; + __dfu_magic[3] = 0; } else { // check if the force DFU mode input is set // disable SWJ pin to use as GPIO #if (GPIO(B) == GPIO(DFU_FORCE_PORT)) && (GPIO(4) == GPIO(DFU_FORCE_PIN)) diff --git a/bootloader.ld b/bootloader.ld index e27f99d..7aef15e 100644 --- a/bootloader.ld +++ b/bootloader.ld @@ -1,13 +1,14 @@ /* linker script for application running on STM32F103x8 micro-controller * the STM32F103xB has 128 KB of flash starting at 0x0800 0000, and 20 KB of RAM starting at 0x2000 0000 * the USB DFU bootloader will take the first 8 KB of flash, followed by the application + * the first 4 bytes of the RAM is reserved for the DFU magic word (DFU! to start DFU bootloader) */ /* Define memory regions. */ MEMORY { rom (rx) : ORIGIN = 0x08000000, LENGTH = 8K - ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K + ram (rwx) : ORIGIN = 0x20000000 + 4, LENGTH = 20K - 4 } PROVIDE(__application_beginning = ORIGIN(rom) + LENGTH(rom)); /* only provide application_end and/or flash_end if you want to force a flash size @@ -21,5 +22,7 @@ PROVIDE(__flash_end = 0); PROVIDE(__application_end = __application_beginning + 128K - 8K); PROVIDE(__flash_end = __application_beginning + 128K - 8K); +PROVIDE(__dfu_magic = ORIGIN(ram) - 4); + /* include rest of the definitions for the STM32F1 family */ INCLUDE libopencm3_stm32f1.ld diff --git a/global.h b/global.h index e4cd72a..2f8eb73 100644 --- a/global.h +++ b/global.h @@ -701,6 +701,11 @@ extern char __application_end; extern char __flash_end; /** flag set when board user button has been pressed/released */ extern volatile bool button_flag; +/** symbol for the DFU magic word + * @note this symbol will be provided by the linker script + */ +extern char __dfu_magic[4]; + /** flag set when user input is available */ extern volatile bool user_input_available; diff --git a/lib/usb_cdcacm.c b/lib/usb_cdcacm.c index a794c94..659874e 100644 --- a/lib/usb_cdcacm.c +++ b/lib/usb_cdcacm.c @@ -280,9 +280,13 @@ static void usb_dfu_detach(usbd_device *usbd_dev, struct usb_setup_data *req) { (void)usbd_dev; // variable not used (void)req; // variable not used - RCC_CSR |= RCC_CSR_RMVF; // clear reset flag for the bootloader to detect the core reset usb_disconnect(); // USB detach (disconnect to force re-enumeration) - scb_reset_core(); // reset device (only the core, to the peripheral stay configured) + // set DFU magic + __dfu_magic[0] = 'D'; + __dfu_magic[1] = 'F'; + __dfu_magic[2] = 'U'; + __dfu_magic[3] = '!'; + scb_reset_system(); // reset system (core and peripherals) while (true); // wait for the reset to happen }