Safe way to write interrupt driven circular buffer tx rx?

Can someone point out source code for a safe circular buffer receiver transmitter? It's for sending and receiving bytes via RS232.

Reply to
Sven
Loading thread data ...

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.

Reply to
cs_posting

My circular buffer implementation for i8096 ( C source ) can be viewed at

formatting link

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

Reply to
msg

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)
Reply to
David T. Ashley

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

Reply to
Stefan Reuther

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

Reply to
Dave Hansen

/ *-------------------------------------------------------------------------- * 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

Reply to
joe4702

You can find source code for a library using queues and interrupts to receive UART data on a 68K system at:

formatting link

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

Reply to
Mark Borgerson

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]; } }

And don't forget the 'volatile' qualifiers and, if you're doing a multi-core application, the memory barriers.

Stefan

Reply to
Stefan Reuther

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.