2021-03-22 02:34 AM
Hi,
I try to jump from Bootloader to my main program using this function:
void jumpToMainProgram(){
uint32_t topOfStack = (*(uint32_t *)0x8008200ul);
HAL_RCC_DeInit(); // deinit clocks
// reset all periphals
__HAL_RCC_AHB_FORCE_RESET();
__HAL_RCC_AHB_RELEASE_RESET();
__HAL_RCC_APB1_FORCE_RESET();
__HAL_RCC_APB1_RELEASE_RESET();
__HAL_RCC_APB2_FORCE_RESET();
__HAL_RCC_APB2_RELEASE_RESET();
// reset Systick
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
/*__set_PSP(topOfStack);*/
__set_MSP(topOfStack);
__DSB(); // complete all memory accesses
{
typedef void (*t_pFunctionNoReturn)(void) __attribute__((noreturn));
register t_pFunctionNoReturn pAppl;
register U32 resetHandler;
resetHandler = (U32)0x08008200ul + 4ul;
pAppl = (t_pFunctionNoReturn)(*(U32 *)resetHandler); /* read from Reset vector */
pAppl();
while(1) { } // never reach this point
}
}
this works fine normally, but when I call this function from an ISR, the new program does not accept any new interrupts - it seems like the Core thinks I am still in the ISR.
Is there a solution how to jump to another program from an ISR?
thanks,
Michael
2021-03-24 06:33 AM
Hello
This is another example fit to your needs
It used only from inside an ISR, to jump to an address in thread mode.
Use it like this: jumpfromISR(topOfStack,(uint32_t)main);// first parameter is the new stackpointer in MSP, main is the function to jump.
The bit 0 of the second parameter must be always 1
clear also all pending interrupts before call this function.
It just a working (tested in M4) example and needs improvements , dont rely on it until you understand how it works.
In general , install the new stack, make the stack frame with new address to jump, load PC with proper exec return value, the stack pointer returns to its set position after jump.
__attribute__((naked)) __attribute__((noreturn)) void jumpfromISR(uint32_t new_stack_pointer,uint32_t jump_to_address);// remember jumptoaddress bit0 must be 1
__attribute__((naked)) __attribute__((noreturn)) void jumpfromISR(uint32_t new_stack_pointer,uint32_t jump_to_address)
{
//_____________________________________________________________________________
// this example uses MSP for both thread and handler modes.
__asm("LDR.W R2, =0xE000ED14");// Read SCB->CCR that located at address 0xE000ED14
__asm("LDR R3, [R2]");//Take the value of register
__asm("ORR R3, R3, #1");//Set bit 0 to enable NONBASETHRDENA
__asm("STR R3, [R2]");// Write back the value to the SCB->CCR
// take only the xPSR from stacked frame and discard the rest
__asm("POP {r2-r8}");// POP R0,ri,r2,r3,r12,lr,pc
__asm("POP {r2}");// POP xPSR to use it
__asm("MSR MSP, R0");//set the new stack pointer
__asm("DSB");// wait for store to complete
__asm("ISB");// reset pipeline
//Make a new stack frame
__asm("PUSH {R2}");//xPSR
__asm("PUSH {R1}");// new address to go
__asm("PUSH {R0-R5}");// just complete the next of stack frame with "dont care" values. But if you care to return something , just modify it
// this is the "jump" of ISR , dont forget to disable the NONBASETHRDENA bit when start the new program(thread mode)
//load the PC with one of EXC_RETURN values.. Exception return values,described in cortex Generic User Guide
__asm("LDR R0, =0xFFFFFFF9");//Return to Thread mode, exception return uses non-floating-point state from MSP and execution uses MSP after return.
__asm("BX R0");// load PC with EXC_RETURN value.. will go to thread mode, after xPSR(8th word) poped from stack
// normaly the execution will not reach this line
__asm("B .");//trap
//_____________________________________________________________________________
}
2021-03-24 07:12 AM
> if the device is frozen somewhere in the main() due to a software error
If the bootloader is freezing, the device is doomed anyway. Bootloader is the piece of code that must always be capable of running and recovering the main firmware. Instead of investing your time into making dirty hacks, you should invest it into learning all the details of hardware and software development and making the bootloader almost perfect. And then to come out of that freezing, that should not happen at all, microcontrollers have a hardware watchdog peripherals.
2021-03-24 08:35 AM
Remove the flag for bootloader entry and reset the CPU. Voila!
2021-03-24 09:10 AM
The easier route is to just HW reset the processor, and fast-track the jump into the application from the loader's Reset Handler using flagging in RAM
2021-03-24 09:49 AM
Indeed. And that is discussed many times with some examples also:
2021-03-26 01:34 AM
okay. thanks guys. I thought there would be a simple solution to this. Now I set up a region in RAM for communication between bootloader and main program. for jumping into any part of the program I now just set the command where to jump to and then reset the device. It is not as simple and fast, but it is more clean.
2021-03-26 01:39 AM
Hi,
I really appreciate your effort. Still as you say... before using this I must understand it fully. I think I am not able to understand this code without learning much more about the internal core structure of the ARM. My problem is, that I don't have time for this at the moment.
Therefore I must use the workaround described below.