0,0 → 1,271 |
/************************************************************************* |
Title: Interrupt UART library with receive/transmit circular buffers |
Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury |
File: $Id: uart.c,v 1.6.2.2 2009/11/29 08:56:12 Peter Exp $ |
Software: AVR-GCC 4.1, AVR Libc 1.4.6 or higher |
Hardware: any AVR with built-in UART, |
License: GNU General Public License |
|
DESCRIPTION: |
An interrupt is generated when the UART has finished transmitting or |
receiving a byte. The interrupt handling routines use circular buffers |
for buffering received and transmitted data. |
|
The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define |
the buffer size in bytes. Note that these variables must be a |
power of 2. |
|
USAGE: |
Refere to the header file uart.h for a description of the routines. |
See also example test_uart.c. |
|
NOTES: |
Based on Atmel Application Note AVR306 |
|
LICENSE: |
Copyright (C) 2006 Peter Fleury |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
*************************************************************************/ |
#include <avr/io.h> |
#include <avr/interrupt.h> |
#include <avr/pgmspace.h> |
#include "uart1.h" |
|
/* |
* constants and macros |
*/ |
//#define __AVR_ATmega644P__ |
|
|
/* size of RX/TX buffers */ |
#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1) |
#define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1) |
|
#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK ) |
#error RX buffer size is not a power of 2 |
#endif |
#if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK ) |
#error TX buffer size is not a power of 2 |
#endif |
|
|
/* ATmega with two USART */ |
|
#define ATMEGA_USART1 |
#define UART1_RECEIVE_INTERRUPT SIG_USART1_RECV |
#define UART1_TRANSMIT_INTERRUPT SIG_USART1_DATA |
#define UART1_STATUS UCSR1A |
#define UART1_CONTROL UCSR1B |
#define UART1_DATA UDR1 |
#define UART1_UDRIE UDRIE1 |
|
|
|
/* |
* module global variables |
*/ |
|
|
static volatile unsigned char UART1_TxBuf[UART_TX_BUFFER_SIZE]; |
static volatile unsigned char UART1_RxBuf[UART_RX_BUFFER_SIZE]; |
static volatile unsigned char UART1_TxHead; |
static volatile unsigned char UART1_TxTail; |
static volatile unsigned char UART1_RxHead; |
static volatile unsigned char UART1_RxTail; |
static volatile unsigned char UART1_LastRxError; |
|
|
|
|
|
/* |
* these functions are only for ATmegas with two USART |
*/ |
|
SIGNAL(UART1_RECEIVE_INTERRUPT) |
/************************************************************************* |
Function: UART1 Receive Complete interrupt |
Purpose: called when the UART1 has received a character |
**************************************************************************/ |
{ |
unsigned char tmphead; |
unsigned char data; |
unsigned char usr; |
unsigned char lastRxError; |
|
|
/* read UART status register and UART data register */ |
usr = UART1_STATUS; |
data = UART1_DATA; |
|
/* */ |
lastRxError = (usr & (_BV(FE1)|_BV(DOR1)) ); |
|
/* calculate buffer index */ |
tmphead = ( UART1_RxHead + 1) & UART_RX_BUFFER_MASK; |
|
if ( tmphead == UART1_RxTail ) { |
/* error: receive buffer overflow */ |
lastRxError = UART_BUFFER_OVERFLOW >> 8; |
}else{ |
/* store new index */ |
UART1_RxHead = tmphead; |
/* store received data in buffer */ |
UART1_RxBuf[tmphead] = data; |
} |
UART1_LastRxError = lastRxError; |
} |
|
|
SIGNAL(UART1_TRANSMIT_INTERRUPT) |
/************************************************************************* |
Function: UART1 Data Register Empty interrupt |
Purpose: called when the UART1 is ready to transmit the next byte |
**************************************************************************/ |
{ |
unsigned char tmptail; |
|
|
if ( UART1_TxHead != UART1_TxTail) { |
/* calculate and store new buffer index */ |
tmptail = (UART1_TxTail + 1) & UART_TX_BUFFER_MASK; |
UART1_TxTail = tmptail; |
/* get one byte from buffer and write it to UART */ |
UART1_DATA = UART1_TxBuf[tmptail]; /* start transmission */ |
}else{ |
/* tx buffer empty, disable UDRE interrupt */ |
UART1_CONTROL &= ~_BV(UART1_UDRIE); |
} |
} |
|
|
/************************************************************************* |
Function: uart1_init() |
Purpose: initialize UART1 and set baudrate |
Input: baudrate using macro UART_BAUD_SELECT() |
Returns: none |
**************************************************************************/ |
void uart1_init(unsigned int baudrate) |
{ |
UART1_TxHead = 0; |
UART1_TxTail = 0; |
UART1_RxHead = 0; |
UART1_RxTail = 0; |
|
|
/* Set baud rate */ |
if ( baudrate & 0x8000 ) |
{ |
UART1_STATUS = (1<<U2X1); //Enable 2x speed |
baudrate &= ~0x8000; |
} |
UBRR1H = (unsigned char)(baudrate>>8); |
UBRR1L = (unsigned char) baudrate; |
|
/* Enable USART receiver and transmitter and receive complete interrupt */ |
UART1_CONTROL = _BV(RXCIE1)|(1<<RXEN1)|(1<<TXEN1); |
|
/* Set frame format: asynchronous, 8data, no parity, 1stop bit */ |
#ifdef URSEL1 |
UCSR1C = (1<<URSEL1)|(3<<UCSZ10); |
#else |
UCSR1C = (3<<UCSZ10); |
#endif |
}/* uart_init */ |
|
|
/************************************************************************* |
Function: uart1_getc() |
Purpose: return byte from ringbuffer |
Returns: lower byte: received byte from ringbuffer |
higher byte: last receive error |
**************************************************************************/ |
unsigned int uart1_getc(void) |
{ |
unsigned char tmptail; |
unsigned char data; |
|
|
if ( UART1_RxHead == UART1_RxTail ) { |
return UART_NO_DATA; /* no data available */ |
} |
|
/* calculate /store buffer index */ |
tmptail = (UART1_RxTail + 1) & UART_RX_BUFFER_MASK; |
UART1_RxTail = tmptail; |
|
/* get data from receive buffer */ |
data = UART1_RxBuf[tmptail]; |
|
return (UART1_LastRxError << 8) + data; |
|
}/* uart1_getc */ |
|
|
/************************************************************************* |
Function: uart1_putc() |
Purpose: write byte to ringbuffer for transmitting via UART |
Input: byte to be transmitted |
Returns: none |
**************************************************************************/ |
void uart1_putc(unsigned char data) |
{ |
unsigned char tmphead; |
|
|
tmphead = (UART1_TxHead + 1) & UART_TX_BUFFER_MASK; |
|
while ( tmphead == UART1_TxTail ){ |
;/* wait for free space in buffer */ |
} |
|
UART1_TxBuf[tmphead] = data; |
UART1_TxHead = tmphead; |
|
/* enable UDRE interrupt */ |
UART1_CONTROL |= _BV(UART1_UDRIE); |
|
}/* uart1_putc */ |
|
|
/************************************************************************* |
Function: uart1_puts() |
Purpose: transmit string to UART1 |
Input: string to be transmitted |
Returns: none |
**************************************************************************/ |
void uart1_puts(const char *s ) |
{ |
while (*s) |
uart1_putc(*s++); |
|
}/* uart1_puts */ |
|
|
/************************************************************************* |
Function: uart1_puts_p() |
Purpose: transmit string from program memory to UART1 |
Input: program memory string to be transmitted |
Returns: none |
**************************************************************************/ |
void uart1_puts_p(const char *progmem_s ) |
{ |
register char c; |
|
while ( (c = pgm_read_byte(progmem_s++)) ) |
uart1_putc(c); |
|
}/* uart1_puts_p */ |
|
|
|