avr-fw-modules/usart/at90/src/at90_usart.c

230 lines
4.4 KiB
C

#include <util/util.h>
#include <sys/atomic.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <io/usart.h>
#include <io/pipe.h>
#if defined( __AVR_AT90CAN128__ ) || defined ( __AVR_ATmega1284P__ ) || defined ( __AVR_ATmega1284__ )
#define HAS_USART0
#define USARTS 2
#else
#define USARTS 1
#endif
int at90_usart_configure (usart_t *usart,uint32_t baud,uint32_t config);
int at90_usart_mode_set (usart_t *usart,uint16_t mode);
int at90_usart_mode_clear (usart_t *usart,uint16_t mode);
typedef struct
{
volatile uint8_t UCSRA;
volatile uint8_t UCSRB;
volatile uint8_t UCSRC;
volatile uint8_t reserved;
union
{
volatile uint16_t UBRR;
struct
{
volatile uint8_t UBRRL;
volatile uint8_t UBRRH;
};
};
volatile uint8_t UDR;
} at90_usart_regs_t;
/*
struct at90_usart_regs* _at90_hw[] = {
(struct at90_usart*)0xC0,
(struct at90_usart*)0xC8
};
*/
typedef struct {
usart_t usart;
at90_usart_regs_t
*hw;
} at90_usart_t;
at90_usart_t at90_usarts[] = {
#if defined( HAS_USART0 )
// usart0
{
usart: {
configure: at90_usart_configure,
mode_set: at90_usart_mode_set,
mode_clear: at90_usart_mode_clear
},
hw: (at90_usart_regs_t*)0xC0
},
#endif
// usart1
{
usart: {
configure: at90_usart_configure,
mode_set: at90_usart_mode_set,
mode_clear: at90_usart_mode_clear
},
hw: (at90_usart_regs_t*)0xC8
}
};
usart_t* usart_device_get(int usart)
{
if ((usart >= 0) && (usart < USARTS)){
return &(at90_usarts[usart].usart);
};
return NULL;
};
int at90_usart_configure(usart_t *_usart,uint32_t baud,uint32_t config)
{
ATOMIC
at90_usart_t *usart = (at90_usart_t*)_usart;
uint32_t ubr = (__freq_cpu / ( 16 * baud )) - 1;
uint8_t b,c;
usart->hw->UCSRB = 0;
b = _BV(RXCIE1) | _BV(RXEN1) | _BV(TXEN1);
c = 0;
if (config & USART_PAR_E)
c |= _BV(UPM11);
else if (config & USART_PAR_O)
c |= _BV(UPM11) | _BV(UPM10);
if (config & USART_STOP2)
c |= _BV(USBS1);
if (config & USART_6BIT)
c |= _BV(UCSZ10);
else if (config & USART_7BIT)
c |= _BV(UCSZ11);
else if (config & USART_8BIT)
c |= _BV(UCSZ10) | _BV(UCSZ11);
usart->hw->UBRR = ubr;
usart->hw->UCSRA = 0; //_BV(U2X1);
usart->hw->UCSRC = c;
usart->hw->UCSRB = b;
return 0;
};
int at90_usart_mode_set (usart_t *_usart,uint16_t mode){
at90_usart_t *usart = (at90_usart_t*)_usart;
if (mode & USART_MODE_TX){
usart->hw->UCSRB |= _BV(UDRIE1);
};
if (mode & USART_MODE_RX){
usart->hw->UCSRB |= _BV(RXCIE1);
};
return ESUCCESS;
};
int at90_usart_mode_clear (usart_t *_usart,uint16_t mode){
at90_usart_t *usart = (at90_usart_t*)_usart;
if (mode & USART_MODE_TX){
usart->hw->UCSRB &= ~_BV(UDRIE1);
};
if (mode & USART_MODE_RX){
usart->hw->UCSRB &= ~_BV(RXCIE1);
};
return ESUCCESS;
};
#if defined( HAS_USART0 )
VECT(USART0_UDRE_vect){
#if defined(__USART_BUFFER__) // buffer based i/o
if (buffer_free( &(at90_usarts[0].usart.tx) ) > 0){
at90_usarts[0].hw->UDR = buffer_byte( &(at90_usarts[0].usart.tx) );
} else {
at90_usarts[0].hw->UCSRB &= ~_BV(UDRIE1);
};
#else
int ch = usart_fifo_read( &(at90_usarts[0].usart.tx) );
if (ch < 0){
at90_usarts[0].hw->UCSRB &= ~_BV(UDRIE1);
} else {
at90_usarts[0].hw->UDR = ch;
};
#endif
};
VECT(USART0_RX_vect){
#if defined(__USART_BUFFER__) // buffer based i/o
if (buffer_free( &(at90_usarts[0].usart.rx) ) > 0){
buffer_byte( &(at90_usarts[0].usart.rx) ) = at90_usarts[0].hw->UDR;
} else {
at90_usarts[0].hw->UDR;
};
#else
usart_fifo_write( &(at90_usarts[0].usart.rx), at90_usarts[0].hw->UDR );
#endif
};
#endif
VECT(USART1_UDRE_vect){
#if defined(__USART_BUFFER__) // buffer based i/o
if (buffer_free( &(at90_usarts[USARTS - 1].usart.tx) ) > 0){
at90_usarts[USARTS - 1].hw->UDR = buffer_byte( &(at90_usarts[USARTS - 1].usart.tx) );
} else {
at90_usarts[USARTS - 1].hw->UCSRB &= ~_BV(UDRIE1);
};
#else
int ch = usart_fifo_read( &(at90_usarts[USARTS - 1].usart.tx) );
if (ch < 0){
at90_usarts[USARTS - 1].hw->UCSRB &= ~_BV(UDRIE1);
} else {
at90_usarts[USARTS - 1].hw->UDR = ch;
};
#endif
};
VECT(USART1_RX_vect){
#if defined(__USART_BUFFER__) // buffer based i/o
if (buffer_free( &(at90_usarts[USARTS - 1].usart.rx) ) > 0){
buffer_byte( &(at90_usarts[USARTS - 1].usart.rx) ) = at90_usarts[USARTS - 1].hw->UDR;
} else {
at90_usarts[USARTS - 1].hw->UDR;
};
#else
usart_fifo_write( &(at90_usarts[USARTS - 1].usart.rx), at90_usarts[USARTS - 1].hw->UDR );
#endif
};