Changing priority of current interrupt in NVIC - arm

I have a conundrum. The part I am using (NXP KL27, Cortex-M0+) has an errata in its I2C peripheral such that during receive there is no flow control. As a result, it needs to be a high priority interrupt. I am also using a UART that, by its asynchronous nature, has no flow control on its receive. As a result, it needs to be a high priority interrupt.
Circular Priority
The I2C interrupt needs to be higher priority than the UART interrupt, otherwise an incoming byte can get demolished in the shift register before being read. It really shouldn't work this way, but that's the errata, and so it needs to be higher priority.
The UART interrupt needs to be higher priority than the I2C interrupt, because to close out an I2C transaction the driver (from NXP's KSDK) needs to set a flag and wait for a status bit. During this wait incoming characters on the UART can overflow the non-FIFO'd shift register.
In trying to solve an issue with the UART, I discovered this circular dependency. The initial issue saw characters disappearing from the UART receive and the overrun flag being set. When swapping priorities, the UART was rock solid, never missing a character, but I2C transactions ended up stalling due to overruns.
Possible Solution
The solution I came up with involves changing interrupt priorities on the fly. When the I2C driver is closing out a transaction, it is not receiving, which means the errata that causes bytes to flow in uncontrolled is not an issue. I would like to demote the I2C interrupt priority in the NVIC during this time so that the UART is able to take priority over it, thus making the UART happy (and not missing any characters).
Question
I haven't been able to find anything from ARM that states whether changing the interrupt priority while executing that interrupt will take effect immediately, or if the priority of the current interrupt was latched in when it started executing. I am hoping someone can definitely save from the depths of their knowledge of the architecture or from experience that changing the priority will take effect immediately, or not.
Other Possible Solutions
There are a number of other possible solutions and reasons why they are undesirable. Refactoring the I2C driver to handle the loop in the process context rather than interrupt context would be a significant effort digging into the vendor code and affects the application code that calls into it. Using DMA for either of these peripherals uses up a non-trivial amount of the DMA channels available and incurs the overhead of setting up DMA for each transaction (and also affects the application code that calls into the drivers).
I am open to other solutions, but hesitant to go down any path that causes significant changes to the vendor code.
Test
I have an idea for an experiment to test how the NVIC works in this regard, but I thought I would check here first. If I get to the experiment, I will post a follow-up answer with the results.

Architecturally, this appears to be UNPREDICTABLE (changing the priority of a currently active exception). There seems to be no logic in place to enforce more consistent behavior (i.e. the registration logic you are concerned about is not obviously present in M0/M0+).
This means that if you test for the effectiveness of your workaround, it will probably appear to work - and in your constrained scenario it might be effective. However, there is no guarantee that the same code will work on M3, or that it works reliably in all scenarios (for example any interaction with debug). You might even observe some completely unpredictable corner case behavior, but the area-constrained
This is specified as unpredictable in section B1.5.4 of the ARM v6-M ARM.
For v7-M (B1.5.4, Exception Priorities and preemption)
This definition of execution priority means that an exception handler
can be executing at a priority that is higher than the priority of the
corresponding exception. In particular, if a handler reduces the
priority of its corresponding exception, the execution priority falls
only to the priority of the highest-priority preempted exception.
Therefore, reducing the priority of the current exception never
permits:
A preempted exception to preempt the current exception handler.
Inversion of the priority of preempted exceptions.
The v7-M aspect clarifies some of the complex scenarios which must be avoided if you attempt to make use of the unpredictable behavior which you have identified as useful with the M0+ part.

Experiment
I coded up a quick experiment today to test this behavior on my particular variant of the Cortex M0+. I am leaving this as an unaccepted answer, and I believe #Sean Houlihane's answer is the most correct (i.e. it is unpredictable). I still wanted to test the behavior and report in under the specific circumstances for while I am using it.
The experiment was performed on a FRDM-KL43Z board. It has a red LED, a green LED, and two push buttons. The application performed some setup of the GPIO and interrupts and then sat in an infinite loop.
Button 1: Button 1's interrupt handler was initialized to midscale priority (0x80). On every falling edge of button 1 it would pend the interrupt. This interrupt would toggle the green LED's state.
Button 2: Button 2's interrupt handler was initialized to midscale priority (0x80), but would be changed as a part of execution. The button 2 interrupt handler would run a loop that lasted approximately 8 seconds (two phases of four), repeating indefinitely. It would turn on the red LED and decrease it's own priority below that of button 1. After the four seconds, it would turn off the red LED and increase it's own priority above that of button 1. After four seconds it would repeat.
Expected Results
If the hypothesis proves to be true, when the red LED is on, pressing button 1 will toggle the green LED, and when the red LED is off, pressing button 1 will have no effect until the red LED turns off. The button 1 interrupt would not execute until the forever looping button 2 interrupt is of a lower priority.
Results
This is the boring section. Everything I expected in the previous section happened.
Conclusion
For the experimental setup (NXP KL43Z Cortex M0+), changing the interrupt priority of the currently executing interrupt takes effect while the interrupt is running. As a result, my hacky workaround of demoting priority during the busy wait and restoring it after should function for what I need.
Edit:
Later Results
Though the experiment was successful, problems started occurring once the workaround for the original issue was implemented. The interaction between the UART and I2C handlers was relatively consistent, but a third peripheral started having very odd behavior in its interrupt handler. Take heed of the warning of UNPREDICTABLE.

One alternative solution could be to defer to another, lower priority, interrupt for the second half of your processing. A good candidate is the PendSV interrupt (if not already in use), which can (only) be triggered from software.
For a more detailed explanation, see this answer to a similar question and this answer about PendSV in general.

Related

How to know whether an IRQ was served immediately on ARM Cortex M0+ (or any other MCU)

For my application (running on an STM32L082) I need accurate (relative) timestamping of a few types of interrupts. I do this by running a timer at 1 MHz and taking its count as soon as the ISR is run. They are all given the highest priority so they pre-empt less important interrupts. The problem I'm facing is that they may still be delayed by other interrupts at the same priority and by code that disables interrupts, and there seems to be no easy way to know this happened. It is no problem that the ISR was delayed, as long as I know that the particular timestamp is not accurate because of this.
My current approach is to let each ISR and each block of code with interrupts disabled check whether interrupts are pending using NVIC->ISPR[0] and flagging this for the pending ISR. Each ISR checks this flag and, if needed, flags the timestamp taken as not accurate.
Although this works, it feels like it's the wrong way around. So my question is: is there another way to know whether an IRQ was served immediately?
The IRQs in question are EXTI4-15 for a GPIO pin change and RTC for the wakeup timer. Unfortunately I'm not in the position to change the PCB layout and use TIM input capture on the input pin, nor to change the MCU used.
update
The fundamental limit to accuracy in the current setup is determined by the nature of the internal RTC calibration, which periodically adds/removes 32kHz ticks, leading to ~31 µs jitter. My goal is to eliminate (or at least detect) additional timestamping inaccuracies where possible. Having interrupts blocked incidentally for, say, 50+ µs is hard to avoid and influences measurements, hence the need to at least know when this occurs.
update 2
To clarify, I think this is a software question, asking if a particular feature exists and if so, how to use it. The answer I am looking for is one of: "yes it is possible, just check bit X of register Y", or "no it is not possible, but MCU ... does have such a feature, called ..." or "no, such a feature is generally not available on any platform (but the common workaround is ...)". This information will guide me (and future readers) towards a solution in software, and/or requirements for better hardware design.
In general
The ideal solution for accurate timestamping is to use timer capture hardware (built-in to the microcontroller, or an external implementation). Aside from that, using a CPU with enough priority levels to make your ISR always the highest priority could work, or you might be able to hack something together by making the DMA engine sample the GPIO pins (specifics below).
Some microcontrollers have connections between built-in peripherals that allow one peripheral to trigger another (like a GPIO pin triggering timer capture even though it isn't a dedicated timer capture input pin). Manufacturers have different names for this type of interconnection, but a general overview can be found on Wikipedia, along with a list of the various names. Exact capabilities vary by manufacturer.
I've never come across a feature in a microcontroller for indicating if an ISR was delayed by a higher priority ISR. I don't think it would be a commonly-used feature, because your ISR can be interrupted by a higher priority ISR at any moment, even after you check the hypothetical was_delayed flag. A higher priority ISR can often check if a lower priority interrupt is pending though.
For your specific situation
A possible approach is to use a timer and DMA (similar to audio streaming, double-buffered/circular modes are preferred) to continuously sample your GPIO pins to a buffer, and then you scan the buffer to determine when the pins changed. Note that this means the CPU must scan the buffer before it is overwritten again by DMA, which means the CPU can only sleep in short intervals and must keep the timer and DMA clocks running. ST's AN4666 is a relevant document, and has example code here (account required to download example code). They're using a different microcontroller, but they claim the approach can be adapted to others in their lineup.
Otherwise, with your current setup, I don't think there is a better solution than the one you're using (the flag that's set when you detect a delay). The ARM Cortex-M0+ NVIC does not have a feature to indicate if an ISR was delayed.
A refinement to your current approach might be making the ISRs as short as possible, so they only do the timestamp collection and then put any other work into a queue for processing by the main application at a lower priority (only applicable if the work is more complex than the enqueue operation, and if the work isn't time-sensitive). Eliminating or making the interrupts-disabled regions short should also help.

What happens when a interrupt occurs in RTOS while currently in any task or another ISR?

I have read this question, It is not a valid answer when one interrupt is executing it will not disable all the other interrupts always. It is based on the interrupt type (in some case we need to do manually in our program).
My Question is what happens when a interrupt occurs while executing a
interrupt ??? If Low priority interrupt is executing then High
priority interrupt occurs the what will happen ?
It depends on the system. If the microcontroller/interrupt controller supports nested interrupts and the application enables that feature then a higher priority interrupt will interrupt a lower priority interrupt. In this case the lower priority interrupt will resume when the higher priority interrupt is complete. But if the system does not support nested interrupts then the subsequent interrupt request will pend and be serviced when the active interrupt service routine is complete.
It is too broad for SO, I think and it is arch based.
I try to give you a brief overview, expecting some DV on it. ;)
Mainly, if the arch allow nested interrupts, the interrupt with lower priority is interrupted while executing to jump to the ISR of high level interrupt.
But you can have NMI (Non Maskable Interrupt) that have priority on all other interrupts and cannot be disable.
Usually (all I think) archs have also a global interrupt enable flag, so it must be enabled to allow other interrupts to be served. Also means that an ISR, when is executing, can disable other interrupts during its job.
You can think, for example, on an RTOS implementation: the scheduler can be easily developed using a Timer within its interrupt. This interrupt must have the lower priority and mustn't stops other interrupts (usually): this grant that interrupts are served a soon as possible not considering context switch of RTOS scheduler.
The question was
What happens when a interrupt occurs in RTOS while currently in any task or another ISR?
I have written two commercial RTOS's and there is no answer that satisfies all of the criteria. However, I CAN answer as broadly as the question:
Depending on what is allowed, it will act as a normal interrupt. The problem with this question is that "what happens" is a little broad - some RTOS's do work behind the scenes with interrupts. So, the problem is that the question is not specific enough.
"What happens" in regards to a task is that NOTHING happens in regards to a task. An interrupt is an interrupt and what the relation to a task is depends on the programming. Since I don't read minds, again, the question is not specific enough.
The BEST answer is 42 (HHGTTG)
There is no one answer, sometimes nothing happens the lower prio interrupt continues to completion, sometimes the higher one interrupts the lower. It depends first on the chip/system design, second it depends on the individual programmers across the board RTOS and application folks.
Or another way to say it is, what happens is what those individuals desired to happen in their design and implementation.

ARM GIC Interrupt starvation

Not sure if there are similar questions. I tried to backread but can't find any, so here it is.
In my bare-metal application that uses ARM Cortex-A9 (dual core with GIC), some of the interrupt sources are 4 FPGA interrupts (let's say IRQ ID 58, 59, 60, 61) that have the same priority and the idea is that all simultaneously trigger continuously in run-time. I can say the interrupt handlers may qualify as long, but not very long.
All interrupts fire and are detected by GIC and all are flagged as PENDING. The problem is, only the two higher ID'ed interrupts (58, 59) get handled by CPU, starving the other two. Once 58 or 59 are done, their source will trigger again and grab the CPU over and over again. My other interrupts are indefinitely being starved.
I played around with priority, assigning higher interrupts to 60 and 61. Sure enough, 60 and 61 triggered and got handled by CPU, but 58 and 59 are starved. So it's really an issue of starvation.
Is there any way out of here, such that the other two will still be processed given their triggering rate?
Assuming the GIC implementation is one of ARM's designs, then the arbitration scheme for multiple interrupts at the same priority is fixed at "dispatch the lowest-numbered one", so if you were hoping it could be changed to some kind of round-robin scheme you're probably out of luck.
That said, if these interrupts are more or less permanently asserted and you're taking them back-to-back then that's a sign that you probably don't need to use interrupts, or at least that the design of your code is inappropriate. Depending on the exact nature of the task, here are some ideas I'd consider:
Just run a continuous polling loop cycling through each device in turn. If there are periods when each device might not need servicing and it's not straightforward to tell, retain a trivial interrupt handler that just atomically sets a flag/sequence number/etc. to inform the loop who's ready.
Handle all the interrupts on one core, and the actual processing on the other. The handler just grabs the necessary data, stuffs it into a queue, and returns as quickly as possible, while the other guy just steadily chews through the queue.
If catching every single interrupt is less important than just getting "enough" of each of them on average, leave each one disabled for a suitable timeout after handling it. Alternatively, hack up your own round-robin scheduling by having only one enabled at a time, and the handler reenables the next interrupt instead of the one just taken.
In my bare-metal application that uses ARM Cortex-A9 (dual core with GIC)...
Is there any way out of here, such that the other two will still be processed given their triggering rate?
Of course there are many ways.
You have a dual CPU so you can route a set to each CPU; 58/59 to CPU0 and 60/61 to CPU1. It is not clear how you have handled things with the distributor nor the per-CPU interfaces.
A 2nd way is to just read the status in the 58/59 handlers of the 60/61 and do the work. Ie, you can always read a status of another interrupt from the IRQ handler.
You can also service each and every pending interrupt recorded at the start of the IRQ before acknowledging the original source. A variant of '2' implemented at the IRQ controller layer.
I believe that most of these solutions avoid needless context save/restores and should also be more efficient.
Of course if you are asking the CPU to do more work than it can handle, priorities don't matter. The issue may be your code is not efficient; either the bare metal interrupt infrastructure or your FPGA IRQ handler. It is also quite likely the FPGA to CPU interface is not designed well. You may need to add FIFOs in the FPGA to buffer the data so the CPU can handle more data at a time. I have worked with several FPGA designers. They have a lot of flexibility and usually if you ask for something that will make the IRQ handler more efficient, they can implement it.

what's wrong in using interrupt handlers as event listeners

My system is simple enough that it runs without an OS, I simply use interrupt handlers like I would use event listener in a desktop program. In everything I read online, people try to spend as little time as they can in interrupt handlers, and give the control back to the tasks. But I don't have an OS or real task system, and I can't really find design information on OS-less targets.
I have basically one interrupt handler that reads a chunk of data from the USB and write the data to memory, and one interrupt handler that reads the data, sends the data on GPIO and schedule itself on an hardware timer again.
What's wrong with using the interrupts the way I do, and using the NVIC (I use a cortex-M3) to manage the work hierarchy ?
First of all, in the context of this question, let's refer to the OS as a scheduler.
Now, unlike threads, interrupt service routines are "above" the scheduling scheme.
In other words, the scheduler has no "control" over them.
An ISR enters execution as a result of a HW interrupt, which sets the PC to a different address in the code-section (more precisely, to the interrupt-vector, where you "do a few things" before calling the ISR).
Hence, essentially, the priority of any ISR is higher than the priority of the thread with the highest priority.
So one obvious reason to spend as little time as possible in an ISR, is the "side effect" that ISRs have on the scheduling scheme that you design for your system.
Since your system is purely interrupt-driven (i.e., no scheduler and no threads), this is not an issue.
However, if nested ISRs are not allowed, then interrupts must be disabled from the moment an interrupt occurs and until the corresponding ISR has completed. In that case, if any interrupt occurs while an ISR is in execution, then your program will effectively ignore it.
So the longer you spend inside an ISR, the higher the chances are that you'll "miss out" on an interrupt.
In many desktop programs, events are send to queue and there is some "event loop" that handle this queue. This event loop handles event by event so it is not possible to interrupt one event by other one. It also is good practise in event driven programming to have all event handlers as short as possible because they are not interruptable.
In bare metal programming, interrupts are similar to events but they are not send to queue.
execution of interrupt handlers is not sequential, they can be interrupted by interrupt with higher priority (numerically lower number in Cortex-M3)
there is no queue of same interrupts - e.g. you can't detect multiple GPIO interrupts while you are in that interrupt - this is the reason you should have all routines as short as possible.
It is possible to implement queues by yourself, feed these queues by interrupts and consume these queues in your super loop (consume while disabling all interrupts). By this approach, you can get sequential processing of interrupts. If you keep your handlers short, this is mostly not needed and you can do the work in handlers directly.
It is also good practise in OS based systems that they are using queues, semaphores and "interrupt handler tasks" to handle interrupts.
With bare metal it is perfectly fine to design for application bound or interrupt/event bound so long as you do your analysis. So if you know what events/interrupts are coming at what rate and you can insure that you will handle all of them in the desired/designed amount of time, you can certainly take your time in the event/interrupt handler rather than be quick and send a flag to the foreground task.
The common approach of course is to get in and out fast, saving just enough info to handle the thing in the foreground task. The foreground task has to spin its wheels of course looking for event flags, prioritizing, etc.
You could of course make it more complicated and when the interrupt/event comes, save state, and return to the forground handler in the forground mode rather than interrupt mode.
Now that is all general but specific to the cortex-m3 I dont think there are really modes like big brother ARMs. So long as you take a real-time approach and make sure your handlers are deterministic, and you do your system engineering and insure that no situation happens where the events/interrupts stack up such that the response is not deterministic, not too late or too long or loses stuff it is okay
What you have to ask yourself is whether all events can be services in time in all circumstances:
For example;
If your interrupt system were run-to-completion, will the servicing of one interrupt cause unacceptable delay in the servicing of another?
On the other hand, if the interrupt system is priority-based and preemptive, will the servicing of a high priority interrupt unacceptably delay a lower one?
In the latter case, you could use Rate Monotonic Analysis to assign priorities to assure the greatest responsiveness (the shortest execution-time handlers get the highest priority). In the first case your system may lack a degree of determinism, and performance will be variable under both event load, and code changes.
One approach is to divide the handler into real-time critical and non-critical sections, the time-critical code can be done in the handler, then a flag set to prompt the non-critical action to be performed in the "background" non-interrupt context in a "big-loop" system that simply polls event flags or shared data for work to complete. Often all that might be necessary in the interrupt handler is to copy some data to timestamp some event - making data available for background processing without holding up processing of new events.
For more sophisticated scheduling, there are a number of simple, low-cost or free RTOS schedulers that provide multi-tasking, synchronisation, IPC and timing services with very small footprints and can run on very low-end hardware. If you have a hardware timer and 10K of code space (sometimes less), you can deploy an RTOS.
I am taking your described problem first
As I interpret it your goal is to create a device which by receiving commands from the USB, outputs some GPIO, such as LEDs, relays etc. For this simple task, your approach seems to be fine (if the USB layer can work with it adequately).
A prioritizing problem exists though, in this case it may be that if you overload the USB side (with data from the other end of the cable), and the interrupt handling it is higher priority than that triggered by the timer, handling the GPIO, the GPIO side may miss ticks (like others explained, interrupts can't queue).
In your case this is about what could be considered.
Some general guidance
For the "spend as little time in the interrupt handler as possible" the rationale is just what others told: an OS may realize a queue, etc., however hardware interrupts offer no such concepts. If the event causing the interrupt happens, the CPU enters your handler. Then until you handle it's source (such as reading a receive holding register in the case of a UART), you lose any further occurrences of that event. After this point, until exiting the handler, you may receive whether the event happened, but not how many times (if the event happened again while the CPU was still processing the handler, the associated interrupt line goes active again, so after you return from the handler, the CPU immediately re-enters it provided nothing higher priority is waiting).
Above I described the general concept observable on 8 bit processors and the AVR 32bit (I have experience with these).
When designing such low-level systems (no OS, one "background" task, and some interrupts) it is fundamental to understand what goes on on each priority level (if you utilize such). In general, you would make the most real-time critical tasks the highest priority, taking the most care of serving those fast, while being more relaxed with the lower priority levels.
From an other aspect usually at design phase it can be planned how the system should react to missed interrupts, since where there are interrupts, missing one will eventually happen anyway. Critical data going across communication lines should have adequate checksums, an especially critical timer should be sourced from a count register, not from event counting, and the likes.
An other nasty part of interrupts is their asynchronous nature. If you fail to design the related locks properly, they will eventually corrupt something giving nightmares to that poor soul who will have to debug it. The "spend as little time in the interrupt handler as possible" statement also encourages you to keep the interrupt code reasonably short which means less code to consider for this problem as well. If you also worked with multitasking assisted by an RTOS you should know this part (there are some differences though: a higher priority interrupt handler's code does not need protection against a lower priority handler's).
If you can properly design your architecture regarding the necessary asynchronous tasks, getting around without an OS (from the no multitasking aspect) may even prove to be a nicer solution. It needs way more thinking to design it properly, however later there are much less locking related problems. I got through some mid-sized safety critical projects designed over a single background "task" with very few and little interrupts, and the experience and maintenance demands regarding those (especially the tracing of bugs) were quite satisfactory compared to some others in the company built over multitasking concepts.

How do you test your interrupt handling module?

I've got an interrupt handling module which controls the interrupt controller hardware on an embedded processor. Now I want to add more tests to it. Currently, the tests only tests if nesting of interrupts works by making two software interrupts from within an ISR, one with low priority and one with high priority. How can I test this module further?
I suggest that you try to create other stimuli as well.
Often, also hardware interrupts can be triggered by software (automatic testing) or the debugger by setting a flag. Or as an interrupt via I/O. Or a timer interrupt. Or you can just set the interrupt bit in an interrupt controller via the debugger while you are single stepping.
You can add some runtime checks on things which are not supposed to happen. Sometimes I elect to set output pins to monitor externally (nice if you have an oscilloscope or logic analyser...)
low_prio_isr(void)
{
LOW_PRIO_ISR=1;
if (1 == HIGH_PRIO_ISR)
{ this may never happen. dummy statement to allow breakpoint in debugger }
}
high_prio_isr(void)
{
HIGH_PRIO_ISR=1
}
The disadvantage of the software interrupt is that the moment is fixed; always the same instruction. I believe you would like to see evidence that it always works; deadlock free.
For interrupt service routines I find code reviews very valuable. In the end you can only test the situations you've imagined and at some point the effort of testing will be very high. ISRs are notoriously difficult to debug.
I think it is useful to provide tests for the following:
- isr is not interrupted for lower priority interrupt
- isr is not interrupted for same priority interrupt
- isr is interrupted for higher priority interrupt
- maximum nesting count within stack limitations.
Some of your tests may stay in the code as instrumentation (so you can monitor for instance maximum nesting level.
Oh, and one more thing: I've generally managed to keep ISRs so short that I can refrain from nesting.... if you can this will gain you additional simplicity and more performance.
[EDIT]
Of course, ISRs need to be tested on hardware in system too. Apart from the bit-by-bit, step-by-step approach you may want to prove:
- stability of system at maximum interrupt load (preferably several times the predicted maximum load; if your 115kbps serial driver can also handle 2MBps you'll be ok!)
- correct moment of enabling / disabling isr, especially if system also enters a sleep mode
- # of interrupts. Can be surprising if you add mechanical switches, mechanical rotary (hundreds of break/contact moments before reaching steady situation)
I recommend real-hardware testing. Interrupt handling is inherently random and unpredictable.
Use a signal generator and feed a square wave into the appropriate interrupt pin. Use multiple generators (or one with multiple outputs) to test multiple IRQ lines and verify priority handling.
Experiment with dialing the frequency up & down on the signal generators (vary the rates between them), and see what happens. Have lots of diagnostic code to verify the state of the interrupt controller in the various states.
Alternative: If your platform has timers that can trigger interrupts, you can use them instead of external hardware.
I'm not an embedded developer, so I don't know if this is possible, but how about decoupling the code that handles the interrupts from the callback-registration mechanism? This would allow you to write simulator code fireing interrupt-events as you like it...
For stuff like this I highly recommend something like the SPIN model checker. You wind up testing the algorithm, not the code, but the testing is exhaustive. Back in the day, I found a bug in gdb using this technique.

Resources