2019-01-19 05:28 PM
I am working on a project with STM32L432 and trying to get a clean (without necessity to de-init peripherals and disable peripheral interrupts) jump to application from a bootloader and back.
The widely described method to do so is as follows (for a booloader):
If it contains the key value, erase it and execute standard jump to the application:
typedef void (*pFunction)(void);
pFunction Jump_To_Application;
void Application_jump(void)
{
uint32_t JumpAddress;
/* Get the application stack pointer (First entry in the application vector table) */
JumpAddress = (uint32_t) *((__IO uint32_t*)APP_START_ADDRESS);
/* Get the application entry point (Second entry in the application vector table) */
Jump_To_Application = (pFunction) *(__IO uint32_t*) (APP_START_ADDRESS + 4);
/* Reconfigure vector table offset register to match the application location */
SCB->VTOR = JumpAddress;
/* Set the application stack pointer */
__set_MSP(JumpAddress);
/* Start the application */
Jump_To_Application();
}
My question is:
Is it possible to force the system to start at the application address after reset.
I tried it, but system always starts at a base address. Maybe I've done something wrong.
It it's possible, then how?
And in this case would using only NVIV_SystemReset() call provide a clean jump?
BTW, if system always starts at a base address, would using only NVIC_SystemReset() in application provide a clean jump to a bootloader?
Thank you.
2019-01-20 07:59 AM
First a few words about Your previous combined initialization idea described there:
It can be done, but it's a bad solution. Not only it makes application more dependent on bootloader, but it also makes bootloader dependent on application, which is unacceptable. Also it makes code on both sides more complex and that is undesirable.
The same principles apply to Your current question about system start address. You don't want it to start at application address because that's not reliable. If bootloader is interrupted while doing application update, device could be bricked, because it will not be able to start neither application, nor bootloader. So You want a system to always start at bootloader address first.
I'll share my reliable and simple solution. The idea is to mimic system reset conditions for application as close as possible. This is the beginning of bootloader's reset handler before usual initialization:
Reset_Handler:
BL Boot_GetApplicationAddress
CBZ R0, StartBootloader
LDR R1, =0xE000ED00 // SCB
STR R0, [R1, #8] // VTOR
LDR SP, [R0, #0] // Stack pointer
LDR R0, [R0, #4] // Reset handler
DSB // Ensure the VTOR and SP operations are complete
ISB // Flush the pipeline because of SP change
BX R0 // Start the application
StartBootloader:
void* Boot_GetApplicationAddress(void) makes a decision whether to start application or bootloader and returns application base address or NULL respectively. It does the following in this order and uses early returns from steps if bootloader must be started:
Starting application from bootloader:
Starting bootloader from application:
This is the cleanest and simplest reliable solution I've come up with. Of course, any additional ideas and comments are welcome!
2019-01-20 08:31 AM
>>SCB->VTOR = JumpAddress;
NO, SCB->VTOR = APP_START_ADDRESS; // The BASE of the table
2019-01-20 03:58 PM
Piranha & Clive,
Thank you so much for your help.
I still need to do a few tweaks (and may ask some questions :) ), but it seems to be working!
2020-02-26 01:33 AM
Hi,
I want to implement a bootloader but facing some issue in jump process. I am using STM32F407 controller. My question is :
1.NVIC_SystemReset() should be used after deinitializing the peripheral. Is it correct ?
2.Also should we set the MSP or not.
I am just setting the vector offset
SCB->VTOR = SECTOR_START_ADDRESS;
Thanks
2020-02-26 01:40 AM
> 1.NVIC_SystemReset() should be used after deinitializing the peripheral. Is it correct ?
Not necessarily.
A reset puts all internal & peripheral registers back to the default value, as described in the reference manual.
In your application, you should never assume any previous initialization.
2020-03-07 12:33 AM
@Community member, you are completely missing the point here, because you haven't read my comment describing a much better solution in which:
2022-12-30 07:14 AM
I'm new to this specific area of embedded programming and am currently just using option bytes to switch between the two. I'm working with the L552ZET6Q and am wondering if there were any additional resources you knew of to help me understand this better and implement it on my setup
2022-12-30 07:55 AM
The Option Bytes are like FLASH, they have a finite life, and also issues if the power fails mid-write. In newer model STM32 the values are latched internally at power-up, not normal resets. This in part has to do with security and attack vectors.
Controlling boot via RAM constants to different loaders, apps, or erasing the app, is perhaps a more consistent method.
RAM on the L5 works much like any other STM32.
Boot Loaders, and Loaders in general are covered in numerous books and papers.
2022-12-30 08:09 AM
Hence why I'm trying to understand how this solution works and what needs to change to use it on the L5.