[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-gcc-list] About context saving in Vectors

From: David Kelly
Subject: Re: [avr-gcc-list] About context saving in Vectors
Date: Wed, 14 Jan 2009 19:22:19 -0600

On Jan 14, 2009, at 5:58 PM, Daniel O'Connor wrote:

On Thursday 15 January 2009 04:15:14 Dave Hylands wrote:

And here's some code that implements such a ring buffer. As David
Kelly points out, as long as the index type is uint8_t, then nothing
special is required (which for this particular implementation means
that buffers upto 128 entries would be supported)

<http://websvn.hylands.org/filedetails.php?repname=Projects&path=%2Fcommon%2FCBUF.h&rev=0&sc=0 >

It's important that the queue be declared volatile (as myQ is in the

And I was just about to ask if someone could post some well tested code! :)

You will notice Dave Hyland's code is C++.

This is how I did it recently for an AVR usart in plain C. Notice I wrapped the indexes using a bitwise AND. That isn't always as efficient as it might seem.

The indexes are named hd and tl, head and tail, as in "food goes in the head and comes out the tail."

None of these funtions loop, so the indexes do not need to be declared volatile.

struct {
        uint8_t        hd, tl;
uint8_t buf[(1<<4)]; // (1<<4) is 16, must be power of two for wrap
} incoming;

struct {
        uint8_t hd, tl;
uint8_t buf[(1<<6)]; // (1<<6) is 64, must be power of two for wrap
} outgoing;

//      Incoming character
if ( UCSR0A & ((1<<FE0)|(1<<DOR0)|(1<<UPE0)) ) { // if error UDR0; // discard
        } else {
incoming.buf[incoming.hd] = UDR0; // reading clears IRQ incoming.hd = (incoming.hd + 1) & (sizeof(incoming.buf)-1);

//      Transmit complete, ready for another.
// USART0_TX_vect says all the buffers are empty, which we don't care.
//      USART0_UDRE_vect tells us when its ready to send another.
        if( outgoing.hd == outgoing.tl ) {
                UCSR0B &= ~(1<<UDRIE0);         //  disable this IRQ
        } else {
                UDR0 = outgoing.buf[outgoing.tl++];
                outgoing.tl &= ~(sizeof(outgoing.buf));
if( outgoing.hd == outgoing.tl ) // anticipate followup IRQ that just disables UCSR0B &= ~(1<<UDRIE0); // disable this IRQ

//      Return a character from incoming buffer, or -1 for empty
        int c;

        if( incoming.hd == incoming.tl )
        c = (unsigned)incoming.buf[incoming.tl];
incoming.tl = (incoming.tl + 1) & 0x0f; // increment and wrap

//      Put character in outgoing buffer. Enable UDRIE0 if not already.
//      Calling routines may disable IRQ so as to prevent the data
//      they are sending from changing before its sent, so we have to
//      preserve the interrupt bit in SREG.
// UDRE0 should be set whenever there is space in the TX buffer for more.
//      Setting UDRIE0 should trigger USART0_UDRE_vect immediately.
//      No protection provided against over filling the buffers.
my_putchar(uint8_t c)
        uint8_t sreg;

        sreg = SREG;    //  save IRQ status, costs almost nothing
cli(); // don't want illegal outgoing.hd during an IRQ

        //  Put it in the queue/buffer
        outgoing.buf[outgoing.hd++] = c;
outgoing.hd &= ~(sizeof(outgoing.buf)); // make it legal

// UDR0 is double-buffered so 2 characters can be handled instantly // leaving IRQ disabled which would force this data to split across hops. if( radio_hop < 3 ) // (re)start now if this is a clean hop
                UCSR0B |= (1<<UDRIE0);  //  enable USART0_UDRE_vect

        SREG = sreg;    //  restore prior IRQ enable/disable

//      Rather than put the outgoing struct in externally visible space,
//      provide a routine to compare head and tail.
//      Then expand it with many other conditions.  :-(
return( (outgoing.hd == outgoing.tl) // buffer is empty && ((RF_CTS_I & (1<<RF_CTS_B)) == 0) // radio is not asking us to stop

David Kelly N4HHE, address@hidden
Whom computers would destroy, they must first drive mad.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]