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