Subversion Repositories HomeAutomation

Rev

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