cancel
Showing results for 
Search instead for 
Did you mean: 

Jumping to main program from ISR

Schmid.M.
Senior

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

16 REPLIES 16

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
//_____________________________________________________________________________  
}

Piranha
Chief II

> 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.

Uwe Bonnes
Principal III

Remove the flag for bootloader entry and reset the CPU. Voila!

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

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Schmid.M.
Senior

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.

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.