2021-03-02 06:58 AM
The code below shows my current attempt to implement a jump to the bootloader:
#define ApplicationAddress 0x1FFFC400
void JumpBootloader(void)
{
typedef void (*pFunction)(void); // defines function pointer for bootloader jump
/* Set System memory address plus 4 bytes */
uint32_t JumpAddress = *(__IO uint32_t*) (ApplicationAddress + 4);
pFunction Jump_To_Boot = (pFunction) JumpAddress;
// /* Set main stack pointer
// * This must be done last otherwise all other variables might get mangled! */
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Boot();
}
When this function is called with the BOOT pin pulled high, the microcontroller correctly restarts into bootloader mode, although admittedly after a slight delay of about a second (Windows connect and disconnect sounds can be heard).
When called with the BOOT pin floating/pulled low (note I am using this pin to drive an LED during normal operation), the device disconnects after a small delay as before but then fails to connect, giving the error 'Device Descriptor Request Failed'.
I have looked around on other threads/forums and tried various different methods such as de-initialising all peripherals prior to calling the above function, remapping the system memory to 0x0 (__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();) with varying changes in behaviour. For example, the code below simply jumps back to the user application after being called:
void JumpBootloader(void)
{
typedef void (*pFunction)(void);
pFunction JumpToApplication;
uint32_t JumpAddress = 0x1FFFC400;
Device_DeInit();
HAL_RCC_DeInit();
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
JumpToApplication = (void (*)(void)) (*((uint32_t *)(JumpAddress + 4)));
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) JumpAddress);
JumpToApplication();
}
void Device_DeInit(void)
{
USBD_Stop(&hUsbDeviceFS);
USBD_DeInit(&hUsbDeviceFS);
HAL_TIM_Base_Stop_IT(&htim16);
HAL_SPI_DeInit(&hspi1);
HAL_DMA_DeInit(&hdma_spi1_tx);
HAL_DMA_DeInit(&hdma_spi1_rx);
HAL_TIM_Base_MspDeInit(&htim16);
HAL_GPIO_DeInit(LED_USB_GPIO_Port, LED_USB_Pin);
HAL_GPIO_DeInit(LED_AXIOM_GPIO_Port, LED_AXIOM_Pin);
HAL_DeInit();
}
Am I missing a vital point here? Are there any pre-requisites I have not met?
If it is of any concern, I am using USB DFU.
Best regards,
James
Solved! Go to Solution.
2021-03-02 08:05 AM
*************************************************************************
EDIT: Be careful when implementing this! Setting BOOT_SEL = 0 disables the physical boot pin from working. This has some pretty serious repercussions - if a firmware upgrade fails then there is no way to get the device into bootloader mode (as the code to enter bootloader doesn't exist). To recover the device you must connect and reprogram using the ST Link debugger.
*************************************************************************
For future reference/anyone searching for the same issue:
In the function that gets called when requesting the bootloader:
void StartBootloader(void)
{
/* The STM32F042 has:
* 6k SRAM in address: 0x2000 0000 - 0x2000 17FF
*/
*((unsigned long *)0x200017F0) = 0xDEADBEEF;
// Reset the processor
NVIC_SystemReset();
/* We then do a check in SystemInit() at startup to see if this 'magic number' has been set */
}
The we do a check at start-up in SystemInit():
void SystemInit(void)
{
/* Check if we should go into bootloader mode.
*
* Set the main stack pointer __set_MSP() to its default value.
*
* Note that 0x1FFFC400 is "System Memory" start address for STM32F042
*/
if( *((unsigned long *)0x200017F0) == 0xDEADBEEF )
{
*((unsigned long *)0x200017F0) = 0xCAFEFEED; // Reset our magic trigger
__set_MSP(0x20001800); // set main stack pointer to start of stack
// 0x1fffC400 is "System Memory" start address for STM32F042
SysMemBootJump = (void (*)(void)) (*((uint32_t *) 0x1fffC404)); // Point the PC to the System Memory reset vector (+4)
SysMemBootJump();
}
...
//Normal SystemInit code here
...
}
For this to work correctly the BOOTMODE configuration register must be the following:
NOTE: The register values and boot configuration is specific to the STM32F042. This should work on other chips but you will need to find the correct stack values, end of RAM addresses etc.
2021-03-02 07:01 AM
A mentioned many time before, best is to have some boot switch very early in the application code before any initialization is done and setup and jump to the bootloader is some magic is seen
2021-03-02 07:05 AM
Hi Uwe, thanks for answering so swiftly.
I did think that might be a better option rather than trying to messily pull myself out mid application. Just so I'm 100% sure I'm understanding correctly:
Would that sort of logic succeed?
2021-03-02 07:48 AM
I use some magic word in RAM that the boot process does not initialize. If you have the swicth before ram initialization you can use almost any ram location.
2021-03-02 08:05 AM
*************************************************************************
EDIT: Be careful when implementing this! Setting BOOT_SEL = 0 disables the physical boot pin from working. This has some pretty serious repercussions - if a firmware upgrade fails then there is no way to get the device into bootloader mode (as the code to enter bootloader doesn't exist). To recover the device you must connect and reprogram using the ST Link debugger.
*************************************************************************
For future reference/anyone searching for the same issue:
In the function that gets called when requesting the bootloader:
void StartBootloader(void)
{
/* The STM32F042 has:
* 6k SRAM in address: 0x2000 0000 - 0x2000 17FF
*/
*((unsigned long *)0x200017F0) = 0xDEADBEEF;
// Reset the processor
NVIC_SystemReset();
/* We then do a check in SystemInit() at startup to see if this 'magic number' has been set */
}
The we do a check at start-up in SystemInit():
void SystemInit(void)
{
/* Check if we should go into bootloader mode.
*
* Set the main stack pointer __set_MSP() to its default value.
*
* Note that 0x1FFFC400 is "System Memory" start address for STM32F042
*/
if( *((unsigned long *)0x200017F0) == 0xDEADBEEF )
{
*((unsigned long *)0x200017F0) = 0xCAFEFEED; // Reset our magic trigger
__set_MSP(0x20001800); // set main stack pointer to start of stack
// 0x1fffC400 is "System Memory" start address for STM32F042
SysMemBootJump = (void (*)(void)) (*((uint32_t *) 0x1fffC404)); // Point the PC to the System Memory reset vector (+4)
SysMemBootJump();
}
...
//Normal SystemInit code here
...
}
For this to work correctly the BOOTMODE configuration register must be the following:
NOTE: The register values and boot configuration is specific to the STM32F042. This should work on other chips but you will need to find the correct stack values, end of RAM addresses etc.
2021-03-02 08:05 AM
Thanks very much for your help Uwe, all works as intended now!