From fca9b8f07acbd2cf5f6cbedf851ad86f689fde7f Mon Sep 17 00:00:00 2001 From: Christian Kroll Date: Sat, 16 Aug 2014 07:01:07 +0200 Subject: [PATCH] UART support for Borg16; using Peter Fleury's UART library --- config.in | 5 + profiles/CTDO-Borg | 162 +++++++ src/borg_hw/config_borg16.in | 13 + src/main.c | 13 +- src/uart/Makefile | 16 + src/uart/config.in | 1 + src/uart/uart.c | 809 ++++++++++++++++++++++++++++------- src/uart/uart.h | 232 ++++++++-- src/uart/uart_commands.c | 114 +++++ src/uart/uart_commands.h | 13 + src/util.c | 7 + 11 files changed, 1203 insertions(+), 182 deletions(-) create mode 100644 profiles/CTDO-Borg create mode 100644 src/uart/Makefile create mode 100644 src/uart/config.in create mode 100644 src/uart/uart_commands.c create mode 100644 src/uart/uart_commands.h diff --git a/config.in b/config.in index 6ed2601..ba0085d 100644 --- a/config.in +++ b/config.in @@ -62,6 +62,11 @@ source src/can/config.in ############################################################################### +### UART Menu ################################################################# +source src/uart/config.in +############################################################################### + + ### Borg Menu ################################################################# dep_bool "Menu Support" MENU_SUPPORT $JOYSTICK_SUPPORT depends on JOYSTICK_SUPPORT diff --git a/profiles/CTDO-Borg b/profiles/CTDO-Borg new file mode 100644 index 0000000..a218ab5 --- /dev/null +++ b/profiles/CTDO-Borg @@ -0,0 +1,162 @@ +# +# Automatically generated by make menuconfig: don't edit +# + +# +# General Setup +# +MCU=atmega644 +FREQ=16000000 + +# +# Borg Hardware +# +NUM_ROWS=16 +NUM_COLS=16 +NUMPLANE=3 +BORG_HW=HW_BORG_16 + +# +# Borg16 port setup +# +UART_SUPPORT=y +UART_BAUDRATE_SETTING=19200 +COLPORT1=PORTC +COLPORT2=PORTA +ROWPORT=PORTD +PIN_MCLR=4 +PIN_CLK=6 +PIN_DATA=7 +# REVERSE_COLS is not set +# INVERT_ROWS is not set +# INTERLACED_ROWS is not set +# INTERLACED_COLS is not set + +# +# Features +# +RANDOM_SUPPORT=y +# LAP_TIME_EXTENSION is not set +SCROLLTEXT_SUPPORT=y +SCROLLTEXT_FONT=FONT_ARIAL8 +SCROLLTEXT_BUFFER_SIZE=128 +SCROLL_X_SPEED=20 +SCROLL_Y_SPEED=20 +SCROLLTEXT_TEXT=" #include +#include #include #include "config.h" @@ -19,6 +20,10 @@ #include "can/borg_can.h" #endif +#ifdef UART_SUPPORT +# include "uart/uart.h" +#endif + #ifdef RFM12_SUPPORT #include "rfm12/borg_rfm12.h" #endif @@ -41,12 +46,12 @@ int main (void){ bcan_init(); #endif -#ifdef JOYSTICK_SUPPORT - joy_init(); +#ifdef UART_SUPPORT + uart_init(UART_BAUD_SELECT(UART_BAUDRATE_SETTING, F_CPU)); #endif -#ifdef UART_SUPPORT - uart_init(); +#ifdef JOYSTICK_SUPPORT + joy_init(); #endif sei(); diff --git a/src/uart/Makefile b/src/uart/Makefile new file mode 100644 index 0000000..6fbb551 --- /dev/null +++ b/src/uart/Makefile @@ -0,0 +1,16 @@ +MAKETOPDIR = ../.. + +TARGET = libuart.a + +SRC_SIM := + +include $(MAKETOPDIR)/defaults.mk + +ifeq ($(UART_SUPPORT),y) + SRC = uart.c + SRC += uart_commands.c +endif + +include $(MAKETOPDIR)/rules.mk + +include $(MAKETOPDIR)/depend.mk diff --git a/src/uart/config.in b/src/uart/config.in new file mode 100644 index 0000000..27ddfd1 --- /dev/null +++ b/src/uart/config.in @@ -0,0 +1 @@ +# nothing for now \ No newline at end of file diff --git a/src/uart/uart.c b/src/uart/uart.c index c372ba2..4cce60d 100644 --- a/src/uart/uart.c +++ b/src/uart/uart.c @@ -1,188 +1,689 @@ -/* USART-Init beim ATmegaXX */ +/************************************************************************* +Title: Interrupt UART library with receive/transmit circular buffers +Author: Peter Fleury http://jump.to/fleury +File: $Id: uart.c,v 1.12 2014/01/08 21:58:12 peter Exp $ +Software: AVR-GCC 4.1, AVR Libc 1.4.6 or higher +Hardware: any AVR with built-in UART, +License: GNU General Public License +DESCRIPTION: + An interrupt is generated when the UART has finished transmitting or + receiving a byte. The interrupt handling routines use circular buffers + for buffering received and transmitted data. + The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define + the buffer size in bytes. Note that these variables must be a + power of 2. + +USAGE: + Refere to the header file uart.h for a description of the routines. + See also example test_uart.c. + +NOTES: + Based on Atmel Application Note AVR306 + +LICENSE: + Copyright (C) 2006 Peter Fleury + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*************************************************************************/ #include #include -#include - -#include "config.h" +#include #include "uart.h" -#ifdef ATMEGA128 -#define UCSRB UCSR0B -#define UCSRC UCSR0C -#define UDR UDR0 -#define UBRRH UBRR0H -#define UBRRL UBRR0L -#define URSEL UMSEL + +/* + * constants and macros + */ + +/* size of RX/TX buffers */ +#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1) +#define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1) + +#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK ) +#error RX buffer size is not a power of 2 +#endif +#if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK ) +#error TX buffer size is not a power of 2 +#endif + +#if defined(__AVR_AT90S2313__) \ + || defined(__AVR_AT90S4414__) || defined(__AVR_AT90S4434__) \ + || defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__) \ + || defined(__AVR_ATmega103__) + /* old AVR classic or ATmega103 with one UART */ + #define AT90_UART + #define UART0_RECEIVE_INTERRUPT UART_RX_vect + #define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect + #define UART0_STATUS USR + #define UART0_CONTROL UCR + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__) + /* old AVR classic with one UART */ + #define AT90_UART + #define UART0_RECEIVE_INTERRUPT UART_RX_vect + #define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \ + || defined(__AVR_ATmega323__) + /* ATmega with one USART */ + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT USART_RXC_vect + #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined (__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT USART_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega163__) + /* ATmega163 with one UART */ + #define ATMEGA_UART + #define UART0_RECEIVE_INTERRUPT UART_RX_vect + #define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega162__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT USART0_RXC_vect + #define UART1_RECEIVE_INTERRUPT USART1_RXC_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART1_RECEIVE_INTERRUPT USART1_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega161__) + /* ATmega with UART */ + #error "AVR ATmega161 currently not supported by this libaray !" +#elif defined(__AVR_ATmega169__) + /* ATmega with one USART */ + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega48__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) \ + || defined(__AVR_ATmega3250__) || defined(__AVR_ATmega3290__) ||defined(__AVR_ATmega6450__) || defined(__AVR_ATmega6490__) + /* ATmega with one USART */ + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT USART_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATtiny2313__) + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT USART_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega329__) || \ + defined(__AVR_ATmega649__) || \ + defined(__AVR_ATmega325__) || \ + defined(__AVR_ATmega645__) + /* ATmega with one USART */ + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega640__) +/* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART1_RECEIVE_INTERRUPT USART1_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega644__) + /* ATmega with one USART */ + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATmega164P__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT USART0_RX_vect + #define UART1_RECEIVE_INTERRUPT USART1_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect + #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1287__) + /* AT90USBxx with one USART */ + #define AT90USB_USART + #define UART0_RECEIVE_INTERRUPT USART1_RX_vect + #define UART0_TRANSMIT_INTERRUPT USART1_UDRE_vect + #define UART0_STATUS UCSR1A + #define UART0_CONTROL UCSR1B + #define UART0_DATA UDR1 + #define UART0_UDRIE UDRIE1 +#elif defined __AVR + #error "no UART definition for MCU available" #endif -#define UART_BAUD_CALC(UART_BAUD_RATE,F_OSC) ((F_OSC)/((UART_BAUD_RATE)*16L)) +/* + * module global variables + */ +static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE]; +static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE]; +static volatile unsigned char UART_TxHead; +static volatile unsigned char UART_TxTail; +static volatile unsigned char UART_RxHead; +static volatile unsigned char UART_RxTail; +static volatile unsigned char UART_LastRxError; - -#ifdef UART_INTERRUPT -volatile static char rxbuf[UART_RXBUFSIZE]; -volatile static char txbuf[UART_TXBUFSIZE]; -volatile static char *volatile rxhead, *volatile rxtail; -volatile static char *volatile txhead, *volatile txtail; - - -ISR(USART_UDRE_vect) { -#ifdef UART_LEDS - PORTC ^= 0x01; +#if defined( ATMEGA_USART1 ) +static volatile unsigned char UART1_TxBuf[UART_TX_BUFFER_SIZE]; +static volatile unsigned char UART1_RxBuf[UART_RX_BUFFER_SIZE]; +static volatile unsigned char UART1_TxHead; +static volatile unsigned char UART1_TxTail; +static volatile unsigned char UART1_RxHead; +static volatile unsigned char UART1_RxTail; +static volatile unsigned char UART1_LastRxError; #endif - - if ( txhead == txtail ) { - UCSRB &= ~(1 << UDRIE); /* disable data register empty IRQ */ - } else { - UDR = *txtail; /* schreibt das Zeichen x auf die Schnittstelle */ - if (++txtail == (txbuf + UART_TXBUFSIZE)) txtail = txbuf; - } -} -ISR(USART_RXC_vect) { - int diff; -#ifdef UART_LEDS - PORTC ^= 0x02; + +ISR (UART0_RECEIVE_INTERRUPT) +/************************************************************************* +Function: UART Receive Complete interrupt +Purpose: called when the UART has received a character +**************************************************************************/ +{ + unsigned char tmphead; + unsigned char data; + unsigned char usr; + unsigned char lastRxError; + + + /* read UART status register and UART data register */ + usr = UART0_STATUS; + data = UART0_DATA; + + /* */ +#if defined( AT90_UART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#elif defined( ATMEGA_USART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#elif defined( ATMEGA_USART0 ) + lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) ); +#elif defined ( ATMEGA_UART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#elif defined( AT90USB_USART ) + lastRxError = (usr & (_BV(FE1)|_BV(DOR1)) ); #endif - - /* buffer full? */ - diff = rxhead - rxtail; - if ( diff < 0 ) diff += UART_RXBUFSIZE; - if (diff < UART_RXBUFSIZE -1) { - // buffer NOT full - *rxhead = UDR; - if (++rxhead == (rxbuf + UART_RXBUFSIZE)) rxhead = rxbuf; - } else { - UDR; //reads the buffer to clear the interrupt condition - } + + /* calculate buffer index */ + tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK; + + if ( tmphead == UART_RxTail ) { + /* error: receive buffer overflow */ + lastRxError = UART_BUFFER_OVERFLOW >> 8; + }else{ + /* store new index */ + UART_RxHead = tmphead; + /* store received data in buffer */ + UART_RxBuf[tmphead] = data; + } + UART_LastRxError |= lastRxError; } -#endif // UART_INTERRUPT - -void uart_init() { - PORTD |= 0x01; //Pullup an RXD an - - UCSRA = 0; - UCSRB |= (1<>8); -// UBRRL=(uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)); - - UBRRL = 8; - -#ifdef UART_INTERRUPT - // init buffers - rxhead = rxtail = rxbuf; - txhead = txtail = txbuf; - - // activate rx IRQ - UCSRB |= (1 << RXCIE); -#endif // UART_INTERRUPT -} - -#ifdef UART_INTERRUPT -void uart_putc(char c) { - volatile int diff; - - /* buffer full? */ - do { - diff = txhead - txtail; - if ( diff < 0 ) diff += UART_TXBUFSIZE; - } while ( diff >= UART_TXBUFSIZE -1 ); - - cli(); - *txhead = c; - if (++txhead == (txbuf + UART_TXBUFSIZE)) txhead = txbuf; - - UCSRB |= (1 << UDRIE); /* enable data register empty IRQ */ - sei(); -} -#else // WITHOUT INTERRUPT -void uart_putc(char c) { - while (!(UCSRA & (1<>8); + UBRRL = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|(1<>8); + UBRR0L = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE0)|(1<>8); + UBRR = (unsigned char) baudrate; + + /* Enable UART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|(1<>8); + UBRR1L = (unsigned char) baudrate; + + /* Enable UART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE1)|(1<> 8; + }else{ + /* store new index */ + UART1_RxHead = tmphead; + /* store received data in buffer */ + UART1_RxBuf[tmphead] = data; + } + UART1_LastRxError |= lastRxError; } -#endif // UART_INTERRUPT + + +ISR(UART1_TRANSMIT_INTERRUPT) +/************************************************************************* +Function: UART1 Data Register Empty interrupt +Purpose: called when the UART1 is ready to transmit the next byte +**************************************************************************/ +{ + unsigned char tmptail; + + + if ( UART1_TxHead != UART1_TxTail) { + /* calculate and store new buffer index */ + tmptail = (UART1_TxTail + 1) & UART_TX_BUFFER_MASK; + UART1_TxTail = tmptail; + /* get one byte from buffer and write it to UART */ + UART1_DATA = UART1_TxBuf[tmptail]; /* start transmission */ + }else{ + /* tx buffer empty, disable UDRE interrupt */ + UART1_CONTROL &= ~_BV(UART1_UDRIE); + } +} + + +/************************************************************************* +Function: uart1_init() +Purpose: initialize UART1 and set baudrate +Input: baudrate using macro UART_BAUD_SELECT() +Returns: none +**************************************************************************/ +void uart1_init(unsigned int baudrate) +{ + UART1_TxHead = 0; + UART1_TxTail = 0; + UART1_RxHead = 0; + UART1_RxTail = 0; + + + /* Set baud rate */ + if ( baudrate & 0x8000 ) + { + UART1_STATUS = (1<>8); + UBRR1L = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART1_CONTROL = _BV(RXCIE1)|(1< http://jump.to/fleury +File: $Id: uart.h,v 1.12 2012/11/19 19:52:27 peter Exp $ +Software: AVR-GCC 4.1, AVR Libc 1.4 +Hardware: any AVR with built-in UART, tested on AT90S8515 & ATmega8 at 4 Mhz +License: GNU General Public License +Usage: see Doxygen manual + +LICENSE: + Copyright (C) 2006 Peter Fleury + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +************************************************************************/ /** - * UART Library + * @defgroup pfleury_uart UART Library + * @code #include @endcode * - * #define F_CPU 16000000 // Oszillator-Frequenz in Hz - * #define UART_INTERRUPT 1 - * #define UART_BAUD_RATE 19200 - * #define UART_RXBUFSIZE 16 - * #define UART_TXBUFSIZE 16 - * #define UART_LINE_BUFFER_SIZE 40 - * #define UART_LEDS // LED1 and LED2 toggle on tx and rx interrupt + * @brief Interrupt UART library using the built-in UART with transmit and + * receive circular buffers. * + * This library can be used to transmit and receive data through the built in + * UART. + * + * An interrupt is generated when the UART has finished transmitting or + * receiving a byte. The interrupt handling routines use circular buffers + * for buffering received and transmitted data. + * + * The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE constants define the size of + * the circular buffers in bytes. Note that these constants must be a power of + * 2. You may need to adapt this constants to your target and your application + * by adding CDEFS += -DUART_RX_BUFFER_SIZE=nn -DUART_RX_BUFFER_SIZE=nn to your + * Makefile. + * + * @note Based on Atmel Application Note AVR306 + * @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury */ -#include -#include +/**@{*/ -void uart_init(); - -void uart_putc(char c); -void uart_putstr(char * str); -void uart_putstr_P(PGM_P str); -void uart_hexdump(char *buf, int len); - -char uart_getc(); -char uart_getc_nb(char *c); // returns 1 on success - -//get one Cariage return terminated line -//echo charakters back on Uart -//returns buffer with zero terminated line on success, 0 pointer otherwise -char * uart_getline_nb(); +#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304 +#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !" #endif + + +/* + * constants and macros + */ + +/** @brief UART Baudrate Expression + * @param xtalcpu system clock in Mhz, e.g. 4000000UL for 4Mhz + * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 + */ +#define UART_BAUD_SELECT(baudRate,xtalCpu) \ + (((xtalCpu) + 8UL * (baudRate)) / (16UL * (baudRate)) -1UL) + +/** @brief UART Baudrate Expression for ATmega double speed mode + * @param xtalcpu system clock in Mhz, e.g. 4000000UL for 4Mhz + * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 + */ +#define UART_BAUD_SELECT_DOUBLE_SPEED(baudRate,xtalCpu) \ + (((((xtalCpu) + 4UL * (baudRate)) / (8UL * (baudRate)) -1UL)) | 0x8000) + + +/** Size of the circular receive buffer, must be power of 2 */ +#ifndef UART_RX_BUFFER_SIZE +#define UART_RX_BUFFER_SIZE 32 +#endif + +/** Size of the circular transmit buffer, must be power of 2 */ +#ifndef UART_TX_BUFFER_SIZE +#define UART_TX_BUFFER_SIZE 32 +#endif + +/* test if the size of the circular buffers fits into SRAM */ +#if ( (UART_RX_BUFFER_SIZE+UART_TX_BUFFER_SIZE) >= (RAMEND-0x60 ) ) && defined __AVR +#error "size of UART_RX_BUFFER_SIZE + UART_TX_BUFFER_SIZE larger than size of SRAM" +#endif + +/* +** high byte error return code of uart_getc() +*/ +#define UART_FRAME_ERROR 0x1000 /* Framing Error by UART */ +#define UART_OVERRUN_ERROR 0x0800 /* Overrun condition by UART */ +#define UART_PARITY_ERROR 0x0400 /* Parity Error by UART */ +#define UART_BUFFER_OVERFLOW 0x0200 /* receive ringbuffer overflow */ +#define UART_NO_DATA 0x0100 /* no receive data available */ + + +/* +** function prototypes +*/ + +/** + @brief Initialize UART and set baudrate + @param baudrate Specify baudrate using macro UART_BAUD_SELECT() + @return none +*/ +extern void uart_init(unsigned int baudrate); + + +/** + * @brief Get received byte from ringbuffer + * + * Returns in the lower byte the received character and in the + * higher byte the last receive error. + * UART_NO_DATA is returned when no data is available. + * + * @param void + * @return lower byte: received byte from ringbuffer + * @return higher byte: last receive status + * - \b 0 successfully received data from UART + * - \b UART_NO_DATA + *
no receive data available + * - \b UART_BUFFER_OVERFLOW + *
Receive ringbuffer overflow. + * We are not reading the receive buffer fast enough, + * one or more received character have been dropped + * - \b UART_OVERRUN_ERROR + *
Overrun condition by UART. + * A character already present in the UART UDR register was not read + * by the interrupt handler before the next character arrived, + * one or more received characters have been dropped. + * - \b UART_FRAME_ERROR + *
Framing Error by UART + */ +extern unsigned int uart_getc(void); + + +/** + * @brief Put byte to ringbuffer for transmitting via UART + * @param data byte to be transmitted + * @return none + */ +extern void uart_putc(unsigned char data); + + +/** + * @brief Put string to ringbuffer for transmitting via UART + * + * The string is buffered by the uart library in a circular buffer + * and one character at a time is transmitted to the UART using interrupts. + * Blocks if it can not write the whole string into the circular buffer. + * + * @param s string to be transmitted + * @return none + */ +extern void uart_puts(const char *s ); + + +/** + * @brief Put string from program memory to ringbuffer for transmitting via + * UART. + * + * The string is buffered by the uart library in a circular buffer + * and one character at a time is transmitted to the UART using interrupts. + * Blocks if it can not write the whole string into the circular buffer. + * + * @param s program memory string to be transmitted + * @return none + * @see uart_puts_P + */ +extern void uart_puts_p(const char *s ); + +/** + * @brief Macro to automatically put a string constant into program memory + */ +#define uart_puts_P(__s) uart_puts_p(PSTR(__s)) + + + +/** @brief Initialize USART1 (only available on selected ATmegas) + * @see uart_init + */ +extern void uart1_init(unsigned int baudrate); + +/** @brief Get received byte of USART1 from ringbuffer (only available on + * selected ATmega) + * @see uart_getc + */ +extern unsigned int uart1_getc(void); + +/** @brief Put byte to ringbuffer for transmitting via USART1 (only available + * on selected ATmega) + * @see uart_putc + */ +extern void uart1_putc(unsigned char data); + +/** @brief Put string to ringbuffer for transmitting via USART1 (only available + * on selected ATmega) + * @see uart_puts + */ +extern void uart1_puts(const char *s ); + +/** @brief Put string from program memory to ringbuffer for transmitting via + * USART1 (only available on selected ATmega) + * @see uart_puts_p + */ +extern void uart1_puts_p(const char *s ); + +/** @brief Macro to automatically put a string constant into program memory */ +#define uart1_puts_P(__s) uart1_puts_p(PSTR(__s)) + +/**@}*/ + +#endif // UART_H diff --git a/src/uart/uart_commands.c b/src/uart/uart_commands.c new file mode 100644 index 0000000..62d92fb --- /dev/null +++ b/src/uart/uart_commands.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include +#include +#include "../config.h" +#include "../borg_hw/borg_hw.h" +#include "../scrolltext/scrolltext.h" +#include "uart.h" +#include "uart_commands.h" + +#define UART_SCROLL_BUFFER_SIZE (SCROLLTEXT_BUFFER_SIZE + 8) +char g_rx_buffer[UART_SCROLL_BUFFER_SIZE]; +uint8_t g_rx_index; + +extern jmp_buf newmode_jmpbuf; +volatile unsigned char mode; + +void uartcmd_clear_buffer(void) { + char *p = &g_rx_buffer[0]; + for (uint8_t i = UART_SCROLL_BUFFER_SIZE; i--;) { + *p++ = 0; + } + g_rx_index = 0; +} + +char const UART_STR_PROMPT[] PROGMEM = "\r\n> "; +char const UART_STR_ERROR[] PROGMEM = "\r\ntransmission error"; +char const UART_STR_UNKNOWN[] PROGMEM = "\r\nunknown command"; +char const UART_STR_TOOLONG[] PROGMEM = "\r\ncommand to long"; +char const UART_STR_HELP[] PROGMEM = "\r\nhelp msg next prev reset scroll"; + +char const UART_CMD_HELP[] PROGMEM = "help"; +char const UART_CMD_MSG[] PROGMEM = "msg "; +char const UART_CMD_NEXT[] PROGMEM = "next"; +char const UART_CMD_PREV[] PROGMEM = "prev"; +char const UART_CMD_RESET[] PROGMEM = "reset"; +char const UART_CMD_SCROLL[] PROGMEM = "scroll "; + +bool uartcmd_read_until_enter(void) { + while (g_rx_index < (UART_SCROLL_BUFFER_SIZE - 1)) { + int uart_result = uart_getc(); + + switch (uart_result & 0xFF00u) { + case 0: + if (!(uart_result == '\r' || uart_result == '\n')) { + g_rx_buffer[g_rx_index++] = uart_result; + uart_putc(uart_result); + } else { + g_rx_buffer[g_rx_index++] = 0; + return true; + } + break; + + case UART_FRAME_ERROR: + case UART_OVERRUN_ERROR: + case UART_PARITY_ERROR: + case UART_BUFFER_OVERFLOW: + uartcmd_clear_buffer(); + uart_puts_p(UART_STR_ERROR); + uart_puts_p(UART_STR_PROMPT); + break; + + case UART_NO_DATA: + default: + return false; + break; + } + } + + if (g_rx_index >= (UART_SCROLL_BUFFER_SIZE - 1)) { + uartcmd_clear_buffer(); + uart_puts_p(UART_STR_TOOLONG); + uart_puts_p(UART_STR_PROMPT); + } + return false; +} + +void uartcmd_process(void) { + if (uartcmd_read_until_enter()) { + if (!strncmp_P(g_rx_buffer, UART_CMD_HELP, 4)) { + uart_puts_p(UART_STR_HELP); + } else if (!strncmp_P(g_rx_buffer, UART_CMD_MSG, 4)) { + g_rx_buffer[1] = '<'; + g_rx_buffer[2] = '/'; + g_rx_buffer[3] = '#'; + // text must not be longer than the scroll text buffer + g_rx_buffer[1 + SCROLLTEXT_BUFFER_SIZE - 1] = 0; + scrolltext(&g_rx_buffer[1]); + } else if (!strncmp_P(g_rx_buffer, UART_CMD_NEXT, 4)) { + uart_puts_p(UART_STR_PROMPT); + uartcmd_clear_buffer(); + longjmp(newmode_jmpbuf, mode); + } else if (!strncmp_P(g_rx_buffer, UART_CMD_PREV, 4)) { + uart_puts_p(UART_STR_PROMPT); + uartcmd_clear_buffer(); + if (mode > 1) { + longjmp(newmode_jmpbuf, mode - 2); + } + } else if (!strncmp_P(g_rx_buffer, UART_CMD_RESET, + UART_SCROLL_BUFFER_SIZE)) { + timer0_off(); + } else if (!strncmp_P(g_rx_buffer, UART_CMD_SCROLL, 7)) { + // text must not be longer than the scroll text buffer + g_rx_buffer[7 + SCROLLTEXT_BUFFER_SIZE - 1] = 0; + scrolltext(&g_rx_buffer[7]); + } else { + uart_puts_p(UART_STR_UNKNOWN); + } + uart_puts_p(UART_STR_PROMPT); + uartcmd_clear_buffer(); + } +} diff --git a/src/uart/uart_commands.h b/src/uart/uart_commands.h new file mode 100644 index 0000000..074583f --- /dev/null +++ b/src/uart/uart_commands.h @@ -0,0 +1,13 @@ +/* + * uart_commands.h + * + * Created on: 16.08.2014 + * Author: chris + */ + +#ifndef UART_COMMANDS_H_ +#define UART_COMMANDS_H_ + +void uartcmd_process(void); + +#endif /* UART_COMMANDS_H_ */ diff --git a/src/util.c b/src/util.c index 87e366c..9138ae7 100644 --- a/src/util.c +++ b/src/util.c @@ -19,6 +19,9 @@ extern jmp_buf newmode_jmpbuf; # include "can/borg_can.h" #endif +#ifdef UART_SUPPORT +# include "uart/uart_commands.h" +#endif void wait(int ms){ /* Always use Timer1 except for the Arduino/LoL Shield platform. */ @@ -41,6 +44,10 @@ void wait(int ms){ bcan_process_messages(); #endif +#ifdef UART_SUPPORT + uartcmd_process(); +#endif + #ifdef RFM12_SUPPORT borg_rfm12_tick(); #endif