Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Bootloader "jump-to-address" assembly code

The following code is from "Boot_Loader\nrf_bootloader_app_start_final.c":

__STATIC_INLINE void jump_to_addr(uint32_t new_msp, uint32_t new_lr, uint32_t addr)
{
 __ASM volatile ("MSR MSP, %[arg]" : : [arg] "r" (new_msp));
 __ASM volatile ("MOV LR, %[arg]" : : [arg] "r" (new_lr) : "lr");
 __ASM volatile ("BX %[arg]" : : [arg] "r" (addr));
}

While I was trying to do a serial DFU operation on nRF52832, the above code does not work (in my case) because it loads 3 registers from the stack. It turned out that once the MSP register is loaded with the new value, the SP register, which is supposed to be used to get the next 2 values, gets updated with the new MSP value (i.e. MSP and SP are linked together) and the retrieved values for the second and third instructions end up getting garbage data. I solved it by loading the 3 values from the stack into 3 general purpose registers and then use them to deliver their values to the intended destinations.

__STATIC_INLINE void jump_to_addr(uint32_t new_msp, uint32_t new_lr, uint32_t addr)
{
__ASM volatile ("MOV R0, %[arg]" : : [arg] "r" (new_msp));
__ASM volatile ("MOV R1, %[arg]" : : [arg] "r" (new_lr));
__ASM volatile ("MOV R2, %[arg]" : : [arg] "r" (addr));
__ASM volatile ("MSR MSP, R0");
__ASM volatile ("MOV LR, R1" : : : "lr");
__ASM volatile ("BX R2");
/}

The original code works in certain cases, depending on the how the compiler optimizes the rest of the project code. It should be changed for a more robust operation. Thanks.

Related