cancel
Showing results for 
Search instead for 
Did you mean: 

A problem with STM32F407 bootloader (FreeRTOS and baremetal HAL)

Disconnected
Visitor

 

Hey there!
I have a bootloader, which partially works with FreeRTOS, but I struggle to get it working on bare metal HAL.
 
My bootloader also contains a FreeRTOS, with TIM5 as a Timebase Source.
The clock library is LL. The RCC is configured to use an internal HSI.
Then main app should switch it to use external HSE.
The start of the bootloader flash is 0x8000000, and the user app should be 0x8008000.
I also have two 1KB regions in main app for storing timestamp and crc, which shouldn't affect anything.
 
Everything is done via CubeIDE 1.16.0 and F4 BSP 1.28.0.
The board is STM32F4XX_M with STM32F407VET6 onboard.I tried a lot of variants for JumpToApp, and it seems like I still miss something either in this function, or in the beginning of the main app.
 
1. So right now JumpToApp in bootloader looks like this:

 

 

 

void Flash_JumpToApp(uint32_t appAddr)
{
    uint32_t appJumpAddress;
    void (*GoToApp)(void);

    // Disable RCC
    LL_RCC_DeInit();
    HAL_DeInit();

    // Disable systick timer and reset it to default values
    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL = 0;

    // Disable all interrupts
    __disable_irq();

	/* Clear Interrupt Enable Register & Interrupt Pending Register */
	for (int i=0;i<7;i++)
	{
		NVIC->ICER[i]=0xFFFFFFFF;
		NVIC->ICPR[i]=0xFFFFFFFF;
	}

	// Set addresses for Jump
    SCB->VTOR = appAddr;
    __set_MSP(*((volatile uint32_t*) appAddr));
    __set_PSP(*((volatile uint32_t*) appAddr));

    appJumpAddress = *((volatile uint32_t*)(appAddr + 4));
    GoToApp = (void (*)(void))appJumpAddress;
    GoToApp();
}

 

 

 

Then in the main app, FreeRTOS image has the following code.

 

 

 

    SCB->VTOR = FLASH_FW_START_ADDR;
    __set_MSP(*((volatile uint32_t*) FLASH_FW_START_ADDR));
    __set_PSP(*((volatile uint32_t*) FLASH_FW_START_ADDR));

 

 

 

 

It works fine with TIM5 as timebase, and the LED is blinking inside the Thread after FreeRTOS init.
But if I try to add __enable_irq();  which should be the correct thing to do, it will not work 

The fun thing, that all interrupts I used in previous project seems to work, so I guess part of them just enabled somewhere else, which still bothers me.
If I try to add infinite led loop before the FreeRTOS Init for check, it will be stucked inside the HAL_Delay().
 
2. Then I wanted to have a HAL example without a FreeRTOS.
I decided to keep the TIM5 as the timebase, to keep the same settings everywhere.
And it never worked from JumpToApp, but I'm able to catch the Debug, and see what's happening
 
2.1. If I keep the same code at start

 

 

 

    SCB->VTOR = FLASH_FW_START_ADDR;
    __set_MSP(*((volatile uint32_t*) FLASH_FW_START_ADDR));
    __set_PSP(*((volatile uint32_t*) FLASH_FW_START_ADDR));

 

 

 

 

It will pass all the Init code, but will be stucked in HAL_Delay().
I suppose the reason for that, is that some of the IRQ were not enabled after the JumpToApp.
2.2. But if I add

 

 

 

    SCB->VTOR = FLASH_FW_START_ADDR;
    __set_MSP(*((volatile uint32_t*) FLASH_FW_START_ADDR));
    __set_PSP(*((volatile uint32_t*) FLASH_FW_START_ADDR));
    __enable_irq();

 

 

 

 

I will have a hardfault after the HAL_InitTick inside the HAL_Init , which seems to be somehow caused or related to NVIC_SetPriority .
 
So my questions are:
1. What else could I miss in JumpToApp , and what's wrong for the F4 here? Not sure, that it's correct to zero all ICER and ICPR regs. Most of the examples miss the HAL_Deinit too. Maybe the SysTick disable code is incorrect. I saw some other variants.
2. Why the use of the __enable_irq could lead to incorrect behavior in the main app?
3. How to further debug the issue with NVIC_SetPriority ?
4. I also had a variant, where I used a default SysTick as a timebase for bootloader, but then the app switch it to TIM5. It works with FreeRTOS, but I didn't check it on bare HAL. I guess that it's better not to use it with FreeRTOS, and I decided not to waste any more time on that.
 
If someone is willing to take a look on complete projects, I could share the full code on GitHub.
My final goal is to publish it as an open-source example later, for anyone to use it as a starting point. The complete project has an ESP32-S3 example to update different STM32 boards, and CI pipeline to build all images with GitHub Actions. Then it could be used to update a lot of boards with OTA updates.
2 REPLIES 2
Disconnected
Visitor

I've uploaded the current code to this repo, feel free to clone and test it 

Disconnected
Visitor

So I've decided to make a bootloader version without the FreeRTOS, because I started to recall that I had a simillar issue with STM32G0 a few years ago.


And it turned out, that it works both with FreeRTOS and HAL images.So I guess the problem is that I need to do some extra work, when performing JumpToApp from FreeRTOS  application? Any suggestions what else is missing?

I've also decided to turn off this code inside the main function of bootloader, to make sure it will not affect anything.

    SCB->VTOR = FLASH_BOOTLOADER_START_ADDR;
    __set_MSP(*((volatile uint32_t*) FLASH_BOOTLOADER_START_ADDR));
    __set_PSP(*((volatile uint32_t*) FLASH_BOOTLOADER_START_ADDR));
    __enable_irq();

But it didn't help with FreeRTOS version.

The main purpose of that was to be able to perform JumpToApp inside the main app.
For now I decided to perform NVIC_SystemReset everywhere.

 

Why I decided to use FreeRTOS for the first time in bootloader?
That's because I wanted the code to be the same between both images.
But now I can't find a lot of examples of how others implementing FreeRTOS in their bootloaders, so maybe it was just the wrong concept from the start.

 

Attached the code here