2
votes

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

2
Can you just jump to the reset vector instead of returning from the ISR at all? It should be possible to write a function that puts most of the CPU state back to something resembling the state at reset, and then jumps.RBerteig
I did write the ISR. I don't want to reset the part completely, as there is a fair amount of comm initialization that shouldn't be redone. I can jump from the interrupt to the wanted code location, but then the interrupt is being handled forever, and will never be triggered again.Vatsu1
Did you remember to set the LSB of the address to 1 (for Thumb mode)?Turbo J
Yes, the Thumb bit is always set to 1.Vatsu1
Why are you using assembly? C can be so good on an M3, and GCC is free. Not enough program space?David Grayson

2 Answers

4
votes

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.

2
votes

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.