Page 1 of 1

Example circular buffer

PostPosted: Fri Mar 06, 2015 11:36 pm
by ric
I posted this code in answer to a question on the MCHIP forum about how to implement a circular buffer.
This example creates a 16 byte buffer for receiving characters using an interrupt service. I don't show the ISR, just a routine called from it (or embedded in it)

I'm posting it here to save time in future. Feel free to post suggestions, improvements, or bugs!

Code: Select all
volatile char comin_wptr;    //write pointer. Is changed inside an interrupt
char comin_rptr;    //read pointer
char comin_buf[16];  //input data buffer
#define BUFFER_MASK 0x0f    //mask to force pointers to wrap after 16
 
void com_init(void)
{
    comin_wptr=0;
    comin_rptr=0;
    //code here to set baud rate, enable serial port, and enable receive interrupts
}
 
//call from USART RX interrupt (or embed inside the ISR)
void comin_put (char dat)
{
    if (((comin_rptr - comin_wptr) & BUFFER_MASK) != 1)    //test if the write pointer is about to hit the read ppinter
    {    //here if there is room in the buffer
        comin_buf[comin_wptr++]=dat;    //add character to buffer, and bump write pointer
        comin_wptr &= BUFFER_MASK;    //force pointer to wrap
    } else
    {    //buffer is full
        //add code here to drop hardware handshaking, or set a flag saying "buffer overflow"
    }
}
 
//fetch the next character from the buffer. Return zero if buffer empty
char comin_get(void)
{
    char temp;    //temp scratch
    if (comin_wptr == comin_rptr)
        return 0;    //if we are called when there is nothing ready
    temp = comin_buf[comin_rptr++];    //fetch character from buffer, and bump read pointer
    comin_rptr &= BUFFER_MASK;    //force pointer to wrap at 16
    return temp;    //return the value we read from the buffer
}
 
//return 0 (false) if buffer empty, or 1 (true) if there is some data in the buffer
bit comin_ready(void)
{
    if ((comin_wptr == comin_rptr)
        return 0;    //buffer is empty
    return 1;    //buffer contains data
}

Re: Example circular buffer

PostPosted: Wed Mar 11, 2015 11:59 am
by vloki
I'm using a simple stack buffer to avoid the more complex pointer handling.
In fact it is rare that the stack really has to be shifted because the incoming
bytes usually get processed fast enough.

Looks like this:
Code: Select all
struct s_rxBuffer{                      // receiver buffer
    unsigned char idx;
    unsigned char bytes[MAX_RX_BUFFER];
};

in interrupt:
Code: Select all
    if (USART_IR) // -------------------------------------------------- USART_IR
    {
        if (RCSTA1bits.OERR) // check overflow error
        {  ...    return; }
        if (RCSTA1bits.FERR) // check framing error
        {  ...    return; }

        if (DataRdy1USART()){ //-------------------- new byte received ###
            if(rxBuffer.idx < MAX_RX_BUFFER){
               rxBuffer.bytes[rxBuffer.idx++] = RCREG;
            }
            else{
                ...
                status.rxOVF = 1;
            }
        }
        return;//IR_USART
    }

in main loop:
Code: Select all
        if(rxBuffer.idx){           //###TODO### ERROR overflow !!!
            mUSART_IR_DIS();
            RXbyteImport(rxBuffer.bytes[0]);  //function to process incoming bytes
            rxBuffer.idx--;
            for(i=0;i<=rxBuffer.idx;i++){
                 rxBuffer.bytes[i] = rxBuffer.bytes[i+1];
            }
            mUSART_IR_EN();
//            status.rxOVF = 0;
        }