/*! \file uart2.c \brief Dual UART driver with buffer support. */
//*****************************************************************************
//
// File Name : 'uart2.c'
// Title : Dual UART driver with buffer support
// Author : Pascal Stang - Copyright (C) 2000-2004
// Created : 11/20/2000
// Revised : 07/04/2004
// Version : 1.0
// Target MCU : ATMEL AVR Series
// Editor Tabs : 4
//
// Description : This is a UART driver for AVR-series processors with two
// hardware UARTs such as the mega161 and mega128
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************
#include <avr/io.h>
#include <avr/interrupt.h>
#include "buffer.h"
#include "uart2.h"
// UART global variables
// flag variables
volatile u08 uartReadyTx[2];
volatile u08 uartBufferedTx[2];
// receive and transmit buffers
cBuffer uartRxBuffer[2];
cBuffer uartTxBuffer[2];
unsigned short uartRxOverflow[2];
#ifndef UART_BUFFER_EXTERNAL_RAM
// using internal ram,
// automatically allocate space in ram for each buffer
static char uart0RxData[UART0_RX_BUFFER_SIZE];
static char uart0TxData[UART0_TX_BUFFER_SIZE];
static char uart1RxData[UART1_RX_BUFFER_SIZE];
static char uart1TxData[UART1_TX_BUFFER_SIZE];
#endif
typedef void (*voidFuncPtru08)(unsigned char);
volatile static voidFuncPtru08 UartRxFunc[2];
void uartInit(void)
{
// initialize both uarts
uart0Init();
uart1Init();
}
void uart0Init(void)
{
// initialize the buffers
uart0InitBuffers();
// initialize user receive handlers
UartRxFunc[0] = 0;
// enable RxD/TxD and interrupts
outb(UCSR0B, BV(RXCIE)|BV(TXCIE)|BV(RXEN)|BV(TXEN));
// set default baud rate
uartSetBaudRate(0, UART0_DEFAULT_BAUD_RATE);
// initialize states
uartReadyTx[0] = TRUE;
uartBufferedTx[0] = FALSE;
// clear overflow count
uartRxOverflow[0] = 0;
// enable interrupts
sei();
}
void uart1Init(void)
{
// initialize the buffers
uart1InitBuffers();
// initialize user receive handlers
UartRxFunc[1] = 0;
// enable RxD/TxD and interrupts
outb(UCSR1B, BV(RXCIE)|BV(TXCIE)|BV(RXEN)|BV(TXEN));
// set default baud rate
uartSetBaudRate(1, UART1_DEFAULT_BAUD_RATE);
// initialize states
uartReadyTx[1] = TRUE;
uartBufferedTx[1] = FALSE;
// clear overflow count
uartRxOverflow[1] = 0;
// enable interrupts
sei();
}
void uart0InitBuffers(void)
{
#ifndef UART_BUFFER_EXTERNAL_RAM
// initialize the UART0 buffers
bufferInit(&uartRxBuffer[0], uart0RxData, UART0_RX_BUFFER_SIZE);
bufferInit(&uartTxBuffer[0], uart0TxData, UART0_TX_BUFFER_SIZE);
#else
// initialize the UART0 buffers
bufferInit(&uartRxBuffer[0], (u08*) UART0_RX_BUFFER_ADDR, UART0_RX_BUFFER_SIZE);
bufferInit(&uartTxBuffer[0], (u08*) UART0_TX_BUFFER_ADDR, UART0_TX_BUFFER_SIZE);
#endif
}
void uart1InitBuffers(void)
{
#ifndef UART_BUFFER_EXTERNAL_RAM
// initialize the UART1 buffers
bufferInit(&uartRxBuffer[1], uart1RxData, UART1_RX_BUFFER_SIZE);
bufferInit(&uartTxBuffer[1], uart1TxData, UART1_TX_BUFFER_SIZE);
#else
// initialize the UART1 buffers
bufferInit(&uartRxBuffer[1], (u08*) UART1_RX_BUFFER_ADDR, UART1_RX_BUFFER_SIZE);
bufferInit(&uartTxBuffer[1], (u08*) UART1_TX_BUFFER_ADDR, UART1_TX_BUFFER_SIZE);
#endif
}
void uartSetRxHandler(u08 nUart, void (*rx_func)(unsigned char c))
{
// make sure the uart number is within bounds
if(nUart < 2)
{
// set the receive interrupt to run the supplied user function
UartRxFunc[nUart] = rx_func;
}
}
void uartSetBaudRate(u08 nUart, u32 baudrate)
{
// calculate division factor for requested baud rate, and set it
u16 bauddiv = ((F_CPU+(baudrate*8L))/(baudrate*16L)-1);
if(nUart)
{
outb(UBRR1L, bauddiv);
#ifdef UBRR1H
outb(UBRR1H, bauddiv>>8);
#endif
}
else
{
outb(UBRR0L, bauddiv);
#ifdef UBRR0H
outb(UBRR0H, bauddiv>>8);
#endif
}
}
cBuffer* uartGetRxBuffer(u08 nUart)
{
// return rx buffer pointer
return &uartRxBuffer[nUart];
}
cBuffer* uartGetTxBuffer(u08 nUart)
{
// return tx buffer pointer
return &uartTxBuffer[nUart];
}
void uartSendByte(u08 nUart, u08 txData)
{
// wait for the transmitter to be ready
// while(!uartReadyTx[nUart]);
// send byte
if(nUart)
{
while(!(UCSR1A & (1<<UDRE)));
outb(UDR1, txData);
}
else
{
while(!(UCSR0A & (1<<UDRE)));
outb(UDR0, txData);
}
// set ready state to FALSE
uartReadyTx[nUart] = FALSE;
}
void uart0SendByte(u08 data)
{
// send byte on UART0
uartSendByte(0, data);
}
void uart1SendByte(u08 data)
{
// send byte on UART1
uartSendByte(1, data);
}
int uart0GetByte(void)
{
// get single byte from receive buffer (if available)
u08 c;
if(uartReceiveByte(0,&c))
return c;
else
return -1;
}
int uart1GetByte(void)
{
// get single byte from receive buffer (if available)
u08 c;
if(uartReceiveByte(1,&c))
return c;
else
return -1;
}
u08 uartReceiveByte(u08 nUart, u08* rxData)
{
// make sure we have a receive buffer
if(uartRxBuffer[nUart].size)
{
// make sure we have data
if(uartRxBuffer[nUart].datalength)
{
// get byte from beginning of buffer
*rxData = bufferGetFromFront(&uartRxBuffer[nUart]);
return TRUE;
}
else
return FALSE; // no data
}
else
return FALSE; // no buffer
}
void uartFlushReceiveBuffer(u08 nUart)
{
// flush all data from receive buffer
bufferFlush(&uartRxBuffer[nUart]);
}
u08 uartReceiveBufferIsEmpty(u08 nUart)
{
return (uartRxBuffer[nUart].datalength == 0);
}
void uartAddToTxBuffer(u08 nUart, u08 data)
{
// add data byte to the end of the tx buffer
bufferAddToEnd(&uartTxBuffer[nUart], data);
}
void uart0AddToTxBuffer(u08 data)
{
uartAddToTxBuffer(0,data);
}
void uart1AddToTxBuffer(u08 data)
{
uartAddToTxBuffer(1,data);
}
void uartSendTxBuffer(u08 nUart)
{
// turn on buffered transmit
uartBufferedTx[nUart] = TRUE;
// send the first byte to get things going by interrupts
uartSendByte(nUart, bufferGetFromFront(&uartTxBuffer[nUart]));
}
u08 uartSendBuffer(u08 nUart, char *buffer, u16 nBytes)
{
register u08 first;
register u16 i;
// check if there's space (and that we have any bytes to send at all)
if((uartTxBuffer[nUart].datalength + nBytes < uartTxBuffer[nUart].size) && nBytes)
{
// grab first character
first = *buffer++;
// copy user buffer to uart transmit buffer
for(i = 0; i < nBytes-1; i++)
{
// put data bytes at end of buffer
bufferAddToEnd(&uartTxBuffer[nUart], *buffer++);
}
// send the first byte to get things going by interrupts
uartBufferedTx[nUart] = TRUE;
uartSendByte(nUart, first);
// return success
return TRUE;
}
else
{
// return failure
return FALSE;
}
}
// UART Transmit Complete Interrupt Function
void uartTransmitService(u08 nUart)
{
// check if buffered tx is enabled
if(uartBufferedTx[nUart])
{
// check if there's data left in the buffer
if(uartTxBuffer[nUart].datalength)
{
// send byte from top of buffer
if(nUart)
outb(UDR1, bufferGetFromFront(&uartTxBuffer[1]) );
else
outb(UDR0, bufferGetFromFront(&uartTxBuffer[0]) );
}
else
{
// no data left
uartBufferedTx[nUart] = FALSE;
// return to ready state
uartReadyTx[nUart] = TRUE;
}
}
else
{
// we're using single-byte tx mode
// indicate transmit complete, back to ready
uartReadyTx[nUart] = TRUE;
}
}
// UART Receive Complete Interrupt Function
void uartReceiveService(u08 nUart)
{
u08 c;
// get received char
if(nUart)
c = inb(UDR1);
else
c = inb(UDR0);
// if there's a user function to handle this receive event
if(UartRxFunc[nUart])
{
// call it and pass the received data
UartRxFunc[nUart](c);
}
else
{
// otherwise do default processing
// put received char in buffer
// check if there's space
if( !bufferAddToEnd(&uartRxBuffer[nUart], c) )
{
// no space in buffer
// count overflow
uartRxOverflow[nUart]++;
}
}
}
UART_INTERRUPT_HANDLER(SIG_UART0_TRANS)
{
// service UART0 transmit interrupt
uartTransmitService(0);
}
UART_INTERRUPT_HANDLER(SIG_UART1_TRANS)
{
// service UART1 transmit interrupt
uartTransmitService(1);
}
UART_INTERRUPT_HANDLER(SIG_UART0_RECV)
{
// service UART0 receive interrupt
uartReceiveService(0);
}
UART_INTERRUPT_HANDLER(SIG_UART1_RECV)
{
// service UART1 receive interrupt
uartReceiveService(1);
}
|