1
\$\begingroup\$

I can't seem to find an answer to this in google or the Definitive guide...

Is it possible to from one interrupt, cancel the return to any pre-empted interrupts? For example, I have an ISR which is called when an interrupt driven process needs to be aborted. Presumably, I will have been in an ISR when this interrupt is triggered, so I would like to reset the state of my state machine and cancel the completion of the previous state processing since there was an error. I know I could set a volatile flag but then I would need to check it constantly in the normal process code. I would prefer a much more direct, deterministic way to cancel the pre-empted interrupt.

Additional Information from the comments

I have a 2 processor system with an SPI command/control bus. The slave waits for a command from the master, then executes it and sends a response back. This is driven with some handshaking signals since the STM32F4 series has a useless hardware CS design. The problem I am experiencing from my other question is that after some time, the data returned to the master from a command is complete nonsense (specifically the last value received by the slave x transfer length). The master is able to detect this error and sends an abort signal. When received, I want the slave to cancel its DMA/SPI transfer, and return its state machine to waiting for a command. I can accomplish resetting the state machine no problem, I just want to make sure that when the abort ISR exits, it does not return to continue a DMA or USB ISR which is no longer valid.

\$\endgroup\$
9
  • 1
    \$\begingroup\$ Without meaning to say what you are wanting to do is unreasonable, having this type of question might be an indication that more involved work is being done in interrupt context than ideal. Can you split some of it into a backend? \$\endgroup\$ Commented Aug 14, 2014 at 19:27
  • \$\begingroup\$ @ChrisStratton I'm perfectly happy to agree with you but I don't see a clear path forward for it. I will try and factor out more to the main program loop if possible, but for academics if nothing else I still wonder if its possible. \$\endgroup\$
    – Jared
    Commented Aug 14, 2014 at 19:31
  • \$\begingroup\$ What are you trying to do? Can you rephrase a little? You want to prevent your ISR (1) to be prempted by another ISR (2) under some conditions or revert back to a previous state just like if you never entered ISR (1) ??? \$\endgroup\$
    – Mishyoshi
    Commented Aug 14, 2014 at 19:34
  • \$\begingroup\$ It sounds crazy I know. Perhaps some more details are in order. I have a 2 processor system with an SPI command/control bus. The slave waits for a command from the master, then executes it and sends a response back. This is driven with some handshaking signals since the STM32F4 series has a useless hardware CS design. The problem I am experiencing from my other question is that after some time, the data returned to the master from a command is complete nonsense (specifically the last value received by the slave x transfer length). The master is able to detect this error and sends an abort... \$\endgroup\$
    – Jared
    Commented Aug 14, 2014 at 19:39
  • \$\begingroup\$ ...signal. When received, I want the slave to cancel its DMA/SPI transfer, and return its state machine to waiting for a command. I can accomplish resetting the state machine no problem, I just want to make sure that when the abort ISR exits, it does not return to continue a DMA or USB ISR which is no longer valid. \$\endgroup\$
    – Jared
    Commented Aug 14, 2014 at 19:41

2 Answers 2

5
\$\begingroup\$

I am concerned that the question implies that the there is something complicated inside the system. That complication might make this even more difficult than it sounds!

I recommend trying Mishyoshi's answer first. It focuses on a cleaner, less intricate, easier to build and test solution.

However, I'll try to give an overview of the way 'aborting' and interrupt service routine might be done, so that folks can judge for themselves.

From a purely technical perspective, it is possible to 'abort' an 'outer' interrupt service routine (ISR) which itself was interrupted to reach 'this' 'inner' interrupt service routine in specific cases, for embedded (Cortex-M processors). However it is a bit tricky, maybe very hard to debug and make robust, and will need some good assembler and hardware debug skills.

A 'simple' technique relies on the 'outer' ISR never ever, under any circumstances calling any functions. If that is not a feasible guarantee then it gets much harder. Put another way, this will work if and only if the 'inner' ISR is always and only called while executing code within the body of the 'outer' ISR, and never in a function called by the 'outer; ISR

It will also get more complex if there are two processor stacks. It is still feasible, but more tricky.

Background:
An ARM does not store the return address of the current running function or ISR on the stack.

