Forum Discussion
Altera_Forum
Honored Contributor
20 years agoSynchronizing 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.gif3 Replies
- Altera_Forum
Honored 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's usually not a single "best way". > Is disabling interrupts during the main'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'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'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
Honored 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'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:
I ask because I can make my main code "deassert" the 'ready' flag when it finished reading the packet, and the ISR to ignore a new packet if 'ready' is still asserted. This way no stomping occurs (overflow messages are lost, which is acceptable). So I wonder whether it's possible for the ISR to run in the middle of asserting 'ready' ? If "ready = 1" is atomic, it certainly can't.int ready; // is this atomic ? ready = 1; // and is this atomic if (ready == 1) { ... } - Altera_Forum
Honored Contributor
Don'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'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'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> }