QDK PIC24/dsPIC-XC16 - Quantum Leaps
QDK PIC24/dsPIC-XC16 - Quantum Leaps
QDK PIC24/dsPIC-XC16 - Quantum Leaps
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
<strong>QDK</strong><br />
<strong>PIC24</strong>/<strong>dsPIC</strong>-<strong>XC16</strong><br />
www.state-machine.com/pic<br />
5 Implementing “Zero Interrupt Latency” with the NMI<br />
As noted in Section 3.2, the interrupt locking policy in this QP port locks only interrupts with IPL from 1 to<br />
6. The highest-level interrupts with IPL=7 are not locked at all. In other words, IPL=7-interrupts are nonmaskable<br />
(they are NMIs). This interrupt locking policy has two important consequences.<br />
First, the IPL=7-interrupts cannot call any QP services (e.g., NMIs cannot post events to QP tasks),<br />
because any system call from an NMI would run the risk of corrupting the internal QP data since the<br />
protection by critical sections does not apply for NMIs.<br />
On the flip side, however, the IPL=7-interrupts run completely “free” with the interrupt latency determined<br />
only by the underlying hardware and independent on the critical sections implemented in the QP. This is<br />
what is meant here by the term “Zero Interrupt Latency”.<br />
Such NMIs (IPL=7-interrupts, in this case) have many potential uses. They are very useful when the<br />
software must perform some simple operations very fast, but most of the time the software does not need<br />
to communicate with the task-level of QP active objects. Consider for example a fast interrupt-driven<br />
UART interface. The ISR that receives bytes must remove the bytes from the FIFO very fast or else the<br />
FIFO will quickly overflow. However, the ISR might buffer the bytes and only need to notify the task level<br />
when the buffer fills up, which is relatively infrequently.<br />
NOTE: NMIs (IPL=7-interrupts, in this case) can be equally well used in the non-preemptive QP port<br />
as well as in the preemptive port with the QK kernel.<br />
5.1 Communication between NMIs and QP<br />
From the previous discussion it is obvious that the NMIs must be able to communicate from time to time<br />
with the task level (active objects in QP). The question is how to achieve such communication without<br />
calling QP services directly<br />
The solution is to call QP services indirectly, by triggering a regular (maskable) interrupt from the NMI. In<br />
the <strong>PIC24</strong>/<strong>dsPIC</strong> architecture you can very easily trigger an ISR by explicitly setting the corresponding<br />
interrupt flag (the same that you explicitly clear in the ISR). The triggered interrupt can call QP services,<br />
such as posting or publishing events to QP active objects.<br />
The subtle, but important consideration is the communication between the NMI and the triggered<br />
maskable interrupt. Typically, such communication must occur by means of atomically-accessed shared<br />
variables. In the <strong>PIC24</strong>/<strong>dsPIC</strong> CISC architecture most 8- and 16-bit variables are read and written<br />
atomically (in one machine instruction), so implementing this way of communication is quite easy. In other<br />
CPUs, such as RISC load-store architectures, the implementation of atomic access is trickier and requires<br />
using special swap (SWP) instructions.<br />
5.2 Implementation Considerations for the NMIs<br />
Because the NMIs run completely “free” and outside the QP framework, they don’t need to follow any<br />
conventions associated with regular maskable ISRs that can call QP services. Generally, the NMIs should<br />
run as fast as possible, because the interrupt latency for NMIs is determined typically by the execution<br />
time of the NMI itself. (In this QP port, only one IPL level 7 is available for NMIs, so NMIs cannot preempt<br />
each other).<br />
NMIs can be coded in C, and in fact the <strong>XC16</strong> compiler offers options to make these interrupts very<br />
efficient. On of these options is __shadow__, which uses fast context save and restore to the shadow<br />
registers. Obviously, you can use only one such fast ISR in your system to avoid corruption of the shadow<br />
registers. And finally, you should generally avoid calling any functions from the NMI, as this would force<br />
the compiler to save and restore w0-w7.<br />
Copyright © <strong>Quantum</strong> <strong>Leaps</strong>, LLC. All Rights Reserved.<br />
26 of 35