That return address is stored in the link register called 'lr' or R14. The only way to update the LR register is with assembler. IIRC might not be as easy as it sounds as some compilers will reload LR after your inline assembler has done its business, or maybe whine.

The return address for the outer function or ISR is on the stack somewhere. Finding that and loading it into the LR will do some of the work to abort the 'outer' ISR when the inner ISR returns.

The other problem is tidying up the stack, and resetting the stack pointer. If that isn't done correctly, the return from the 'outer' ISR can not be simulated. The effect might be subtle with calculations going wrong, pointers damaged, loops wrong, etc. This will need assembler skills and good 'hardware debugging' skills to ensure it is tested and working.

If this isn't exactly correct stack memory might 'leak'.

Do you want me to proceed, i.e. does this sound feasible for you folks to write and debug? It is still quite involved, and I have limited bandwidth.

I would recommend getting a copy of The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors by Joseph Yiu ASAP if you don't already have it. It explains some of this stuff.

\$\endgroup\$
8
  • \$\begingroup\$ I do have a copy but assembly is outside of my experience in general and I have only about a year's worth of small scale stuff with ARM. It sounds like that will be more involved than I was hoping, and given that the desire to do it is a sign of a likely bad design, I think its better to go with what I do know how to do and alter the over all data flow design to not need this. I was simply hoping there was a CMSIS call or register I could modify to jump back to to the normal code execution immediately. \$\endgroup\$
    – Jared
    Commented Aug 14, 2014 at 20:38
  • \$\begingroup\$ Also, given that your answer is more explanation to the question, I'm changing the accepted answer. \$\endgroup\$
    – Jared
    Commented Aug 14, 2014 at 20:39
  • \$\begingroup\$ @Jared - That is very kind. I will update my answer to pint folks at Mishyoshi. "Let's try to share the love" \$\endgroup\$
    – gbulmer
    Commented Aug 14, 2014 at 20:41
  • 1
    \$\begingroup\$ +1 for detailed explanation and clever solution. I generally avoid at all costs to unwind a stack generated by an optimizing C/C++ compiler, but I guess it is correct in that case since it is a prototype. Last time I tried that with MSPGCC I discovered that starting from O2 the compiler is not using the stack frame pointer R4 and return register R5 at all and that calling conventions used were sometimes different between O1 and O2+ ... But I guess someone motivated could achieve that. \$\endgroup\$
    – Mishyoshi
    Commented Aug 14, 2014 at 20:51
  • \$\begingroup\$ @Mishyoshi - I would avoid it at all costs too. I partly justified the effort of answering because I don't recall anyone giving enough detail to help people decide for themselves. Also, if you are really, really stuck (for example the company has lost the source code, which does happen) and the constraints can be guaranteed (e.g. by inspection of the binary) then an overview of the approach might help dig someone out of a deep, deep hole. \$\endgroup\$
    – gbulmer
    Commented Aug 14, 2014 at 20:59
3
\$\begingroup\$

From the comments:

you look like your are stuck in an USB ISR waiting for another isr to compelte and on aborting you want to leave that USB ISR too. To do that, put a kind of "spin lock" in your USB ISR that also as a flag to notify from special events such as cancellation. With that flag you may simply issue a return or a goto to the end of your ISR to ignore next step (sending data back to usb). The flag is a nice thing, because if global enough, your "ordinary code" state machine will also be aware of the "result" of your USB ISR, namely a successful transfer or a cancellation/failure.

\$\endgroup\$
3
  • \$\begingroup\$ As mentioned in chat, adapting to implementing this will be what I attempt to do moving forward. \$\endgroup\$
    – Jared
    Commented Aug 14, 2014 at 20:10
  • \$\begingroup\$ @Jared - I prefer Mishyoshi's approach over my answer too, though it is fun to think about :-) \$\endgroup\$
    – gbulmer
    Commented Aug 14, 2014 at 20:36
  • \$\begingroup\$ I also prefer his approach, but in the interests of what the question was actually asking, your answer is more correct. I am however following through with his suggestions. \$\endgroup\$
    – Jared
    Commented Aug 14, 2014 at 20:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.