From 01261ca1b54c046081d47ecf2fc321ebf2cc94b4 Mon Sep 17 00:00:00 2001 From: Mika Tuupola Date: Sat, 17 Dec 2011 19:10:24 +0200 Subject: [PATCH] Add UART library. --- tpic6b595_spi/uart/uart.c | 74 +++++++++++++++++++++ tpic6b595_spi/uart/uart.h | 17 +++++ tpic6b595_spi/uart/uart_async.c | 112 ++++++++++++++++++++++++++++++++ 3 files changed, 203 insertions(+) create mode 100644 tpic6b595_spi/uart/uart.c create mode 100644 tpic6b595_spi/uart/uart.h create mode 100644 tpic6b595_spi/uart/uart_async.c diff --git a/tpic6b595_spi/uart/uart.c b/tpic6b595_spi/uart/uart.c new file mode 100644 index 0000000..a6e869f --- /dev/null +++ b/tpic6b595_spi/uart/uart.c @@ -0,0 +1,74 @@ +/* + * Copyright 2011 Mika Tuupola + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + * + */ + +#include +#include + +#ifndef F_CPU +#define F_CPU 16000000UL +#endif + +#ifndef BAUD +#define BAUD 9600 +#endif +#include + +/* http://www.cs.mun.ca/~rod/Winter2007/4723/notes/serial/serial.html */ + +#if defined (__AVR_ATmega32U4__) +void uart_init(void) { + UBRR1H = UBRRH_VALUE; + UBRR1L = UBRRL_VALUE; + +#if USE_2X + UCSR1A |= _BV(U2X1); +#else + UCSR1A &= ~(_BV(U2X1)); +#endif + + UCSR1C = _BV(UCSZ11) | _BV(UCSZ10); /* 8-bit data */ + UCSR1B = _BV(RXEN1) | _BV(TXEN1); /* Enable RX and TX */ +} +#else +void uart_init(void) { + UBRR0H = UBRRH_VALUE; + UBRR0L = UBRRL_VALUE; + +#if USE_2X + UCSR0A |= _BV(U2X0); +#else + UCSR0A &= ~(_BV(U2X0)); +#endif + + UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */ + UCSR0B = _BV(RXEN0) | _BV(TXEN0); /* Enable RX and TX */ +} +#endif + +void uart_putchar(char c, FILE *stream) { + if (c == '\n') { + uart_putchar('\r', stream); + } +#if defined (__AVR_ATmega32U4__) + loop_until_bit_is_set(UCSR1A, UDRE1); + UDR1 = c; +#else + loop_until_bit_is_set(UCSR0A, UDRE0); + UDR0 = c; +#endif +} + +char uart_getchar(FILE *stream) { +#if defined (__AVR_ATmega32U4__) + loop_until_bit_is_set(UCSR1A, RXC1); + return UDR1; +#else + loop_until_bit_is_set(UCSR0A, RXC0); + return UDR0; +#endif +} diff --git a/tpic6b595_spi/uart/uart.h b/tpic6b595_spi/uart/uart.h new file mode 100644 index 0000000..ce87030 --- /dev/null +++ b/tpic6b595_spi/uart/uart.h @@ -0,0 +1,17 @@ +/* + * Copyright 2011 Mika Tuupola + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + * + */ + +void uart_putchar(char c, FILE *stream); +char uart_getchar(FILE *stream); + +void uart_init(void); + +/* http://www.ermicro.com/blog/?p=325 */ + +FILE uart_output = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); +FILE uart_input = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_READ); diff --git a/tpic6b595_spi/uart/uart_async.c b/tpic6b595_spi/uart/uart_async.c new file mode 100644 index 0000000..b2d4cc4 --- /dev/null +++ b/tpic6b595_spi/uart/uart_async.c @@ -0,0 +1,112 @@ +/* + * Copyright 2011 Mika Tuupola + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + * + */ + +/* Based on Atmel Application Note AVR 306 */ + +#include +#include +#include + +#ifndef BAUD +#define BAUD 9600 +#endif +#include + +#ifndef UART_RX_BUFFER_SIZE +#define UART_RX_BUFFER_SIZE 64 +#endif + +#ifndef UART_TX_BUFFER_SIZE +#define UART_TX_BUFFER_SIZE 64 +#endif + +struct tx_ring { + int buffer[UART_TX_BUFFER_SIZE]; + int start; + int end; +}; + +struct rx_ring { + int buffer[UART_RX_BUFFER_SIZE]; + int start; + int end; +}; + +static struct tx_ring tx_buffer; +static struct rx_ring rx_buffer; + +/* http://www.cs.mun.ca/~rod/Winter2007/4723/notes/serial/serial.html */ + +void uart_init(void) { + + tx_buffer.start = 0; + tx_buffer.end = 0; + + rx_buffer.start = 0; + rx_buffer.end = 0; + + UBRR0H = UBRRH_VALUE; + UBRR0L = UBRRL_VALUE; + + UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */ + UCSR0B = _BV(RXEN0) | _BV(TXEN0); /* Enable RX and TX */ + + sei(); +} + + +//int uart_putchar(char c, FILE *stream) { +void uart_putchar(char c, FILE *stream) { + if (c == '\n') { + uart_putchar('\r', stream); + } + + int write_pointer = (tx_buffer.end + 1) % UART_TX_BUFFER_SIZE; + + if (write_pointer != tx_buffer.start){ + tx_buffer.buffer[tx_buffer.end] = c; + tx_buffer.end = write_pointer; + + /* Data available. Enable the transmit interrupt for serial port 0. */ + UCSR0B |= _BV(UDRIE0); + } + + //return 0; +} + +char uart_getchar(FILE *stream) { + int read_pointer = (rx_buffer.start + 1) % UART_RX_BUFFER_SIZE; + + rx_buffer.start = read_pointer; + return rx_buffer.buffer[read_pointer]; +} + +ISR(USART_RX_vect) { + int write_pointer = (rx_buffer.end + 1) % UART_RX_BUFFER_SIZE; + + /* Add next byte to ringbuffer if it has space available. */ + if (write_pointer != rx_buffer.start){ + rx_buffer.buffer[rx_buffer.end] = UDR0; + rx_buffer.end = write_pointer; + } +} + +ISR(USART_UDRE_vect){ + int read_pointer = (tx_buffer.start + 1) % UART_TX_BUFFER_SIZE; + + /* Transmit next byte if data available in ringbuffer. */ + if (read_pointer != tx_buffer.end) { + UDR0 = tx_buffer.buffer[read_pointer]; + tx_buffer.start = read_pointer; + } else { + /* Nothing to send. Disable the transmit interrupt for serial port 0. */ + UCSR0B &= ~_BV(UDRIE0); + } +} + +