EmbeddedRelated.com
Forums

Safe way to write interrupt driven circular buffer tx rx?

Started by Sven August 29, 2007
Can someone point out source code for a safe circular buffer receiver 
transmitter? It's for sending and receiving bytes via RS232.




On Aug 29, 8:21 am, "Sven" <S...@tim.com> wrote:
> Can someone point out source code for a safe circular buffer receiver > transmitter? It's for sending and receiving bytes via RS232.
What I do is let the interrupt process freely modify the buffer count & head variables. The interruptible process modifies the buffer variables in only one small block of code, which is bracketed with interrupt disable & enable instructions. Even if your UART only offers a simple result register for the receive, you should be able to execute the non-interruptible section, and then the interrupt, fast enough to not miss data at 115200 baud.
Sven wrote:

> Can someone point out source code for a safe circular buffer receiver > transmitter? It's for sending and receiving bytes via RS232. >
My circular buffer implementation for i8096 ( C source ) can be viewed at http://www.cybertheque.org/homebrew/hmi-200 The ICE is currently not powered up, but on request I will do so. You can still inspect source code and compile it however. Look for programs with 'buffered' and 'serial' in their titles on the 'compile' page and in the 'ucos-compile' page. Regards, Michael
<cs_posting@hotmail.com> wrote in message 
news:1188395695.412412.51620@w3g2000hsg.googlegroups.com...
> On Aug 29, 8:21 am, "Sven" <S...@tim.com> wrote: >> Can someone point out source code for a safe circular buffer receiver >> transmitter? It's for sending and receiving bytes via RS232. > > What I do is let the interrupt process freely modify the buffer count > & head variables. > > The interruptible process modifies the buffer variables in only one > small block of code, which is bracketed with interrupt disable & > enable instructions.
Just be aware that the critical section protocol depends on the "design rules" for the entire embedded project. The most common set of design rules is that for critical sections, interrupts are disabled and enabled. The assumption is that the critical sections will be short enough that they won't introduce any real-time difficulties with the invocation of ISRs. However, in some rare cases, someone may decide that a critical section should block only interrupts of a certain type, but allow others. The "design rules" might call for manipulating the only the SCI hardware to implement the critical section, and only to prevent SCI interrupts. The DI()/EI() protocol is not universally applicable, but it is nearly so. Dave. -- David T. Ashley (dta@e3ft.com) http://www.e3ft.com (Consulting Home Page) http://www.dtashley.com (Personal Home Page) http://gpl.e3ft.com (GPL Publications and Projects)
cs_posting@hotmail.com wrote:
> On Aug 29, 8:21 am, "Sven" <S...@tim.com> wrote: >>Can someone point out source code for a safe circular buffer receiver >>transmitter? It's for sending and receiving bytes via RS232. > > What I do is let the interrupt process freely modify the buffer count > & head variables. > > The interruptible process modifies the buffer variables in only one > small block of code, which is bracketed with interrupt disable & > enable instructions.
You can avoid that interrupt disable by using head and tail variables instead of head and count. The interrupt would then modify only the head (and read the tail to check for overflow), the interruptible process would modify only the tail (and read the head to check whether anything is in the buffer). Stefan
On Aug 29, 11:54 am, Stefan Reuther <stefan.n...@arcor.de> wrote:
> cs_post...@hotmail.com wrote: > > On Aug 29, 8:21 am, "Sven" <S...@tim.com> wrote: > >>Can someone point out source code for a safe circular buffer receiver > >>transmitter? It's for sending and receiving bytes via RS232. > > > What I do is let the interrupt process freely modify the buffer count > > & head variables. > > > The interruptible process modifies the buffer variables in only one > > small block of code, which is bracketed with interrupt disable & > > enable instructions. > > You can avoid that interrupt disable by using head and tail variables > instead of head and count. The interrupt would then modify only the head > (and read the tail to check for overflow), the interruptible process > would modify only the tail (and read the head to check whether anything > is in the buffer).
This is the way I do it. A couple small things to watch: 1) You must _always_ have at least one empty slot in your buffer. You can probably figure out why for yourself (hint: what does head==tail mean?). 2) You can avoid critical sections (e.g., disabling interrupts) only if access to the head and tail variables is atomic. For example, if head and tail are 16 bits wide, and you're running on an AVR or 8051, you'll still have to protect access to the variables in your main-line code. 3) Even if access to the head an tail variables is atomic, you must still be careful about how you order your code. Always check the full/ empty status first. Then copy the data. Update the index last. Regards, -=Dave
On Aug 29, 6:21 am, "Sven" <S...@tim.com> wrote:
> Can someone point out source code for a safe circular buffer receiver > transmitter? It's for sending and receiving bytes via RS232.
/ *-------------------------------------------------------------------------- * Filename: queue.h * * Description: Generic circular queue macros * * Notes * * The queue macros are safe when used in producer/consumer fashion. * User must check queue full/empty conditions prior to enqueuing/ * dequeueing. * * Example Usage * * #include "queue.h" * * #define MY_Q_SIZE 10 * * struct * { * queue_hdr_t hdr; // must be named "hdr" * my_type_t items[MY_Q_SIZE+1]; // must be named "items", 1 space wasted * } my_q; * * my_type_t an_item; * * QUEUE_INIT(my_q); * * if (!QUEUE_FULL(q)) * { * QUEUE_PUT(my_q,an_item); * } * * if (!QUEUE_EMPTY(q)) * { * QUEUE_GET(my_q,an_item); * } * -------------------------------------------------------------------------- */ #ifndef __QUEUE_H__ #define __QUEUE_H__ /*-------------------------------- Includes --------------------------------*/ #include "types.h" /*---------------------------- Defines & Types -----------------------------*/ #define QUEUE_INIT(q) \ q.hdr.front = q.hdr.rear = 0; \ q.hdr.size = sizeof(q.items) / sizeof(q.items[0]); #define QUEUE_PUT(q,item) \ q.items[q.hdr.rear] = item; \ q.hdr.rear = (q.hdr.rear+1) % q.hdr.size; #define QUEUE_GET(q,item) \ item = q.items[q.hdr.front]; \ q.hdr.front = (q.hdr.front + 1) % q.hdr.size; #define QUEUE_FRONT(q,item) \ item = q.items[q.hdr.front] #define QUEUE_EMPTY(q) (q.hdr.front == q.hdr.rear) #define QUEUE_FULL(q) ((q.hdr.rear + 1) % q.hdr.size == q.hdr.front) /* Private - do not access directly */ typedef struct { int front; int rear; int size; } queue_hdr_t; /*---------------------------- Global Variables ----------------------------*/ /*--------------------------- Function Prototypes --------------------------*/ #endif
In article <46d572d6$0$90271$14726298@news.sunsite.dk>, Sven@tim.com 
says...
> Can someone point out source code for a safe circular buffer receiver > transmitter? It's for sending and receiving bytes via RS232. > >
You can find source code for a library using queues and interrupts to receive UART data on a 68K system at: http://www.oes.to/u4scfxlib.zip It may not be the best code out there, but I haven't had to make any major changes in about 5 years now, and my customers indicate that it does the job for them. If you have particular questions, send me an email. Mark Borgerson
Dave Hansen wrote:
> On Aug 29, 11:54 am, Stefan Reuther <stefan.n...@arcor.de> wrote: >>cs_post...@hotmail.com wrote: >>>The interruptible process modifies the buffer variables in only one >>>small block of code, which is bracketed with interrupt disable & >>>enable instructions. >> >>You can avoid that interrupt disable by using head and tail variables >>instead of head and count. The interrupt would then modify only the head >>(and read the tail to check for overflow), the interruptible process >>would modify only the tail (and read the head to check whether anything >>is in the buffer). > > This is the way I do it. A couple small things to watch: > > 1) You must _always_ have at least one empty slot in your buffer. You > can probably figure out why for yourself (hint: what does head==tail > mean?).
If the number of slots is a power of two, and your head/tail variables have more bits than needed to represent the number of slots, you can also use the final slot. Quick&dirty: #define N 128 volatile unsigned int head, tail; volatile char buffer[N]; unsigned int inuse() { return head - tail; } void put(char c) { if (inuse() != N) { buffer[head++%N] = c; } } void get(char* c) { if (inuse() != 0) { *c = buffer[tail++%N]; } }
> 2) You can avoid critical sections (e.g., disabling interrupts) only > if access to the head and tail variables is atomic. For example, if > head and tail are 16 bits wide, and you're running on an AVR or 8051, > you'll still have to protect access to the variables in your main-line > code. > > 3) Even if access to the head an tail variables is atomic, you must > still be careful about how you order your code. Always check the full/ > empty status first. Then copy the data. Update the index last.
And don't forget the 'volatile' qualifiers and, if you're doing a multi-core application, the memory barriers. Stefan