avr-gcc-list
[Top][All Lists]
Advanced

[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
sample).

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
//
ISR(USART0_RX_vect)
{
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.
//
ISR(USART0_UDRE_vect)
{
        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
my_getchar(void)
{
        int c;

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

//
//      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.
//
void
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.  :-(
//
uint8_t
usart_tx_empty(void)
{
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]