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

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

Re: [avr-gcc-list] Problems with ATMEGA8 USART


From: David Kelly
Subject: Re: [avr-gcc-list] Problems with ATMEGA8 USART
Date: Sat, 13 Aug 2005 19:35:59 -0500


On Aug 13, 2005, at 3:08 PM, juan antonio jimenez martinez wrote:

Hi, Im experimenting some details setting the ATMEGA8 usart, for example, I have an interrupt driven routine for receiving data, may problem is how can I clean the buffer in orther to let it ready for the next reception, I mean, when I send two chars from my computer to the ATMEGA, the interrupt routine do what I want , but when I send 10 chars, the buffer that I use to read the incomming data, reads the two chars that I have send before plus the new data and as a result I got the 10 chars message incomplete due the two chars that I have sent before

I hope some one know an answer, because I have tryed with the RXC flag and it seems not work, or how can I select the sise in bytes to read at one time, and again flush all the RX usart buffers

You need to learn the basics of a circular buffer. Set aside a buffer which will not be used by anything other than the receive side of the serial port. Use two indexes into this buffer, I like to call them "head" and "tail". Think of it as "food goes in at the head, comes out the tail end."

In RX IRQ always write the character in the buffer at head then increment head. The IRQ routine never touches tail.

Outside of IRQ if head != tail then read the character at tail and increment tail. Never change head outside of IRQ.

When either index is incremented beyond the size of your buffer, reset that index to 0. A quick way to do this is to use a buffer size which is a power of 2, then mask the index after incrementing.

#define BUFFER_SIZE (1<<5)    //  16
volatile uint8_t buffer[BUFFER_SIZE];
volatile uint8_t head;
uint8_t tail;

int my_getchar()
{
    int c = -1;        //  preset with error condition

    if( head != tail ) {
        c = buffer[tail++];
        tail &= (BUFFER_SIZE-1);    //  0x0f if BUFFER_SIZE is 16
    }
    return(c);
}

For advanced discussion one would probably wish to put the buffer and its indexes into a struct so that its obvious to future generations maintaining your code that the indexes and buffer belong together. Doesn't make code size one iota bigger:

struct {
    uint8_t tail;
    volatile uint8_t head, buffer[BUFFER_SIZE];
} uart0;

Next, a purist might insist head and buffer should be volatile as they are modified within IRQ. Volatile does not hurt anything in this case but doesn't help unless my_getchar() is inlined and used within a loop waiting for input. Avr-gcc is capable of inline functions so I used volatile.

If tail were volatile then it would have to be read for the index and increment, and read again to be masked. Not volatile, the compiler can use the copy of tail already in its registers and write only after it has no more use of it.

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