17.01.2015 Views

QDK PIC24/dsPIC-XC16 - Quantum Leaps

QDK PIC24/dsPIC-XC16 - Quantum Leaps

QDK PIC24/dsPIC-XC16 - Quantum Leaps

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!