Skip to content

Instantly share code, notes, and snippets.

@t-moe
Created February 25, 2019 14:36
Show Gist options
  • Save t-moe/bebf36d32685ecc42e5fa340b84bfa6f to your computer and use it in GitHub Desktop.
Save t-moe/bebf36d32685ecc42e5fa340b84bfa6f to your computer and use it in GitHub Desktop.
Jump to DFU bootloader from a stm32f042c6 application that uses usb cdc
#include "stm32f0xx.h"
#include "stm32f0xx_hal_flash.h"
#include "usb_device.h"
// Idea: We want to be able to jump to the bootloader from application
// Problems:
// 1. Once usb is initialized in application mode you cannot reinitialize it from bootloader. Thats why we do a system reset as first step
// 2. The bootloader will immediately jump back to application unless the first page of the flash has been cleared. That's why we erase the first page of the flash before jumping
// 3. Clock and other stuff must be reset before jumping into bootloader. We copied that from the example. See JumpToBootloader code below
#define MAGIC_ADDR 0x200017FC //top of SRAM. Make sure that you modify the linker file so that the top of stack starts after it.
#define MAGIC_VALUE 0xDEADBEEF
//Call this function from your application when you want to jump to the bootloader
void PrepareJumpToBootloader(void) {
usb_deinit(); //deinit usb (optional? maybe done by soft reset as well?)
//Do System Reset
uint32_t* magicAddr = (uint32_t*)MAGIC_ADDR;
*magicAddr = MAGIC_VALUE;
NVIC_SystemReset();
}
static void JumpToBootloader();
void CheckBootloaderJump() {
//Check if we did a system reset and want to jump into bootloader
uint32_t* magicAddr = (uint32_t*)MAGIC_ADDR;
if(*magicAddr == MAGIC_VALUE) {
JumpToBootloader();
while(1);
}
}
//From: https://stm32f4-discovery.net/2017/04/tutorial-jump-system-memory-software-stm32/
void JumpToBootloader(void) {
void (*SysMemBootJump)(void);
/**
* Step: Set system memory address.
*
* For STM32F429, system memory is on 0x1FFF 0000
* For other families, check AN2606 document table 110 with descriptions of memory addresses
* https://www.st.com/content/ccc/resource/technical/document/application_note/b9/9b/16/3a/12/1e/40/0c/CD00167594.pdf/files/CD00167594.pdf/jcr:content/translations/en.CD00167594.pdf
*/
volatile uint32_t addr = 0x1FFFC400; //AN2606 Page 38 Table 12
/**
* Step: Disable RCC, set it to default (after reset) settings
* Internal clock, no PLL, etc.
*/
#if defined(USE_HAL_DRIVER)
HAL_RCC_DeInit();
#endif /* defined(USE_HAL_DRIVER) */
#if defined(USE_STDPERIPH_DRIVER)
RCC_DeInit();
#endif /* defined(USE_STDPERIPH_DRIVER) */
/**
* Step: Disable systick timer and reset it to default values
*/
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
/**
* Step: Erase first user flash page because unless it's empty the bootloader will directly jump back to user app again
*/
FLASH_EraseInitTypeDef EraseInitStruct;
uint32_t SECTORError = 0;;
HAL_FLASH_Unlock(); //Unlock the Flash to enable the flash control register access
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.PageAddress = 0x08000000; // start address
EraseInitStruct.NbPages = 1;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK)
{
SECTORError = SECTORError + 1;
}
/**
* Step: Remap system memory to address 0x0000 0000 in address space
* For each family registers may be different.
* Check reference manual for each family.
*
* For STM32F4xx, MEMRMP register in SYSCFG is used (bits[1:0])
* For STM32F0xx, CFGR1 register in SYSCFG is used (bits[1:0])
* For others, check family reference manual
*/
//Remap by hand... {
#if defined(STM32F4)
SYSCFG->MEMRMP = 0x01;
#endif
#if defined(STM32F0)
SYSCFG->CFGR1 = 0x01;
#endif
//} ...or if you use HAL drivers
//__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); //Call HAL macro to do this for you
/**
* Step: Set jump memory location for system memory
* Use address with 4 bytes offset which specifies jump location where program starts
*/
SysMemBootJump = (void (*)(void)) (*((uint32_t *)(addr + 4)));
/**
* Step: Set main stack pointer.
* This step must be done last otherwise local variables in this function
* don't have proper value since stack pointer is located on different position
*
* Set direct address location which specifies stack pointer in SRAM location
*/
__set_MSP(*(uint32_t *)addr);
/**
* Step: Actually call our function to jump to set location
* This will start system memory execution
*/
SysMemBootJump();
/**
* Step: Connect USB<->UART converter to dedicated USART pins and test
* and test with bootloader works with STM32 Flash Loader Demonstrator software
*/
}
void CheckBootloaderJump();
void PrepareJumpToBootloader();
int main(void)
{
HAL_Init();
CheckBootloaderJump();
while(1) {
// <-- your application --->
if(something) {
PrepareJumpToBootloader();
}
}
}
@ck989
Copy link

ck989 commented Sep 24, 2021

I have a small question line 48 of JumpToBootloader() function. The system memory address of STM32F429 is 0x1FFF0000. I'm sure why did you add extra offset of c400? I couldn't find anything related to this on AN2606 doc. Could you explain this? I'm trying to replicate your code on STM32L0xx family.

@20jmorrison
Copy link

I have a small question line 48 of JumpToBootloader() function. The system memory address of STM32F429 is 0x1FFF0000. I'm sure why did you add extra offset of c400? I couldn't find anything related to this on AN2606 doc. Could you explain this? I'm trying to replicate your code on STM32L0xx family.

I'm trying to replicate this on an STM32F051. Did you ever figure out why they added the extra offset of c400?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment