Make the CC2538 UART driver more configurable

* We can now very easily switch between UART0 and UART1 through a define
* We can also configure the UART RX and TX port/pin through defines
This commit is contained in:
George Oikonomou 2013-05-15 12:59:49 +01:00 committed by George Oikonomou
parent 1f76b7d0f9
commit 6c6013b898
4 changed files with 91 additions and 37 deletions

View File

@ -48,49 +48,82 @@
static int (* input_handler)(unsigned char c);
/*---------------------------------------------------------------------------*/
/*
* Once we know what UART we're on, configure correct values to be written to
* the correct registers
*/
#if UART_BASE==UART_1_BASE
/* Running, in sleep, in deep sleep, enable the clock for the correct UART */
#define SYS_CTRL_RCGCUART_UART SYS_CTRL_RCGCUART_UART1
#define SYS_CTRL_SCGCUART_UART SYS_CTRL_SCGCUART_UART1
#define SYS_CTRL_DCGCUART_UART SYS_CTRL_DCGCUART_UART1
#define NVIC_INT_UART NVIC_INT_UART1
#define IOC_PXX_SEL_UART_TXD IOC_PXX_SEL_UART1_TXD
#define IOC_UARTRXD_UART IOC_UARTRXD_UART1
#else /* Defaults for UART0 */
#define SYS_CTRL_RCGCUART_UART SYS_CTRL_RCGCUART_UART0
#define SYS_CTRL_SCGCUART_UART SYS_CTRL_SCGCUART_UART0
#define SYS_CTRL_DCGCUART_UART SYS_CTRL_DCGCUART_UART0
#define NVIC_INT_UART NVIC_INT_UART0
#define IOC_PXX_SEL_UART_TXD IOC_PXX_SEL_UART0_TXD
#define IOC_UARTRXD_UART IOC_UARTRXD_UART0
#endif
/*---------------------------------------------------------------------------*/
static void
reset(void)
{
uint32_t lchr;
/* Make sure the UART is disabled before trying to configure it */
REG(UART_0_BASE | UART_CTL) = UART_CTL_TXE | UART_CTL_RXE;
REG(UART_BASE | UART_CTL) = UART_CTL_TXE | UART_CTL_RXE;
/* Clear error status */
REG(UART_0_BASE | UART_ECR) = 0xFF;
REG(UART_BASE | UART_ECR) = 0xFF;
/* Store LCHR configuration */
lchr = REG(UART_0_BASE | UART_LCRH);
lchr = REG(UART_BASE | UART_LCRH);
/* Flush FIFOs by clearing LCHR.FEN */
REG(UART_0_BASE | UART_LCRH) = 0;
REG(UART_BASE | UART_LCRH) = 0;
/* Restore LCHR configuration */
REG(UART_0_BASE | UART_LCRH) = lchr;
REG(UART_BASE | UART_LCRH) = lchr;
/* UART Enable */
REG(UART_0_BASE | UART_CTL) |= UART_CTL_UARTEN;
REG(UART_BASE | UART_CTL) |= UART_CTL_UARTEN;
}
/*---------------------------------------------------------------------------*/
void
uart_init(void)
{
/* Enable clock for the UART while Running, in Sleep and Deep Sleep */
REG(SYS_CTRL_RCGCUART) |= SYS_CTRL_RCGCUART_UART0;
REG(SYS_CTRL_SCGCUART) |= SYS_CTRL_DCGCUART_UART0;
REG(SYS_CTRL_DCGCUART) |= SYS_CTRL_DCGCUART_UART0;
REG(SYS_CTRL_RCGCUART) |= SYS_CTRL_RCGCUART_UART;
REG(SYS_CTRL_SCGCUART) |= SYS_CTRL_SCGCUART_UART;
REG(SYS_CTRL_DCGCUART) |= SYS_CTRL_DCGCUART_UART;
/* Run on SYS_DIV */
REG(UART_0_BASE | UART_CC) = 0;
REG(UART_BASE | UART_CC) = 0;
/* PA1: UART TX */
REG(IOC_PA1_SEL) = IOC_PXX_SEL_UART0_TXD;
/*
* Select the UARTx RX pin by writing to the IOC_UARTRXD_UARTn register
*
* The value to be written will be on of the IOC_INPUT_SEL_Pxn defines from
* ioc.h. The value can also be calculated as:
*
* (port << 3) + pin
*/
REG(IOC_UARTRXD_UART) = (UART_RX_PORT << 3) + UART_RX_PIN;
/* PA0: UART RX */
REG(IOC_UARTRXD_UART0) = IOC_INPUT_SEL_PA0;
/* Pad Control: PA1 Output Enable */
REG(IOC_PA1_OVER) = IOC_OVERRIDE_OE;
/*
* Pad Control for the TX pin:
* - Set function to UART0 TX
* - Output Enable
*/
ioc_set_sel(UART_TX_PORT, UART_TX_PIN, IOC_PXX_SEL_UART_TXD);
ioc_set_over(UART_TX_PORT, UART_TX_PIN, IOC_OVERRIDE_OE);
/* Set PA[1:0] to peripheral mode */
REG(GPIO_A_BASE | GPIO_AFSEL) |= (0x00000002 | 0x00000001);
@ -100,27 +133,27 @@ uart_init(void)
* Acknowledge RX and RX Timeout
* Acknowledge Framing, Overrun and Break Errors
*/
REG(UART_0_BASE | UART_IM) = UART_IM_RXIM | UART_IM_RTIM;
REG(UART_0_BASE | UART_IM) |= UART_IM_OEIM | UART_IM_BEIM | UART_IM_FEIM;
REG(UART_BASE | UART_IM) = UART_IM_RXIM | UART_IM_RTIM;
REG(UART_BASE | UART_IM) |= UART_IM_OEIM | UART_IM_BEIM | UART_IM_FEIM;
REG(UART_0_BASE | UART_IFLS) =
REG(UART_BASE | UART_IFLS) =
UART_IFLS_RXIFLSEL_1_8 | UART_IFLS_TXIFLSEL_1_2;
/* Make sure the UART is disabled before trying to configure it */
REG(UART_0_BASE | UART_CTL) = UART_CTL_TXE | UART_CTL_RXE;
REG(UART_BASE | UART_CTL) = UART_CTL_TXE | UART_CTL_RXE;
/* Baud Rate Generation */
REG(UART_0_BASE | UART_IBRD) = UART_CONF_IBRD;
REG(UART_0_BASE | UART_FBRD) = UART_CONF_FBRD;
REG(UART_BASE | UART_IBRD) = UART_CONF_IBRD;
REG(UART_BASE | UART_FBRD) = UART_CONF_FBRD;
/* UART Control: 8N1 with FIFOs */
REG(UART_0_BASE | UART_LCRH) = UART_LCRH_WLEN_8 | UART_LCRH_FEN;
REG(UART_BASE | UART_LCRH) = UART_LCRH_WLEN_8 | UART_LCRH_FEN;
/* UART Enable */
REG(UART_0_BASE | UART_CTL) |= UART_CTL_UARTEN;
REG(UART_BASE | UART_CTL) |= UART_CTL_UARTEN;
/* Enable UART0 Interrupts */
nvic_interrupt_enable(NVIC_INT_UART0);
nvic_interrupt_enable(NVIC_INT_UART);
}
/*---------------------------------------------------------------------------*/
void
@ -133,9 +166,9 @@ void
uart_write_byte(uint8_t b)
{
/* Block if the TX FIFO is full */
while(REG(UART_0_BASE | UART_FR) & UART_FR_TXFF);
while(REG(UART_BASE | UART_FR) & UART_FR_TXFF);
REG(UART_0_BASE | UART_DR) = b;
REG(UART_BASE | UART_DR) = b;
}
/*---------------------------------------------------------------------------*/
void
@ -147,18 +180,18 @@ uart_isr(void)
/* Store the current MIS and clear all flags early, except the RTM flag.
* This will clear itself when we read out the entire FIFO contents */
mis = REG(UART_0_BASE | UART_MIS) & 0x0000FFFF;
mis = REG(UART_BASE | UART_MIS) & 0x0000FFFF;
REG(UART_0_BASE | UART_ICR) = 0x0000FFBF;
REG(UART_BASE | UART_ICR) = 0x0000FFBF;
if(mis & (UART_MIS_RXMIS | UART_MIS_RTMIS)) {
while(!(REG(UART_0_BASE | UART_FR) & UART_FR_RXFE)) {
while(!(REG(UART_BASE | UART_FR) & UART_FR_RXFE)) {
if(input_handler != NULL) {
input_handler((unsigned char)(REG(UART_0_BASE | UART_DR) & 0xFF));
input_handler((unsigned char)(REG(UART_BASE | UART_DR) & 0xFF));
} else {
/* To prevent an Overrun Error, we need to flush the FIFO even if we
* don't have an input_handler. Use mis as a data trash can */
mis = REG(UART_0_BASE | UART_DR);
mis = REG(UART_BASE | UART_DR);
}
}
} else if(mis & (UART_MIS_OEMIS | UART_MIS_BEMIS | UART_MIS_FEMIS)) {

View File

@ -52,6 +52,13 @@
*/
#define UART_0_BASE 0x4000C000
#define UART_1_BASE 0x4000D000
/* Default to UART 0 unless the configuration tells us otherwise */
#ifdef UART_CONF_BASE
#define UART_BASE UART_CONF_BASE
#else
#define UART_BASE UART_0_BASE
#endif
/** @} */
/*---------------------------------------------------------------------------*/
/**

View File

@ -111,8 +111,11 @@
* - CTS: PB0 (Can only be used with UART1)
* - RTS: PD3 (Can only be used with UART1)
*
* We configure the port to use UART0. To use UART1, change UART_CONF_BASE
* @{
*/
#define UART_CONF_BASE UART_0_BASE
#define UART_RX_PORT GPIO_A_NUM
#define UART_RX_PIN 0

View File

@ -38,6 +38,7 @@
*/
#include "contiki.h"
#include "reg.h"
#include "uart.h"
#include <stdint.h>
@ -71,12 +72,22 @@ void usb_isr(void);
#define usb_isr default_handler
#endif
/* Likewise for the UART ISR */
/* Likewise for the UART[01] ISRs */
#if UART_CONF_ENABLE
void uart_isr(void);
#if UART_BASE==UART_1_BASE
#define uart0_isr default_handler
#define uart1_isr uart_isr
#else
#define uart_isr default_handler
#define uart0_isr uart_isr
#define uart1_isr default_handler
#endif
#else /* UART_CONF_ENABLE */
#define uart0_isr default_handler
#define uart1_isr default_handler
#endif /* UART_CONF_ENABLE */
/*---------------------------------------------------------------------------*/
/* Allocate stack space */
static unsigned long stack[512];
@ -123,8 +134,8 @@ void(*const vectors[])(void) =
gpio_port_c_isr, /* 18 GPIO Port C */
gpio_port_d_isr, /* 19 GPIO Port D */
0, /* 20 none */
uart_isr, /* 21 UART0 Rx and Tx */
default_handler, /* 22 UART1 Rx and Tx */
uart0_isr, /* 21 UART0 Rx and Tx */
uart1_isr, /* 22 UART1 Rx and Tx */
default_handler, /* 23 SSI0 Rx and Tx */
default_handler, /* 24 I2C Master and Slave */
0, /* 25 Reserved */