avr: Clean up serial port register aliases

Define unique register aliases for all of the hardware serial port
definitions.  This makes it easier to deal with the AVR chips that use
different register names.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2018-04-25 10:13:07 -04:00
parent 22c49a7c3f
commit cf475a9a39
2 changed files with 38 additions and 31 deletions

View File

@ -110,6 +110,10 @@ config SERIAL_BAUD_U2X
depends on AVR_SERIAL && !SIMULAVR
bool
default y
config SERIAL_PORT
int
default 1 if MACH_at90usb1286 || MACH_at90usb646
default 0
config SIMULAVR
depends on MACH_atmega168 || MACH_atmega328 || MACH_atmega644p || MACH_atmega1284p

View File

@ -4,66 +4,69 @@
//
// This file may be distributed under the terms of the GNU GPLv3 license.
#include <avr/interrupt.h> // USART0_RX_vect
#include <avr/interrupt.h> // USART_RX_vect
#include "autoconf.h" // CONFIG_SERIAL_BAUD
#include "board/serial_irq.h" // serial_rx_byte
#include "sched.h" // DECL_INIT
// Define serial port registers on AT90USB1286
#if !defined(UCSR0A) && defined(UCSR1A)
#define UCSR0A UCSR1A
#define UCSR0B UCSR1B
#define UCSR0C UCSR1C
#define UBRR0 UBRR1
#define UDR0 UDR1
#define UCSZ01 UCSZ11
#define UCSZ00 UCSZ10
#define U2X0 U2X1
#define RXEN0 RXEN1
#define TXEN0 TXEN1
#define RXCIE0 RXCIE1
#define UDRIE0 UDRIE1
#define USART0_RX_vect USART1_RX_vect
#define USART0_UDRE_vect USART1_UDRE_vect
#endif
// Helper macros for defining serial port aliases
#define AVR_SERIAL_REG1(prefix, id, suffix) prefix ## id ## suffix
#define AVR_SERIAL_REG(prefix, id, suffix) AVR_SERIAL_REG1(prefix, id, suffix)
// Serial port register aliases
#define UCSRxA AVR_SERIAL_REG(UCSR, CONFIG_SERIAL_PORT, A)
#define UCSRxB AVR_SERIAL_REG(UCSR, CONFIG_SERIAL_PORT, B)
#define UCSRxC AVR_SERIAL_REG(UCSR, CONFIG_SERIAL_PORT, C)
#define UBRRx AVR_SERIAL_REG(UBRR, CONFIG_SERIAL_PORT,)
#define UDRx AVR_SERIAL_REG(UDR, CONFIG_SERIAL_PORT,)
#define UCSZx1 AVR_SERIAL_REG(UCSZ, CONFIG_SERIAL_PORT, 1)
#define UCSZx0 AVR_SERIAL_REG(UCSZ, CONFIG_SERIAL_PORT, 0)
#define U2Xx AVR_SERIAL_REG(U2X, CONFIG_SERIAL_PORT,)
#define RXENx AVR_SERIAL_REG(RXEN, CONFIG_SERIAL_PORT,)
#define TXENx AVR_SERIAL_REG(TXEN, CONFIG_SERIAL_PORT,)
#define RXCIEx AVR_SERIAL_REG(RXCIE, CONFIG_SERIAL_PORT,)
#define UDRIEx AVR_SERIAL_REG(UDRIE, CONFIG_SERIAL_PORT,)
// Define serial port registers on atmega168 / atmega328
#if defined(USART_RX_vect)
#define USART0_RX_vect USART_RX_vect
#define USART0_UDRE_vect USART_UDRE_vect
// The atmega168 / atmega328 doesn't have an ID in the irq names
#define USARTx_RX_vect USART_RX_vect
#define USARTx_UDRE_vect USART_UDRE_vect
#else
#define USARTx_RX_vect AVR_SERIAL_REG(USART, CONFIG_SERIAL_PORT, _RX_vect)
#define USARTx_UDRE_vect AVR_SERIAL_REG(USART, CONFIG_SERIAL_PORT, _UDRE_vect)
#endif
void
serial_init(void)
{
UCSR0A = CONFIG_SERIAL_BAUD_U2X ? (1<<U2X0) : 0;
UCSRxA = CONFIG_SERIAL_BAUD_U2X ? (1<<U2Xx) : 0;
uint32_t cm = CONFIG_SERIAL_BAUD_U2X ? 8 : 16;
UBRR0 = DIV_ROUND_CLOSEST(CONFIG_CLOCK_FREQ, cm * CONFIG_SERIAL_BAUD) - 1UL;
UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0) | (1<<UDRIE0);
UBRRx = DIV_ROUND_CLOSEST(CONFIG_CLOCK_FREQ, cm * CONFIG_SERIAL_BAUD) - 1UL;
UCSRxC = (1<<UCSZx1) | (1<<UCSZx0);
UCSRxB = (1<<RXENx) | (1<<TXENx) | (1<<RXCIEx) | (1<<UDRIEx);
}
DECL_INIT(serial_init);
// Rx interrupt - data available to be read.
ISR(USART0_RX_vect)
ISR(USARTx_RX_vect)
{
serial_rx_byte(UDR0);
serial_rx_byte(UDRx);
}
// Tx interrupt - data can be written to serial.
ISR(USART0_UDRE_vect)
ISR(USARTx_UDRE_vect)
{
uint8_t data;
int ret = serial_get_tx_byte(&data);
if (ret)
UCSR0B &= ~(1<<UDRIE0);
UCSRxB &= ~(1<<UDRIEx);
else
UDR0 = data;
UDRx = data;
}
// Enable tx interrupts
void
serial_enable_tx_irq(void)
{
UCSR0B |= 1<<UDRIE0;
UCSRxB |= 1<<UDRIEx;
}