1. This forum section is a read-only archive which contains old newsgroup posts. If you wish to post a query, please do so in one of our main forum sections (here). This way you will get a faster, better response from the members on Motherboard Point.

Safe way to write interrupt driven circular buffer tx rx?

Discussion in 'Embedded' started by Sven, Aug 29, 2007.

  1. Sven

    Sven Guest

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

  2. Sven

    cs_posting Guest

    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.
     
    cs_posting, Aug 29, 2007
    #2
    1. Advertisements

  3. Sven

    msg Guest

    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
     
    msg, Aug 29, 2007
    #3
  4. 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, Aug 29, 2007
    #4
  5. 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
     
    Stefan Reuther, Aug 29, 2007
    #5
  6. Sven

    Dave Hansen Guest

    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
     
    Dave Hansen, Aug 29, 2007
    #6
  7. Sven

    joe4702 Guest

    /
    *--------------------------------------------------------------------------
    * 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
     
    joe4702, Aug 29, 2007
    #7
  8. 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
     
    Mark Borgerson, Aug 30, 2007
    #8
  9. 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
     
    Stefan Reuther, Aug 30, 2007
    #9
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.