Question

I need to edit the return address of an ISR. The ISR should return to a specific address after the interrupt is handled, regardless of where it came from. This is to facilitate a fast system reset. This functionality can't be implemented in the normal firmware as timing is too tight to check a flag somewhere frequently.

I've tried editing the stack frame that is saved by the ISR upon exception entry, which seems to work for a few milliseconds, then it enters the micro's "Oh shit something went bad" state. In this state, the stack looks normal, and there are no signs that anything went wrong. This occurs even if I pop the stack and push exactly the same data back onto it. Also, using a stack-pointer-relative store causes this failure.

Info about exception handling can be found here, but I can't find enough info to tell me whats going wrong.

Ideas? I really just need to get the interrupt to return to the same label regardless of where the interrupt hits, and without the core getting all fussy.

Thanks, Stuart

Was it helpful?

Solution

A word of warning: this project was written in assembly with a lot of assumptions. This process is probably unsafe in C or assembly where you don't know exactly what the state of the CPU will be when the interrupt hits.

After messing around with the stack frame for a while I realized that the saved status register (xPSR) had some bits set that I hadn't seen set during operation. It turns out that the interrupt was sometimes firing in the middle of a LDM or STM command. The Cortex-M3 has functionality to save the state of these commands so that they can be resumed properly. Teh problem arose when it would return from the interrupt to my specified location expecting to finish a LDM/STM command, but could not.

In order to solve this problem, I merely had to clear the ICI bits in the saved status register in the stack frame. This made the Cortex-M3 "forget" that it was handling a LDM/STM command, and allowed the processor to return to an arbitrary location without consequence.

OTHER TIPS

You can do a reset by setting SYSRESETREQ (bit 2) in the Application Interrupt and Reset Control Register (addess 0xE000ED0C).

In C, I wrote:

// Reset by setting SYSRESETREQ
SCB->AIRCR = 0x05FA0004;

This will probably be a much cleaner reset than the other method you are trying.

You can find more details in the Cortex M3 Technical Reference Manual from ARM.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top