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

## 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
```        );
}

--