2024-12-19 10:45 AM - edited 2024-12-19 10:47 AM
Hello all,
My aim is to utilize the User Push button (configured as an EXTI gpio) on Nucelo-F411RE board along with a software reset to enter the System Bootloader located @0x1FFF0000 (ref: AN2606).
With the software reset implementation, I face the bellow issues:
A.) The SFTRSTF flag is always set by the hardware while the user application is running. Shouldn't this flag be set only when the software reset line is executed? This should only occur when the User Push button is pressed.
B.) Because the SFTRSTF flag is set, the program always enters the check flag function (See Step 2.) and tries executing the bootloader code without even reaching the user application code (See Step 4.). The program always remains in this function an keeps on continuously executing the bootloader function and never goes to the user application.
C.) Sometimes, the program correctly enters the 'check flag' function (See Step 2.) upon pressing the user button, the function 'check flag' (See Step 2) clears the software reset flag bit and then executes the system bootloader, but then the program gets stuck in this loop and never exits the bootloader code.
D.) The VTOR is never loaded with the System Bootloader address and is always 0x00000000 while testing software reset.
NOTE:
SFTRSTF flag in the RCC_CSR register is set by the Hardware upon software reset. This flag can be used to check if the software reset condition is met and must be cleared by setting the RMVF flag in the RCC_CSR register.
Implementation Steps for Software RESET:
Step 1.) User Push button is configured as an EXTI gpio, so the callback function would get called upon pressing this button. Once pressed, I perform the Software Reset using the HAL_API.
<bootloader.c>
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == User_PB_Pin)
{
//Perform software reset
HAL_NVIC_SystemReset();
}
}
Step 2.) Upon Software reset, the board initiates its execution by initializing everything. So, in the register (RCC_CSR), I check for software reset flag condition(SFTRSTF) which is automatically set by the hardware when a software reset occurs. If SFTRSTF is set, I clear this flag by setting the RMVF (Remove Flag) bit from the same register (RCC_CSR) and implement the call the function "jumpTo_STBootloader()'.
<main.c>
int main (void) {
// HAL initialization here
// CODE HERE
if(__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST))
{
//Clr reset flag
RCC->CSR |= RCC_CSR_RMVF;
jumpTo_STBootloader();
}
//CODE HERE
while (1) {
}
return 0;
}
Step 3.) The function 'jumpTo_STBootloader' handles the jump from the user application to the system memory bootloader. This function is implemented as below:
<bootloader.c>
void jumpTo_STBootloader()
{
void(*SysMemBootJump)(void);
volatile uint32_t addr = 0x01FFF0000; // System memory address
__disable_irq();
// Diaable RCC peripherals
HAL_RCC_DeInit();
HAL_DeInit();
// Re-map memory address
SYSCFG->MEMRMP = 0x01;
// Reset SYSTICK
SysTick->CTRL = 0;
SysTick->VAL = 0;
SysTick->LOAD = 0;
SysMemBootJump = (void (*) (void))(*((uint32_t *)(addr+4)));
__set_MSP(*(uint32_t *)addr);
SysMemBootJump();
//should never return here
while(1);
}
Step 4.) User application is Toggling led in the super loop as below,
<main.c>
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
TOGG_LED();
HAL_Delay(250);
}
/* USER CODE END 3 */
Previous Implementation using Hardware RESET button:
I had previously tested using a hardware reset button and I was able to access the System Bootloader without any issues. While testing the hardware reset, instead of using the interrupt callback function for the User Push button, I was simply using an if condition to check if the button was pressed and execute the jumpTo-STBootloader() function.
The way it was achieved was, I would press the hardware RESET button while pressing the User Push button, so that the moment my Nucleo board would reset, the first thing that it would check was the user push button is pressed and immediately it would execute the bootloader code. Also the VTOR register would correctly hold the System Bootloader Address (0x1FFF0000).
But with the software reset implementation, I am facing issues which I am not able to understand. I would appreciate any guidance on this. Also is my implementation correct?
Thank you
2024-12-19 11:14 AM
>>Also is my implementation correct?
You're telling us it doesn't work the way you want.
Honestly, you're making this all far too complex. Sorry TL;DR; I have a short attention span
Perhaps set a magic value in RAM, and check it immediately in Reset_Handler, or top-of-main, and don't be doing a lot of HAL initialization.
Perhaps check the button status as you enter main(), so that's an immediate path. You can't do that directly in an IRQ Handler/Callback as you can't unwind the MCU/NVIC state
The ROM/CPU doesn't start with the system's interrupts disabled, it doesn't have any of the peripheral/NVIC ones started. Don't rely on variables placed on the stack frame when you're destroying their frame of reference.
Can't say I've micro-analyzed what RCC->CSR is doing/flaging. I don't think you can rely on specific singular flags to understand how the MCU started. Better to have magic values in RAM that you subsequently invalidate.
The MCU clears SCB->VTOR and the mapping of ROM/RAM/FLASH at zero determines what's jumped too. Subsequenty SystemInit() code used by ST sets to basis it thinks it should be using.
Software resets can fail if you actively drive the NRST pin high externally.
2024-12-19 11:45 AM - edited 2024-12-19 11:46 AM
Shouldn't I be storing the magic number in the Flash instead of RAM? RAM would erase the magic number upon a software reset correct.
I must rather use the Main Flash Memory.
2024-12-19 11:48 AM
2024-12-19 11:52 AM
Thanks for this link, but I had previously tried it and it didn't worked for me in my situation. This link is helpful if I am using a hardware reset button. But things change when it comes to implementing software reset.
2024-12-19 11:58 AM - edited 2024-12-19 12:00 PM
No when you read exist way to store marker in memory instead flag reset, or as i write here instead nvic reset use IWDG or WWDG when isnt used in application. This set marker state flag as you try read my post in KB or bpm posts
And no RAM isnt erased by reset, but in init asm code, except areas marked noinit...