[ create a new paste ] login | about

Link: http://codepad.org/Typ1kND2    [ raw code | fork ]

C, pasted on Jan 25:
#include <stdint.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/cpufunc.h>
#include <util/delay.h>

#define UART_RXBUF_SZ 32 //receive and transmit buffer sizes
#define UART_TXBUF_SZ 32
#define UART_RXBUF_MASK (UART_RXBUF_SZ - 1) //buffer index bitmasks for
#define UART_TXBUF_MASK (UART_TXBUF_SZ - 1) //  cheap modulo operation

static uint8_t rxbuf[UART_RXBUF_SZ]; //receive ring buffer
static uint8_t txbuf[UART_TXBUF_SZ]; //transmit ring buffer


volatile uint8_t rx_count = 0; //number of bytes in receive buffer
volatile uint8_t tx_count = 0; //number of bytes in transmit buffer

ISR(USART_UDRE_vect) //data register empty - can add next char to be transmitted
{
        static uint8_t tx_cons_ind; //uart_recv() gets next byte(s) from this index
        if (tx_count) { //more data to be transmitted
                UDR = txbuf[tx_cons_ind++ & UART_TXBUF_MASK];
                tx_count--;
        } else
                UCSRB &= ~(1<<UDRIE); //no more data - disable this interrupt
}

ISR(USART_RXC_vect) //incoming data, put into receive buffer
{
        static uint8_t rx_prod_ind; //receiver ISR stores next byte at this index
        rxbuf[rx_prod_ind++ & UART_RXBUF_MASK] = UDR;

        if (++rx_count > UART_RXBUF_SZ)
                rx_count = UART_RXBUF_SZ; //overflow, data has been overwritten
}

uint8_t //read at most `num` bytes from recv buffer into `data`, return num read
uart_recv(uint8_t *data, uint8_t num)
{
        static uint8_t rx_cons_ind; //transmitter ISR transmits byte at this index next
        uint8_t numgot = 0; //count how many bytes we got so far
        uint8_t rxcnt = rx_count; //cache volatile

        while(rxcnt > 0 && numgot < num) {
                data[numgot++] = rxbuf[rx_cons_ind++ & UART_RXBUF_MASK];
                rxcnt--;
        }

        cli();
        rx_count -= numgot;//rx_count = rxcnt would be wrong
        sei();

        return numgot;
}

uint8_t //buffer up to `num` bytes for transmit, return num. actually buffered
uart_send(uint8_t *data, uint8_t num)
{
        static uint8_t tx_prod_ind; //uart_send() queues next  byte(s) at this index
        uint8_t numput = 0; //count how many bytes we processed so far
        uint8_t txcnt = tx_count; //cache volatile
        while(num-- && txcnt < UART_TXBUF_SZ) {
                txbuf[tx_prod_ind++ & UART_TXBUF_MASK] = *data++;
                numput++;
                txcnt++;
        }

        cli();
        tx_count += numput;
        sei();

        UCSRB |= (1<<UDRIE); //enable interrupt so that transmission starts
        return numput;
}

int
main(void)
{
        uint16_t ubrr = 25; //38400 baud @ 16MHz clock
        UBRRH = (uint8_t)(ubrr>>8); //initialize uart 
        UBRRL = (uint8_t)ubrr;
        UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // frame format: 8N1

        DDRC = (1<<DDC7); // a debug led

        for(int x = 0; x < 3; x++) { //flash the led to indicate startup
                PORTC ^= (1<<PORTC7); _delay_ms(500);
                PORTC ^= (1<<PORTC7); _delay_ms(100);
        }

        UCSRB = (1<<TXEN)|(1<<UDRIE)|(1<<RXEN)|(1<<RXCIE); // usart enable
        sei();

        uint8_t buf[32];
        for(;;) { //now just read...
                uint8_t n = uart_recv(buf, sizeof buf);
                if (n) //...and echo back
                        uart_send(buf, n);
        }
}


Create a new paste based on this one


Comments: