From 6c6013b8980d48718c2e48312cdc6bca25c2efcf Mon Sep 17 00:00:00 2001 From: George Oikonomou Date: Wed, 15 May 2013 12:59:49 +0100 Subject: [PATCH] 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 --- cpu/cc2538/dev/uart.c | 99 ++++++++++++++++++++++----------- cpu/cc2538/dev/uart.h | 7 +++ platform/cc2538dk/dev/board.h | 3 + platform/cc2538dk/startup-gcc.c | 19 +++++-- 4 files changed, 91 insertions(+), 37 deletions(-) diff --git a/cpu/cc2538/dev/uart.c b/cpu/cc2538/dev/uart.c index 00595f1c2..a83f559cb 100644 --- a/cpu/cc2538/dev/uart.c +++ b/cpu/cc2538/dev/uart.c @@ -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)) { diff --git a/cpu/cc2538/dev/uart.h b/cpu/cc2538/dev/uart.h index 58ce01dbe..dfb54fc56 100644 --- a/cpu/cc2538/dev/uart.h +++ b/cpu/cc2538/dev/uart.h @@ -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 /** @} */ /*---------------------------------------------------------------------------*/ /** diff --git a/platform/cc2538dk/dev/board.h b/platform/cc2538dk/dev/board.h index dd5637dda..be7b5e091 100644 --- a/platform/cc2538dk/dev/board.h +++ b/platform/cc2538dk/dev/board.h @@ -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 diff --git a/platform/cc2538dk/startup-gcc.c b/platform/cc2538dk/startup-gcc.c index 00ae2eadf..239f5a3d4 100644 --- a/platform/cc2538dk/startup-gcc.c +++ b/platform/cc2538dk/startup-gcc.c @@ -38,6 +38,7 @@ */ #include "contiki.h" #include "reg.h" +#include "uart.h" #include @@ -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 */