Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
20 years ago

Synchronizing between ISR and main code

Hello all,

What is the best way to ensure safe access to shared data between an ISR and the main code ?

In my application, the ISR reads a packet from the FIFO of a custom UART and saves it in a buffer provided to it upon registration. It then asserts a "ready" flag on the data. The main code polls for this flag and processes the data when it's ready. How can I ensure that during the main code's processing the data the ISR won't jump again and override it ? It may cause corrupted data. Say the main code has read 5 out of 10 bytes and then the ISR has overwritten them. When the main code resumes it will read the remaining 5 bytes from the new message.

Is disabling interrupts during the main's code reading of the data the best option ?

What are the common guideline when dealing with data synchronization in ISRs for Nios ?

Thanks in advance

http://forum.niosforum.com/work2/style_emoticons/<#EMO_DIR#>/cool.gif

3 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi eliben,

    > What is the best way to ensure safe access to shared data between an

    > ISR and the main code ?

    That depends on what you are trying to do -- there&#39;s usually not a single "best way".

    > Is disabling interrupts during the main&#39;s code reading of the data the best option ?

    In most cases, no. This usually leads to those "mysterious" bugs that show up when

    baud rates, cpu clocks, etc. change.

    > What are the common guideline when dealing with data synchronization

    > in ISRs for Nios ?

    Here&#39;s a good reference: http://www.xml.com/ldd/chapter/book/ch09.html#t8 (http://www.xml.com/ldd/chapter/book/ch09.html#t8)

    A very simple and common technique is to use a circular buffer. The size of the buffer can

    be adjusted to meet your requirements ... provided you have adequate memory resources.

    Here&#39;s a basic overview:

    1. The isr reads a "put" pointer, and writes its data. Then updates the put pointer.

    2. The app compares the put pointer to a "get" pointer, when unequal, there is data.

    3. The app reads (copies, consumes, whatever) the data, then updates the get pointer.

    Regards,

    --Scott
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    The circular buffer is indeed useful, implementing a FIFO in software. I wanted, however, to avoid it and use something simpler, as I don&#39;t need a FIFO. I can, however, use a "trivial" FIFO which has depth 1 and "loses" all subsequent packets until the old ones has been read.

    Which brings me to the question - are variable assignment and test atomic in Nios ? What I mean is:

    int ready;
    // is this atomic ?
    ready = 1;
    // and is this atomic 
    if (ready == 1)
    {
     ...
    }

    I ask because I can make my main code "deassert" the &#39;ready&#39; flag when it finished reading the packet, and the ISR to ignore a new packet if &#39;ready&#39; is still asserted. This way no stomping occurs (overflow messages are lost, which is acceptable). So I wonder whether it&#39;s possible for the ISR to run in the middle of asserting &#39;ready&#39; ? If "ready = 1" is atomic, it certainly can&#39;t.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Don&#39;t forget to specify variables as "volatile" to prevent them being optimised out.

    Sometimes I do tricks such as implementing S/R Flip Flops or counters in hardware, with different memory addresses to set/reset increment/decrement/read them.

    For simple FIFO buffers I&#39;ll do e.g. "ISR owns write pointer", "main thread owns read pointer" as Scott says.

    I will also use a "main thread is using this" flag as you&#39;ve suggested. So

    //shared
    volatile int MT_Access;
    //main thread
    MT_Access = 1;
    <do something>
    MT_Access = 0;
    //ISR
    if (0 == MT_Access)
    {
    <update something>
    }