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/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 */