Passing Small Amount of Data From an ISR Context to a Task/Thread Context

64 Views Asked by At

I have a device that I've written a driver for in an RTOS such that when it fires off an interrupt, its task is to read a 32-bit value from the device and have the system take some appropriate action based on the bits set in the value read. The solution I came up with seems to work, but I'm not sure if it would be frowned upon for being inefficient.

I realize that ISRs are naturally disruptive, so to spend as little time within the ISR context as possible, I separated the "appropriate action" logic into a separate thread so that it would be outside of the ISR context.

This is the approach I've taken:

  1. Mask interrupts for the device.

  2. Read 32-bit value from the device.

  3. Send value using a message queue for processing in a different thread.

  4. Clear and re-enable interrupts for the device.

This seems to work fine, but my main concern is the usage of the message queue. How costly is using a message queue in an ISR, and is it generally frowned upon? Is there a better, more efficient way to send data from an ISR to a different task/thread?

2

There are 2 best solutions below

2
Tom V On

Writing to a message queue from an interrupt is a textbook case of what message queues are for. It can be done very efficiently.

I'm not sure why you are turning off interrupts though. Do you mean that in the interrupt handler you turn off the interrupt that is currently running? That would not do anything on any architecture that I can think of. (Maybe edit the question if I have misinterpreted this part).

0
Clifford On

A message queue is entirely appropriate in the case that new data may arrive before old data has been processed, due either to burst writes or preemption of the processing thread by higher priority threads or interrupts.

It is often appropriate in cases where the data is always processed before new data arrives for simplicity and robustness (an RTOS queue is intrinsically thread safe). But in that case you may have a queue comprising a single message.

You could in the second case simply use shared memory and a thread signalling primitive such as a binary semaphore or event flag. The "zero-copy" semantics of that can make it more efficient, but for a single 32-bit word, that is unlikely to be significant.

Another technique you might consider if the data is a sequence of words arriving in a stream or burst is to use DMA transfer. That can reduce the interrupt rate and software overhead if dealing with rapidly arriving stream if data. In that case you might use either a queue or shared memory (the DMA buffer itself), but the handler would be the DMA interrupt, not the device interrupt.

I would strongly advise that you omit steps 1 and 4 in your interrupt handler. It should be unnecessary, and may result in loss of datam If an interrupt event occurs while you are in the handler, it will be pending and the ISR will re-enter. In that case you definitely need a queue. It is unlikely, but in that case there is also no need to disable them if they can't happen.

In the case where the data arrival interval faster than can be reasonably handled by a per-word interrupt handler, then DMA is the only viable solution (short of a faster processor).