Subversion Repositories HomeAutomation

Rev

Rev 127 | Go to most recent revision | Blame | Last modification | View Log | SVN | RSS feed

  1. /*************************************************************************
  2. Title:     Interrupt UART library with receive/transmit circular buffers
  3. Author:    Peter Fleury <pfleury@gmx.ch>   http://jump.to/fleury
  4. File:      $Id: uart.c,v 1.5.2.2 2004/02/27 22:00:28 peter Exp $
  5. Software:  AVR-GCC 3.3
  6. Hardware:  any AVR with built-in UART,
  7.            tested on AT90S8515 at 4 Mhz and ATmega at 1Mhz
  8. Extensions:- uart_puti by M. Thomas 9/2004
  9.            - uart_puthex_nibble and _byte by M.T. 9/2004
  10.            - uart_putbin_byte by M.T. 1/2005
  11.  
  12. DESCRIPTION:
  13.     An interrupt is generated when the UART has finished transmitting or
  14.     receiving a byte. The interrupt handling routines use circular buffers
  15.     for buffering received and transmitted data.
  16.    
  17.     The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define
  18.     the buffer size in bytes. Note that these variables must be a
  19.     power of 2.
  20.    
  21. USAGE:
  22.     Refere to the header file uart.h for a description of the routines.
  23.     See also example test_uart.c.
  24.  
  25. NOTES:
  26.     Based on Atmel Application Note AVR306
  27.                    
  28. *************************************************************************/
  29. #include <stdlib.h>
  30. #include <stdio.h>
  31.  
  32. #include <avr/io.h>
  33. #include <avr/interrupt.h>
  34. #include <avr/pgmspace.h>
  35.  
  36. #include <uart.h>
  37.  
  38.  
  39. static int uart_putchar(char c, FILE *stream);
  40. static void Uart_InitHw(unsigned int baudrate);
  41.  
  42. static FILE myStdOut = FDEV_SETUP_STREAM(uart_putchar, NULL,_FDEV_SETUP_WRITE);
  43.  
  44. static int uart_putchar(char c, FILE *stream) {
  45.     if (c == '\n') uart_putchar('\r', stream);
  46.     uart_putc(c);
  47.     return 0;
  48. }
  49.  
  50.  
  51. /*
  52.  *  constants and macros
  53.  */
  54.  
  55. /* size of RX/TX buffers */
  56. #define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1)
  57. #define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1)
  58.  
  59. #if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK )
  60. #error RX buffer size is not a power of 2
  61. #endif
  62. #if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK )
  63. #error TX buffer size is not a power of 2
  64. #endif
  65.  
  66. #if defined(__AVR_AT90S2313__) \
  67.  || defined(__AVR_AT90S4414__) || defined(__AVR_AT90S4434__) \
  68.  || defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__)
  69.  /* old AVR classic with one UART */
  70.  #define AT90_UART
  71.  #define UART0_RECEIVE_INTERRUPT   SIG_UART_RECV
  72.  #define UART0_TRANSMIT_INTERRUPT  SIG_UART_DATA
  73.  #define UART0_STATUS   USR
  74.  #define UART0_CONTROL  UCR
  75.  #define UART0_DATA     UDR  
  76.  #define UART0_UDRIE    UDRIE
  77. #elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__)
  78.  /* old AVR classic with one UART */
  79.  #define AT90_UART
  80.  #define UART0_RECEIVE_INTERRUPT   SIG_UART_RECV
  81.  #define UART0_TRANSMIT_INTERRUPT  SIG_UART_DATA
  82.  #define UART0_STATUS   UCSRA
  83.  #define UART0_CONTROL  UCSRB
  84.  #define UART0_DATA     UDR
  85.  #define UART0_UDRIE    UDRIE
  86. #elif  defined(__AVR_ATmega8__)  || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \
  87.   || defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) \
  88.   || defined(__AVR_ATmega323__)
  89.   /* ATMega with one USART */
  90.  #define ATMEGA_USART
  91.  #define UART0_RECEIVE_INTERRUPT   SIG_UART_RECV
  92.  #define UART0_TRANSMIT_INTERRUPT  SIG_UART_DATA
  93.  #define UART0_STATUS   UCSRA
  94.  #define UART0_CONTROL  UCSRB
  95.  #define UART0_DATA     UDR
  96.  #define UART0_UDRIE    UDRIE
  97. #elif defined(__AVR_ATmega163__)
  98.   /* ATMega163 with one UART */
  99.  #define ATMEGA_UART
  100.  #define UART0_RECEIVE_INTERRUPT   SIG_UART_RECV
  101.  #define UART0_TRANSMIT_INTERRUPT  SIG_UART_DATA
  102.  #define UART0_STATUS   UCSRA
  103.  #define UART0_CONTROL  UCSRB
  104.  #define UART0_DATA     UDR
  105.  #define UART0_UDRIE    UDRIE
  106. #elif defined(__AVR_ATmega162__)
  107.  /* ATMega with two USART */
  108.  #define ATMEGA_USART0
  109.  #define ATMEGA_USART1
  110.  #define UART0_RECEIVE_INTERRUPT   SIG_USART0_RECV
  111.  #define UART1_RECEIVE_INTERRUPT   SIG_USART1_RECV
  112.  #define UART0_TRANSMIT_INTERRUPT  SIG_USART0_DATA
  113.  #define UART1_TRANSMIT_INTERRUPT  SIG_USART1_DATA
  114.  #define UART0_STATUS   UCSR0A
  115.  #define UART0_CONTROL  UCSR0B
  116.  #define UART0_DATA     UDR0
  117.  #define UART0_UDRIE    UDRIE0
  118.  #define UART1_STATUS   UCSR1A
  119.  #define UART1_CONTROL  UCSR1B
  120.  #define UART1_DATA     UDR1
  121.  #define UART1_UDRIE    UDRIE1
  122. #elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)
  123.  /* ATMega with two USART */
  124.  #define ATMEGA_USART0
  125.  #define ATMEGA_USART1
  126.  #define UART0_RECEIVE_INTERRUPT   SIG_UART0_RECV
  127.  #define UART1_RECEIVE_INTERRUPT   SIG_UART1_RECV
  128.  #define UART0_TRANSMIT_INTERRUPT  SIG_UART0_DATA
  129.  #define UART1_TRANSMIT_INTERRUPT  SIG_UART1_DATA
  130.  #define UART0_STATUS   UCSR0A
  131.  #define UART0_CONTROL  UCSR0B
  132.  #define UART0_DATA     UDR0
  133.  #define UART0_UDRIE    UDRIE0
  134.  #define UART1_STATUS   UCSR1A
  135.  #define UART1_CONTROL  UCSR1B
  136.  #define UART1_DATA     UDR1
  137.  #define UART1_UDRIE    UDRIE1
  138. #elif defined(__AVR_ATmega103__)
  139.  /* ATMega with one UART */
  140.  #error "AVR ATmega103 currently not supported by this libaray !"
  141. #elif defined(__AVR_ATmega161__)
  142.  /* ATmega with UART */
  143.  #error "AVR ATmega161 currently not supported by this libaray !"
  144. #elif defined(__AVR_ATmega169__)
  145.  #error "AVR ATmega169 currently not supported by this libaray !"
  146. #endif
  147.  
  148.  
  149. /*
  150.  *  module global variables
  151.  */
  152. static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];
  153. static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE];
  154. static volatile unsigned char UART_TxHead;
  155. static volatile unsigned char UART_TxTail;
  156. static volatile unsigned char UART_RxHead;
  157. static volatile unsigned char UART_RxTail;
  158. static volatile unsigned char UART_LastRxError;
  159.  
  160.  
  161.  
  162. ISR(UART0_RECEIVE_INTERRUPT)
  163. /*************************************************************************
  164. Function: UART Receive Complete interrupt
  165. Purpose:  called when the UART has received a character
  166. **************************************************************************/
  167. {
  168.     unsigned char tmphead;
  169.     unsigned char data;
  170.     unsigned char usr;
  171.     unsigned char lastRxError;
  172.  
  173.  
  174.     /* read UART status register and UART data register */
  175.     usr  = UART0_STATUS;
  176.     data = UART0_DATA;
  177.    
  178.     /* */
  179. #if defined( AT90_UART )
  180.     lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
  181. #elif defined( ATMEGA_USART )
  182.     lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
  183. #elif defined( ATMEGA_USART0 )
  184.     lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) );
  185. #elif defined ( ATMEGA_UART )
  186.     lastRxError = (usr & (_BV(FE)|_BV(DOR)) );
  187. #endif
  188.        
  189.     /* calculate buffer index */
  190.     tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK;
  191.    
  192.     if ( tmphead == UART_RxTail ) {
  193.         /* error: receive buffer overflow */
  194.         lastRxError = UART_BUFFER_OVERFLOW >> 8;
  195.     }else{
  196.         /* store new index */
  197.         UART_RxHead = tmphead;
  198.         /* store received data in buffer */
  199.         UART_RxBuf[tmphead] = data;
  200.     }
  201.     UART_LastRxError = lastRxError;
  202. }
  203.  
  204.  
  205. ISR(UART0_TRANSMIT_INTERRUPT)
  206. /*************************************************************************
  207. Function: UART Data Register Empty interrupt
  208. Purpose:  called when the UART is ready to transmit the next byte
  209. **************************************************************************/
  210. {
  211.     unsigned char tmptail;
  212.  
  213.    
  214.     if ( UART_TxHead != UART_TxTail) {
  215.         /* calculate and store new buffer index */
  216.         tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK;
  217.         UART_TxTail = tmptail;
  218.         /* get one byte from buffer and write it to UART */
  219.         UART0_DATA = UART_TxBuf[tmptail];  /* start transmission */
  220.     }else{
  221.         /* tx buffer empty, disable UDRE interrupt */
  222.         UART0_CONTROL &= ~_BV(UART0_UDRIE);
  223.     }
  224. }
  225.  
  226.  
  227.  
  228. /**
  229.  * Wrapper function for uart_init.
  230.  */
  231. void Uart_Init() {
  232.     Uart_InitHw((UART_BAUD_SELECT((BAUD),F_OSC)));
  233.     stdout = &myStdOut;
  234. }
  235.  
  236.  
  237. /*************************************************************************
  238. Function: uart_init()
  239. Purpose:  initialize UART and set baudrate
  240. Input:    baudrate using macro UART_BAUD_SELECT()
  241. Returns:  none
  242. **************************************************************************/
  243. static void Uart_InitHw(unsigned int baudrate)
  244. {
  245.     UART_TxHead = 0;
  246.     UART_TxTail = 0;
  247.     UART_RxHead = 0;
  248.     UART_RxTail = 0;
  249.    
  250. #if defined( AT90_UART )
  251.     /* set baud rate */
  252.     UBRR = (unsigned char)baudrate;
  253.  
  254.     /* enable UART receiver and transmmitter and receive complete interrupt */
  255.     UART0_CONTROL = _BV(RXCIE)|_BV(RXEN)|BV(TXEN);
  256.  
  257. #elif defined (ATMEGA_USART)
  258.     /* Set baud rate */
  259.     UBRRH = (unsigned char)(baudrate>>8);
  260.     UBRRL = (unsigned char) baudrate;
  261.  
  262.     /* Enable USART receiver and transmitter and receive complete interrupt */
  263.     UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);
  264.    
  265.     /* Set frame format: asynchronous, 8data, no parity, 1stop bit */
  266.     #ifdef URSEL
  267.     UCSRC = (1<<URSEL)|(3<<UCSZ0);
  268.     #else
  269.     UCSRC = (3<<UCSZ0);
  270.     #endif
  271.    
  272. #elif defined (ATMEGA_USART0 )
  273.     /* Set baud rate */
  274.     UBRR0H = (unsigned char)(baudrate>>8);
  275.     UBRR0L = (unsigned char) baudrate;
  276.  
  277.     /* Enable USART receiver and transmitter and receive complete interrupt */
  278.     UART0_CONTROL = _BV(RXCIE0)|(1<<RXEN0)|(1<<TXEN0);
  279.    
  280.     /* Set frame format: asynchronous, 8data, no parity, 1stop bit */
  281.     #ifdef URSEL0
  282.     UCSR0C = (1<<URSEL0)|(3<<UCSZ00);
  283.     #else
  284.     UCSR0C = (3<<UCSZ00);
  285.     #endif
  286.  
  287. #elif defined ( ATMEGA_UART )
  288.     /* set baud rate */
  289.     UBRRHI = (unsigned char)(baudrate>>8);
  290.     UBRR   = (unsigned char) baudrate;
  291.  
  292.     /* Enable UART receiver and transmitter and receive complete interrupt */
  293.     UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);
  294.  
  295. #endif
  296.  
  297. }/* uart_init */
  298.  
  299.  
  300. /*************************************************************************
  301. Function: uart_getc()
  302. Purpose:  return byte from ringbuffer  
  303. Returns:  lower byte:  received byte from ringbuffer
  304.           higher byte: last receive error
  305. **************************************************************************/
  306. unsigned int uart_getc(void)
  307. {    
  308.     unsigned char tmptail;
  309.     unsigned char data;
  310.  
  311.  
  312.     if ( UART_RxHead == UART_RxTail ) {
  313.         return UART_NO_DATA;   /* no data available */
  314.     }
  315.    
  316.     /* calculate /store buffer index */
  317.     tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK;
  318.     UART_RxTail = tmptail;
  319.    
  320.     /* get data from receive buffer */
  321.     data = UART_RxBuf[tmptail];
  322.    
  323.     return (UART_LastRxError << 8) + data;
  324.  
  325. }/* uart_getc */
  326.  
  327.  
  328. /*************************************************************************
  329. Function: uart_putc()
  330. Purpose:  write byte to ringbuffer for transmitting via UART
  331. Input:    byte to be transmitted
  332. Returns:  none          
  333. **************************************************************************/
  334. void uart_putc(unsigned char data)
  335. {
  336.     unsigned char tmphead;
  337.  
  338.    
  339.     tmphead  = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
  340.    
  341.     while ( tmphead == UART_TxTail ){
  342.         ;/* wait for free space in buffer */
  343.     }
  344.    
  345.     UART_TxBuf[tmphead] = data;
  346.     UART_TxHead = tmphead;
  347.  
  348.     /* enable UDRE interrupt */
  349.     UART0_CONTROL    |= _BV(UART0_UDRIE);
  350.  
  351. }/* uart_putc */
  352.  
  353.  
  354. /*************************************************************************
  355. Function: uart_puts()
  356. Purpose:  transmit string to UART
  357. Input:    string to be transmitted
  358. Returns:  none          
  359. **************************************************************************/
  360. void uart_puts(const char *s )
  361. {
  362.     while (*s)
  363.       uart_putc(*s++);
  364.  
  365. }/* uart_puts */
  366.  
  367.  
  368. /*************************************************************************
  369. Function: uart_puts_p()
  370. Purpose:  transmit string from program memory to UART
  371. Input:    program memory string to be transmitted
  372. Returns:  none
  373. **************************************************************************/
  374. void uart_puts_p(const char *progmem_s )
  375. {
  376.     register char c;
  377.    
  378.     while ( (c = pgm_read_byte(progmem_s++)) )
  379.       uart_putc(c);
  380.  
  381. }/* uart_puts_p */
  382.  
  383. /*************************************************************************
  384. Function: uart_puti()
  385. Purpose:  transmit integer as ASCII to UART
  386. Input:    integer value
  387. Returns:  none
  388. This functions has been added by Martin Thomas <eversmith@heizung-thomas.de>
  389. Don't blame P. Fleury if it doesn't work ;-)
  390. **************************************************************************/
  391. void uart_puti( const int val )
  392. {
  393.     char buffer[sizeof(int)*8+1];
  394.    
  395.     uart_puts( itoa(val, buffer, 10) );
  396.  
  397. }/* uart_puti */
  398.  
  399. /*************************************************************************
  400. Function: uart_puthex_nibble()
  401. Purpose:  transmit lower nibble as ASCII-hex to UART
  402. Input:    byte value
  403. Returns:  none
  404. This functions has been added by Martin Thomas <eversmith@heizung-thomas.de>
  405. Don't blame P. Fleury if it doesn't work ;-)
  406. **************************************************************************/
  407. void uart_puthex_nibble(const unsigned char b)
  408. {
  409.     unsigned char  c = b & 0x0f;
  410.     if (c>9) c += 'A'-10;
  411.     else c += '0';
  412.     uart_putc(c);
  413. } /* uart_puthex_nibble */
  414.  
  415. /*************************************************************************
  416. Function: uart_puthex_byte()
  417. Purpose:  transmit upper and lower nibble as ASCII-hex to UART
  418. Input:    byte value
  419. Returns:  none
  420. This functions has been added by Martin Thomas <eversmith@heizung-thomas.de>
  421. Don't blame P. Fleury if it doesn't work ;-)
  422. **************************************************************************/
  423. void uart_puthex_byte(const unsigned char  b)
  424. {
  425.     uart_puthex_nibble(b>>4);
  426.     uart_puthex_nibble(b);
  427. } /* uart_puthex_byte */
  428.  
  429. /*************************************************************************
  430. Function: uart_putbin_byte()
  431. Purpose:  transmit byte as ASCII-bin to UART
  432. Input:    byte value
  433. Returns:  none
  434. This functions has been added by Martin Thomas <eversmith@heizung-thomas.de>
  435. Don't blame P. Fleury if it doesn't work ;-)
  436. **************************************************************************/
  437. void uart_putbin_byte(const unsigned char b)
  438. {
  439. #if 0
  440.     char buffer[sizeof(int)*8+1];
  441.    
  442.     uart_puts( itoa(b, buffer, 2) );
  443. #else
  444.     signed char i;
  445.     for (i=7;i>=0;i--) {
  446.         if (b & (1<<i)) {
  447.             uart_putc('1');
  448.         }
  449.         else {
  450.             uart_putc('0');
  451.         }
  452.     }
  453. #endif
  454. } /* uart_putbin_byte */
  455.