Subversion Repositories HomeAutomation

Rev

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