Jump to main application from a bootloader running FreeRTOS

I’m using FreeRTOS Kernel V11.1.0
Cortex-M4 ATSAM microcontroller

I have a bootloader that runs FreeRTOS. My main application also runs FreeRTOS.
I have one task that performs ota update and another task that monitors update process. If no update is happening it jumps to main app after a few seconds.

The issue is that without performing any update the timer expires the bootloader tries to jump to main application and it hangs.
I randomly change the size of some buffer arrays and the issue dissapears.
I’m not confident of what is going on.

I have used very similar code in bootloader without FreeRTOS and I didn’t have any issues.

I tried to disable interrupts before jump. No success.

If I call jump before scheduler starts it works fine.

One key thing to remember when writing a boot loader, is that you need to be sure you have put the processor back into the state the loaded program is expecting.

Particularly with FreeRTOS, that means that interrupts should be disabled when you go to the application, and something needs to be handling the change of the location of the interrupt vectors from the boot loader to the application.

Remember starting the schedule changed the system state by enabling interrupts, and you need to undo that when you go to the application.

1 Like

Yes, I also execute

    __disable_irq();          
    NVIC->ICER[0] = 0xFFFFFFFF;  // Disable all IRQs in NVIC
    NVIC->ICPR[0] = 0xFFFFFFFF;  // Clear pending IRQs

before jumping to main application.

The weird thing is why I see different behaviour when I randomly change the size of some array buffers. For example too big or too low makes it work.

Could some device still be operating, and perhaps DMAing data into memory. (Like the Network Driver). That would be address dependent.

I have implemented a bootloader on the same chip. Same main app address, without FreeRTOS and it’s been working for many years.

I also tried to disable all peripheral clocks. Nothing changed.

did you make sure that the app runs with the ivt pointing to the correct application interrupt handlers?

1 Like

I’m not sure about this.
I have a linker script from another project. That uses the same microcontroller.
And I build the project using that linker script.
That project works fine with bootloader (without freertos)

when the bootloader passes control to the application, very likely the interrupt handlers of the application are not the same as those for the bootloader, so before jumping to the application, you need to rebase the ivt to one that contains the correct absolute addresses of your apps interrupt handlers. This has been discussed on this forum many times before, just query the forum for bootloader.

1 Like

This is how my jump function looks like:

void jump_to_main_app(void)
{
    pmc_disable_all_periph_clk();
    __disable_irq();          
    NVIC->ICER[0] = 0xFFFFFFFF;  // Disable all IRQs in NVIC
    NVIC->ICPR[0] = 0xFFFFFFFF;  // Clear pending IRQs


	uint32_t main_stack_pointer = *(volatile uint32_t*)MAIN_APP_ADDRESS;
    void (*main_app_entry)(void) = (void (*)(void))(*(volatile uint32_t*)(MAIN_APP_ADDRESS + 4));

	// Set the vector table to the main application
    SCB->VTOR = MAIN_APP_ADDRESS;  
    __DSB();  // Data Synchronization Barrier
    __ISB();  // Instruction Synchronization Barrier

    // Set the main stack pointer
    __set_MSP(main_stack_pointer);

	// Set the program counter to the application start address
	// just for remainder: Vector table's second entry is the system reset value
	main_app_entry();

    while(true);
}

well, you must set MAIN_APP_ADDRESS[0] to a RAM area that is large enough to host the interrupt stack before you jump to the entry point.

1 Like

Okay would you mind elaborate that? Why do you use an array [0]?

I don’t think the issue is the IVT, if I remove one task, it jumps into main app.

You also might need to switch from the process stack pointer (PSP) to the main stack pointer (MSP).

Please have a look here for more details.

1 Like

I’m going to try that too

@Til I’m trying your example. I notice something different. Let me test it more and I’ll come back with my feedback

This worked for me in similar circumstances:
Setting a unique code in the RAM and restart MCU.
When waking, redirect the code according to RAM content.
Use __no_init

Thanks everyone for your suggestions. @OneSecondBefore were you able to try @Til 's example?