Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Are you using an RTOS? Generally this type of thing would be handled by having a high priority thread that gets signaled to do some work by the interrupt. </p> <p>If you're not using an RTOS, you only have a few tasks, and the work being kicked off by the interrupt isn't too resource intensive, it might be simplest having your high priority work done in the context of the interrupt handler. If those conditions don't hold, then implementing what you're talking about would be the start of a basic multitasking OS itself. That can be an interesting project in its own right, but if you're looking to just get work done, you might want to consider a simple RTOS.</p> <p>Since you mentioned some specifics about the work you're doing, here's an overview of how I've handled a similar problem in the past:</p> <p>For handling received data over a UART one method that I've used when dealing with a simpler system that doesn't have full support for tasking (ie., the tasks are round-robined i na simple <code>while</code> loop) is to have a shared queue for data that's received from the UART. When a UART interrupt fires, the data is read from the UART's RDR (Receive Data Register) and placed in the queue. The trick to deal with this in such a way that the queue pointers aren't corrupted is to carefully make the queue pointers volatile, and make certain that only the interrupt handler modifies the tail pointer and that only the 'foreground' task that's reading data off the queue modified the head pointer. A high-level overview:</p> <ul> <li><p>producer (the UART interrupt handler):</p> <ol> <li>read <code>queue.head</code> and <code>queue.tail</code> into locals;</li> <li>increment the local tail pointer (<em>not</em> the actual <code>queue.tail</code> pointer). Wrap it to the start of the queue buffer if you've incremented past the end of the queue's buffer.</li> <li>compare <code>local.tail</code> and <code>local.head</code> - if they're equal, the queue is full, and you'll have to do whatever error handing is appropriate.</li> <li>otherwise you can write the new data to where <code>local.tail</code> points</li> <li>only now can you set queue.tail == local.tail</li> <li>return from the interrupt (or handle other UART related tasks, if appropriate, like reading from a transmit queue)</li> </ol></li> <li><p>consumer (the foreground 'task')</p> <ol> <li>read <code>queue.head</code> and <code>queue.tail</code> into locals;</li> <li>if <code>local.head</code> == <code>local.tail</code> the queue is empty; return to let the next task do some work</li> <li>read the byte pointed to by <code>local.head</code></li> <li>increment <code>local.head</code> and wrap it if necessary;</li> <li>set <code>queue.head</code> = <code>local.head</code></li> <li>goto step 1</li> </ol></li> </ul> <p>Make sure that <code>queue.head</code> and <code>queue.tail</code> are <code>volatile</code> (or write these bits in assembly) to make sure there are no sequencing issues. </p> <p>Now just make sure that your UART received data queue is large enough that it'll hold all the bytes that could be received before the foreground task gets a chance to run. The foreground task needs to pull the data off the queue into it's own buffers to build up the messages to give to the 'message processor' task.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload