From 45cbcde797d3189c3f6fcfbc981f4ac87f698d48 Mon Sep 17 00:00:00 2001 From: barner Date: Fri, 22 Dec 2006 17:00:45 +0000 Subject: [PATCH] - Fix/enhence support for RS232 interface on AVR (ATMega128): * support for multiple ports: (extended interface with 'port' parameter) * new function: rs232_redirect_stdout that allows you to redirect stdout to a serial port - In order to implement support for other MCUs, adopt a copy of rs232_atmega128.h --- cpu/avr/dev/rs232.c | 173 +++++++++++++++++++++++++--------- cpu/avr/dev/rs232.h | 70 ++++++++++++-- cpu/avr/dev/rs232_atmega128.h | 127 +++++++++++++++++++++++++ 3 files changed, 319 insertions(+), 51 deletions(-) create mode 100644 cpu/avr/dev/rs232_atmega128.h diff --git a/cpu/avr/dev/rs232.c b/cpu/avr/dev/rs232.c index adca2624e..14a1dcc1c 100644 --- a/cpu/avr/dev/rs232.c +++ b/cpu/avr/dev/rs232.c @@ -28,103 +28,190 @@ * * This file is part of the Contiki operating system. * - * @(#)$Id: rs232.c,v 1.1 2006/06/17 22:41:21 adamdunkels Exp $ + * @(#)$Id: rs232.c,v 1.2 2006/12/22 17:00:45 barner Exp $ */ +#include #include -#include #include #include +#include "contiki-conf.h" #include "contiki.h" + #include "dev/slip.h" #include "dev/serial.h" #include "dev/rs232.h" -static volatile unsigned char txwait; -/*static unsigned char slipmode;*/ +#ifdef RS232_CONF_PRINTF_BUFFER_LENGTH +#define RS232_PRINTF_BUFFER_LENGTH RS232_CONF_PRINTF_BUFFER_LENGTH +#else +#define RS232_PRINTF_BUFFER_LENGTH 64 +#endif -static int (* input_handler)(unsigned char) = NULL; +#if MCU == atmega128 +typedef struct { + volatile uint8_t * UDR; + volatile uint8_t * UBRRH; + volatile uint8_t * UBRRL; + volatile uint8_t * UCSRB; + volatile uint8_t * UCSRC; + volatile uint8_t txwait; + int (* input_handler)(unsigned char); +} rs232_t; + +static rs232_t rs232_ports[2] = { + { // UART0 + &UDR0, + &UBRR0H, + &UBRR0L, + &UCSR0B, + &UCSR0C, + 0, + NULL + }, + + { // UART1 + &UDR1, + &UBRR1H, + &UBRR1L, + &UCSR1B, + &UCSR1C, + 0, + NULL + } +}; +#else +#error Please define the UART registers for your MCU! +#endif /*---------------------------------------------------------------------------*/ SIGNAL(SIG_UART0_TRANS) { - txwait = 0; + rs232_ports[RS232_PORT_0].txwait = 0; } + /*---------------------------------------------------------------------------*/ SIGNAL(SIG_UART0_RECV) { unsigned char c; - c = UDR0; + c = *(rs232_ports[RS232_PORT_0].UDR); - if(input_handler != NULL) { - input_handler(c); + if(rs232_ports[RS232_PORT_0].input_handler != NULL) { + rs232_ports[RS232_PORT_0].input_handler(c); } - - /* if(slipmode) { - slip_input_byte(c); - } else { - serial_input_byte(c); - }*/ } + +/*---------------------------------------------------------------------------*/ +SIGNAL(SIG_UART1_TRANS) +{ + rs232_ports[RS232_PORT_1].txwait = 0; +} + +/*---------------------------------------------------------------------------*/ +SIGNAL(SIG_UART1_RECV) +{ + unsigned char c; + + c = *(rs232_ports[RS232_PORT_1].UDR); + + if(rs232_ports[RS232_PORT_1].input_handler != NULL) { + rs232_ports[RS232_PORT_1].input_handler(c); + } +} + /*---------------------------------------------------------------------------*/ void -rs232_init(void) +rs232_init (uint8_t port, uint8_t bd, uint8_t ffmt) { - /* Enable transmit. */ - UCSR0B = _BV(RXCIE) | _BV(TXCIE) | _BV(RXEN) | _BV(TXEN); - /* Set baud rate (23 =~ 38400) */ - UBRR0H = 0; - UBRR0L = 23; + *(rs232_ports[port].UBRRH) = (uint8_t)(bd>>8); + *(rs232_ports[port].UBRRL) = (uint8_t)bd; - /* slipmode = 0;*/ - txwait = 0; + /* + * - Enable receiver and transmitter, + * - Enable interrupts for receiver and transmitter + */ + *(rs232_ports[port].UCSRB) = USART_INTERRUPT_RX_COMPLETE | USART_INTERRUPT_TX_COMPLETE | \ + USART_RECEIVER_ENABLE | USART_TRANSMITTER_ENABLE; - input_handler = NULL; + /* + * - mode (sync. / async) + * - Parity + * - Stop bits + * - charater size (9 bits are currently not supported) + * - clock polarity + */ + *(rs232_ports[port].UCSRC) = ffmt; + + rs232_ports[port].txwait = 0; + + rs232_ports[port].input_handler = NULL; } -/*---------------------------------------------------------------------------*/ -/*void -rs232_init_slip(void) -{ - rs232_init(); - slipmode = 1; -}*/ -/*---------------------------------------------------------------------------*/ + void -rs232_print_p(prog_char *buf) +rs232_print_p(uint8_t port, prog_char *buf) { while(pgm_read_byte(buf)) { - rs232_send(pgm_read_byte(buf)); + rs232_send(port, pgm_read_byte(buf)); ++buf; } } /*---------------------------------------------------------------------------*/ void -rs232_print(char *buf) +rs232_print(uint8_t port, char *buf) { while(*buf) { - rs232_send(*buf++); + rs232_send(port, *buf++); } } /*---------------------------------------------------------------------------*/ void -rs232_send(unsigned char c) +rs232_printf(uint8_t port, const char *fmt, ...) { - txwait = 1; - UDR0 = c; - while(txwait); + va_list ap; + static char buf[RS232_PRINTF_BUFFER_LENGTH]; + + va_start (ap, fmt); + vsnprintf (buf, RS232_PRINTF_BUFFER_LENGTH, fmt, ap); + va_end(ap); + + rs232_print (port, buf); } /*---------------------------------------------------------------------------*/ void -rs232_set_input(int (*f)(unsigned char)) +rs232_send(uint8_t port, unsigned char c) { - input_handler = f; + rs232_ports[port].txwait = 1; + *(rs232_ports[port].UDR) = c; + while(rs232_ports[port].txwait); +} +/*---------------------------------------------------------------------------*/ +void +rs232_set_input(uint8_t port, int (*f)(unsigned char)) +{ + rs232_ports[port].input_handler = f; } /*---------------------------------------------------------------------------*/ void slip_arch_writeb(unsigned char c) { - rs232_send(c); + rs232_send(SLIP_PORT, c); } /*---------------------------------------------------------------------------*/ +int rs232_stdout_putchar(char c, FILE *stream); +static uint8_t stdout_rs232_port=RS232_PORT_0; +static FILE rs232_stdout = FDEV_SETUP_STREAM(rs232_stdout_putchar, + NULL, + _FDEV_SETUP_WRITE); + +int rs232_stdout_putchar(char c, FILE *stream) +{ + rs232_send (stdout_rs232_port, c); + return 0; +} +/*---------------------------------------------------------------------------*/ +void rs232_redirect_stdout (uint8_t port) { + stdout_rs232_port = port; + stdout = &rs232_stdout; +} diff --git a/cpu/avr/dev/rs232.h b/cpu/avr/dev/rs232.h index 3c671b18a..0e7feef35 100644 --- a/cpu/avr/dev/rs232.h +++ b/cpu/avr/dev/rs232.h @@ -28,24 +28,41 @@ * * This file is part of the Contiki operating system. * - * @(#)$Id: rs232.h,v 1.1 2006/06/17 22:41:21 adamdunkels Exp $ + * Author: Adam Dunkels + * Simon Barner + * + * @(#)$Id: rs232.h,v 1.2 2006/12/22 17:00:45 barner Exp $ */ #ifndef __RS232_H__ #define __RS232_H__ #include +#include "contiki-conf.h" + +#if MCU == atmega128 +#include "dev/rs232_atmega128.h" +#else +#error "Please implement a rs232 header for your MCU (or set the MCU type \ +in contiki-conf.h)." +#endif /** * \brief Initialize the RS232 module * * This function is called from the boot up code to * initalize the RS232 module. + * \param port The RS232 port to be used. + * \param bd The baud rate of the connection. + * \param ffmt The frame format of the connection, i.e. parity mode, + * number of stop and data bits, ... */ -void rs232_init(void); +void +rs232_init (uint8_t port, uint8_t bd, uint8_t ffmt); /** * \brief Set an input handler for incoming RS232 data + * \param port The RS232 port to be used. * \param f A pointer to a byte input handler * * This function sets the input handler for incoming RS232 @@ -61,23 +78,26 @@ void rs232_init(void); * take place. If the input handler returns zero, the CPU * is kept sleeping. */ -void rs232_set_input(int (* f)(unsigned char)); +void +rs232_set_input(uint8_t port, int (* f)(unsigned char)); /** * \brief Print a text string from program memory on RS232 - * \param str A pointer to the string that is to be printed + * \param port The RS232 port to be used. + * \param buf A pointer to the string that is to be printed * * This function prints a string from program memory to * RS232. The string must be terminated by a null * byte. The RS232 module must be correctly initalized and * configured for this function to work. */ -void rs232_print_p(prog_char *buf); - +void +rs232_print_p(uint8_t port, prog_char *buf); /** * \brief Print a text string on RS232 + * \param port The RS232 port to be used. * \param str A pointer to the string that is to be printed * * This function prints a string to RS232. The string must @@ -85,16 +105,50 @@ void rs232_print_p(prog_char *buf); * correctly initalized and configured for this function * to work. */ -void rs232_print(char *buf); +void +rs232_print(uint8_t port, char *buf); + +/** + * \brief Print a formated string on RS232 + * \param port The RS232 port to be used. + * \param fmt The format string that is used to construct the string + * from a variable number of arguments. + * + * This function prints a formated string to RS232. Note + * that this function used snprintf internally and thus cuts + * the resulting string after RS232_PRINTF_BUFFER_LENGTH - 1 + * bytes. You can override this buffer lenght with the + * RS232_CONF_PRINTF_BUFFER_LENGTH define. The RS232 module + * must becorrectly initalized and configured for this + * function to work. + */ +void +rs232_printf(uint8_t port, const char *fmt, ...); /** * \brief Print a character on RS232 + * \param port The RS232 port to be used. * \param c The character to be printed * * This function prints a character to RS232. The RS232 * module must be correctly initalized and configured for * this function to work. */ -void rs232_send(unsigned char c); +void +rs232_send(uint8_t port, unsigned char c); + +/** + * \brief Redirects stdout to a given RS232 port + * \param port The RS232 port to be used. + * + * This function redirects the stdout channel to a given + * RS232 port. Note that this modfies the global variable + * stdout. If you want to restore the previous behaviour, it + * is your responsibility to backup to old value. The RS232 + * module must be correctly initalized and configured for + * the redirection to work. + */ +void +rs232_redirect_stdout (uint8_t port); #endif /* __RS232_H__ */ diff --git a/cpu/avr/dev/rs232_atmega128.h b/cpu/avr/dev/rs232_atmega128.h new file mode 100644 index 000000000..ea5081e93 --- /dev/null +++ b/cpu/avr/dev/rs232_atmega128.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2006, Technical University of Munich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * @(#)$$ + */ + +/** + * \file + * AVR specific definitions for the rs232 port. + * + * \author + * Simon Barner + +/******************************************************************************/ +/*** RS232 ports */ +/******************************************************************************/ +#define RS232_PORT_0 0 +#define RS232_PORT_1 1 + +/******************************************************************************/ +/*** Baud rates */ +/******************************************************************************/ +#if MCU_MHZ == 16 +/* Single speed operation (U2X = 0)*/ +#define USART_BAUD_2400 416 +#define USART_BAUD_4800 207 +#define USART_BAUD_9600 103 +#define USART_BAUD_14400 68 +#define USART_BAUD_19200 51 +#define USART_BAUD_28800 34 +#define USART_BAUD_38400 25 +#define USART_BAUD_57600 16 +#define USART_BAUD_76800 12 +#define USART_BAUD_115200 8 +#define USART_BAUD_230400 3 +#define USART_BAUD_250000 3 +#define USART_BAUD_500000 1 +#define USART_BAUD_1000000 0 +#else +#error "Please define the baud rates for your CPU clock: ATmega128 handbook p. \ +195-198 or set the rate in contiki-conf.h" +#endif + + +/******************************************************************************/ +/*** Interrupt settings */ +/******************************************************************************/ +#define USART_INTERRUPT_RX_COMPLETE _BV (RXCIE) +#define USART_INTERRUPT_TX_COMPLETE _BV (TXCIE) +#define USART_INTERRUPT_DATA_REG_EMPTY _BV (UDRIE) + +/******************************************************************************/ +/*** Receiver / transmitter */ +/******************************************************************************/ +#define USART_RECEIVER_ENABLE _BV (RXEN) +#define USART_TRANSMITTER_ENABLE _BV (TXEN) + +/******************************************************************************/ +/*** Mode select */ +/******************************************************************************/ +#define USART_MODE_ASYNC 0x00 +#define USART_MODE_SYNC _BV (UMSEL) + +/******************************************************************************/ +/*** Parity */ +/******************************************************************************/ +#define USART_PARITY_NONE 0x00 +#define USART_PARITY_EVEN _BV (UPM1) +#define USART_PARITY_ODD _BV (UPM1) | _BV (UPM0) + +/******************************************************************************/ +/*** Stop bits */ +/******************************************************************************/ +#define USART_STOP_BITS_1 0x00 +#define USART_STOP_BITS_2 _BV (USBS) + +/******************************************************************************/ +/*** Character size */ +/******************************************************************************/ +#define USART_DATA_BITS_5 0x00 +#define USART_DATA_BITS_6 _BV (UCSZ0) +#define USART_DATA_BITS_7 _BV (UCSZ1) +#define USART_DATA_BITS_8 _BV (UCSZ1) | _BV (UCSZ0) +// #define USART_DATA_BITS_9 (needs also UCSZ2 bit in UCSRnB) + +/******************************************************************************/ +/*** Clock polarity */ +/******************************************************************************/ +#define USART_RISING_XCKN_EDGE 0x00 +#define USART_FALLING_XCKN_EDGE _BV (UCPOL) + +#endif /* #ifndef __RS232_ATMEGA128__ */