Details | Last modification | View Log | SVN | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 19 | jimmy | 1 | /** |
| 2 | * @file uart.c |
||
| 3 | * Routines for interrupt based USART communication on the ATmega8. |
||
| 4 | * @author Jimmy Myhrman |
||
| 5 | * @date 2005-08-20 |
||
| 6 | */ |
||
| 7 | |||
| 8 | /* ----------------------------------------------------------------------------- |
||
| 9 | * Includes |
||
| 10 | * ---------------------------------------------------------------------------*/ |
||
| 11 | #include "uart.h" |
||
| 12 | |||
| 13 | /* ----------------------------------------------------------------------------- |
||
| 14 | * Defines |
||
| 15 | * ---------------------------------------------------------------------------*/ |
||
| 16 | #define TX_BUFSIZE 256 /* must be power of 2 */ |
||
| 17 | #define RX_BUFSIZE 2 /* must be power of 2 */ |
||
| 18 | |||
| 19 | #define TX_MASK (TX_BUFSIZE-1) |
||
| 20 | #define RX_MASK (RX_BUFSIZE-1) |
||
| 21 | |||
| 22 | #define RX_BUFLEN (rx_tail - rx_head) |
||
| 23 | #define TX_BUFLEN (tx_tail - tx_head) |
||
| 24 | |||
| 25 | /* ----------------------------------------------------------------------------- |
||
| 26 | * Variables |
||
| 27 | * ---------------------------------------------------------------------------*/ |
||
| 28 | volatile unsigned char tx_buf[TX_BUFSIZE]; |
||
| 29 | volatile unsigned char rx_buf[RX_BUFSIZE]; |
||
| 30 | |||
| 31 | volatile uint8_t tx_head; |
||
| 32 | volatile uint8_t tx_tail; |
||
| 33 | |||
| 34 | volatile uint8_t rx_head; |
||
| 35 | volatile uint8_t rx_tail; |
||
| 36 | |||
| 37 | /* ----------------------------------------------------------------------------- |
||
| 38 | * Functions |
||
| 39 | * ---------------------------------------------------------------------------*/ |
||
| 40 | |||
| 41 | void uartInit(unsigned char baudrate) { |
||
| 42 | UBRRH = (unsigned char) (baudrate>>8); |
||
| 43 | UBRRL = (unsigned char) baudrate; |
||
| 44 | /* 8 Databits, receive and transmit enabled, receive complete interrupt enabled */ |
||
| 45 | UCSRB = (1<<RXCIE)|(1<<TXEN)|(1<<RXEN); |
||
| 46 | } |
||
| 47 | |||
| 48 | int uartPutChar(char c) { |
||
| 49 | // Fills the transmit buffer, if it is full wait |
||
| 50 | //TODO: if interrupts are currently disabled (which is the case when this |
||
| 51 | //function is called from within an interrupt routine), skip the while-loop |
||
| 52 | //below. otherwise, use it |
||
| 53 | //while ((TX_BUFSIZE - TX_BUFLEN) <= 2) { |
||
| 54 | //if uartPutchar is called while global ints are disabled, we are |
||
| 55 | //stuck here! |
||
| 56 | //} |
||
| 57 | if ((TX_BUFSIZE - TX_BUFLEN) <= 2) { |
||
| 58 | return(1); |
||
| 59 | } |
||
| 60 | // Add data to the transmit buffer, move the tail and enable TXCIE |
||
| 61 | // while tx_tail will count from 0 to 255... AND'ing it with 31 will |
||
| 62 | //continually wrap the index 0 to 31 |
||
| 63 | tx_buf[tx_tail & TX_MASK] = c; |
||
| 64 | tx_tail++; |
||
| 65 | // enable data register empty interrupt |
||
| 66 | UCSRB |= (1<<UDRIE); |
||
| 67 | return(0); |
||
| 68 | } |
||
| 69 | |||
| 70 | |||
| 71 | int uartGetChar (void) { |
||
| 72 | unsigned char c; |
||
| 73 | // this will sit here and wait for SIG_UART0_RECV to get a character and |
||
| 74 | //place it into rx0_buff |
||
| 75 | while (RX_BUFLEN == 0) { |
||
| 76 | } |
||
| 77 | // rx_head will count from 0 to 255... AND'ing it with 31 will continually |
||
| 78 | //wrap the index 0 to 31 |
||
| 79 | c = rx_buf[rx_head & RX_MASK]; |
||
| 80 | rx_head++; |
||
| 81 | return(c); |
||
| 82 | } |
||
| 83 | |||
| 84 | |||
| 85 | // USART receive complete interrupt |
||
| 86 | SIGNAL(SIG_UART_RECV) { |
||
| 87 | char c; |
||
| 88 | // Get the received character |
||
| 89 | c = UDR; |
||
| 90 | // Echo the character back |
||
| 91 | uartPutChar(c); |
||
| 92 | // place the received character into the receive buffer and move the tail |
||
| 93 | // rx_tail will count from 0 to 255... AND'ing it with 31 will continually |
||
| 94 | //wrap the index 0 to 31 |
||
| 95 | rx_buf[rx_tail & RX_MASK] = c; |
||
| 96 | rx_tail++; |
||
| 97 | } |
||
| 98 | |||
| 99 | |||
| 100 | // USART0 data register empty interrupt... another char can be transmitted if (tx0_head != tx0_tail) |
||
| 101 | SIGNAL(SIG_UART_DATA) { |
||
| 102 | // tx_head will count from 0 to 255... AND'ing it with 31 will continually |
||
| 103 | //wrap the index 0 to 31 |
||
| 104 | if (tx_head != tx_tail) { |
||
| 105 | UDR = tx_buf[tx_head & TX_MASK]; |
||
| 106 | tx_head++; |
||
| 107 | } |
||
| 108 | else { |
||
| 109 | // "~" is a one's compliment so UCSR0B = (UCSR0B AND 11011111) which disables udr empty interrupt |
||
| 110 | UCSRB &= ~(1<<UDRIE); |
||
| 111 | } |
||
| 112 | } |
||
| 113 | |||
| 114 | |||
| 115 | //string must be null-terminated |
||
| 116 | void uartPutString(char* str) { |
||
| 117 | while (*str != 0) { |
||
| 118 | uartPutChar(*str); |
||
| 119 | str++; |
||
| 120 | } |
||
| 121 | } |
||
| 122 | |||
| 123 | |||
| 124 | void uartPutUInt8(uint8_t number, uint8_t base) { |
||
| 125 | uint8_t a; |
||
| 126 | if ((a = number/base) != 0) { |
||
| 127 | uartPutUInt8(a, base); |
||
| 128 | } |
||
| 129 | uartPutChar("0123456789ABCDEF"[(uint8_t)(number%base)]); |
||
| 130 | } |
||
| 131 | |||
| 132 | |||
| 133 | void uartPutUInt16(uint16_t number, uint8_t base) { |
||
| 134 | uint16_t a; |
||
| 135 | if ((a = number/base) != 0) { |
||
| 136 | uartPutUInt16(a, base); |
||
| 137 | } |
||
| 138 | uartPutChar("0123456789ABCDEF"[(uint8_t)(number%base)]); |
||
| 139 | } |
||
| 140 | |||
| 141 | |||
| 142 | void uartNewLine(void) { |
||
| 143 | uartPutString("\n\r"); |
||
| 144 | } |