Subversion Repositories HomeAutomation

Rev

Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
29 jimmy 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
 
30 jimmy 147
ISR(UART0_RECEIVE_INTERRUPT)
29 jimmy 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
 
30 jimmy 190
ISR(UART0_TRANSMIT_INTERRUPT)
29 jimmy 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 */