Subversion Repositories HomeAutomation

Rev

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

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