Figure 6: An example of debugging interrupts without breakpoints

// A printf-like function to publish information 
// over an Ethernet connection.
int publish (const char*, ...);
 
// Global buffer and count of interrupt status
struct intData {
    unsigned long   tickCount;
    unsigned short  intLevel;
    unsigned short  charsWaiting;
};

intData inputInterruptData [NUM_INT_DATA]; 
unsigned short inputDataCount = 0;

// Global mutex created for debugging
Mutex debugMutex;

// Characters available in input buffer 
extern unsigned short getInputChars (int); 
// System interrupt level
extern unsigned short getIntLevel(); 
// System time in ticks
extern unsigned long getTickCount();    

// Interrupt being debugged
void myAsyncInputInterrupt ()
{
    // Save all the relevant information 
    inputInterruptData [inputDataCount].tickCount =
        getTickCount();
    inputInterruptData [inputDataCount].intLevel =
        getIntLevel();
 
    // Save the number of characters but not the data for now
    // memcpy() can be very slow
    inputInterruptData [inputDataCount].charsWaiting = 
        getInputChars (INPUT_1);

    if (NUM_INT_DATA == ++inputDataCount)
        inputDataCount = 0;

    // Wake up the regular thread that is waiting for this data
    mutex_give (&debugMutex);

    // Regular interrupt processing
    ...
}


bool debugInt = true;

// Regular task code for debugging the interrupt
void myDebugCode()
{
    // Wait forever for the interrupt to wake us up
    while (NO_ERROR == mutex_take (&debugMutex, 0) && debugInt)
    {

        // Grab a local copy as fast as possible in case of
        // additional interrupts are generated before debug 
        // processing is complete
        unsigned short localCount = inputDataCount; 
        intData localIntData = inputInterruptData[localCount];
 
        // Do whatever debug processing is helpful
        publish ("Interrupt data count %ud:\n", localCount);
        ...
    }
}