2020-10-15 02:07 AM
Hi there!
I have a weird problem, where I'm a bit lost, probably also due to my limited knowledge of assembly. So I am trying to write a function (which is called using a very secret pattern) which sets a magic number and soft resets the microcontroller. On startup, a comparison to the magic number is made, and it either jumps into the DFU bootloader, or continues regular startup.
But somehow even when I press the physical reset switch, it goes into the bootloader, although it shouldn't. And I'd like to ask for your advice why.
Here's the reset handler. Line 3 to line 8 is what I have added. It loads the bootloader_flag address, reads out bootloader_flag, loads magic number 0x00C0FFEE, and clears bootloader_flag. Then it compares the dereferenced bootloader_flag in r2 to the magic number in r1 and decides whether to jump or to continue.
Reset_Handler:
/*Check for bootloader*/
ldr r0, =_bootloader_flag // Load bootloader flag address
ldr r1, =0x00C0FFEE // Load magic number
ldr r2, [r0, #0] // Dereference flag
str r0, [r0, #0] // Clear
cmp r2, r1 // Check flag
beq Reboot_Loader // Flag detected? Go to loader
ldr sp, =_estack /* Set stack pointer */
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
Here's the code of Reboot_Loader:
Reboot_Loader:
ldr r0, =0x1FFF0000 // Load bootloader address
ldr r1, [r0, #0] // Load default stack pointer
mov sp, r1 // Set stack pointer to default
ldr r0, [r0, #4] // Load bootloader +4
bx r0 // Go to bootloader +4
And finally the code piece that triggers the dirty reset:
volatile uint32_t _bootloader_flag = 0x00000001;
/**
* @brief Write dirty bit and go into DFU mode bootloader
* @param bootloader_status
*/
void activate_bootloader(uint32_t bootloader_status) {
if(bootloader_status == 1) {
// Write DFU message
NVIC_DisableIRQ(TIM1_UP_TIM16_IRQn);
WriteSomeMessageToNotifyUser("");
NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);
// Disable interrupts
__disable_irq();
// http://blog.fahhem.com/2017/12/jump-to-emb-bootloader/
_bootloader_flag = 0x00C0FFEE; // Magic number flag set
// See you latte
NVIC_SystemReset();
while(1);
}
}
Thank you for your help.
I'm using STM32CubeMX, everything HAL, SystemWorkbench, macOS Catalina and the microcontroller is an STM32L412KB.
Stay safe and cheers.
2020-10-15 05:08 AM
The state of the boot pins, and if the flash looks like it has valid SP/PC values, will impact if the loader will run or jump back into flash.
2020-10-15 05:22 AM
Thanks for your reply. Could you please elaborate on what you mean by
2020-10-15 05:22 AM
+1
Toggle some pin to see if it went to bootloader through your code or directly due to some of the bootloader entry mechanisms Clive said above.
Note, that for AN2606/pattern6 (as is L412), the "flash empty" detection in fact only checks the very first word of FLASH against 0xFFFFFFFF; and also that once this is detected true, it won't go away using "ordinary" reset even if the FLASH is reprogrammed, you need either poweron reset or forced reloading of the option bytes.
JW
2020-10-15 06:59 AM
Thanks. I've found the (pretty obvious) mistake I have made.
I'm using BOOT0 as GPIO and the Option Bits are set so that nSWBOOT0 == 1, which means that reset would take value from the BOOT0 pin.
Now that nSWBOOT0 == 0, the device resets and DFUs just as expected.
2020-10-15 07:35 AM
Sorry I tend to be a bit terse, often using a phone, and not looking to write an essay.
Yes, the BOOTx pins or their proxy, which are changing the mapping of the zero page memory, ie ROM, FLASH, RAM, and is the default vector table when SCB->VTOR == 0 at reset.
I haven't pulled the specific loader apart here, but the typical approach is to check the SP (word at 0) is not 0xFFFFFFFF, and ideally in the 0x200xxxxx type range representing RAM, 32-bit aligned, and the PC (word at 4) is not 0xFFFFFFFF, and is at 0x080xxxxxx range and ODD, indicating a Thumb subroutine within the FLASH.