From 93e7d88f7556a3cc50cc8435a1c9c9c4d44f9e83 Mon Sep 17 00:00:00 2001 From: Hauke Petersen Date: Fri, 25 Jan 2019 11:41:21 +0100 Subject: [PATCH] cpu/nrf5x: reworked and fixed UART driver --- boards/nrf52840dk/include/periph_conf.h | 2 +- cpu/nrf52/include/periph_cpu.h | 3 - cpu/nrf5x_common/periph/uart.c | 241 ++++++++++++++---------- 3 files changed, 140 insertions(+), 106 deletions(-) diff --git a/boards/nrf52840dk/include/periph_conf.h b/boards/nrf52840dk/include/periph_conf.h index a3d143d765..feef124331 100644 --- a/boards/nrf52840dk/include/periph_conf.h +++ b/boards/nrf52840dk/include/periph_conf.h @@ -50,7 +50,7 @@ static const uart_conf_t uart_config[] = { }; #define UART_0_ISR (isr_uart0) -#define UART_1_ISR (isr_uart1) +#define UART_1_ISR (isr_uarte1) #define UART_NUMOF (sizeof(uart_config) / sizeof(uart_config[0])) /** @} */ diff --git a/cpu/nrf52/include/periph_cpu.h b/cpu/nrf52/include/periph_cpu.h index 27843d075e..b684f234bc 100644 --- a/cpu/nrf52/include/periph_cpu.h +++ b/cpu/nrf52/include/periph_cpu.h @@ -43,9 +43,6 @@ extern "C" { #define SPI_MOSISEL (dev(bus)->PSEL.MOSI) #define SPI_MISOSEL (dev(bus)->PSEL.MISO) #ifndef CPU_MODEL_NRF52840XXAA -#define UART_PIN_RTS (GPIO_UNDEF) -#define UART_PIN_CTS (GPIO_UNDEF) -#define UART_HWFLOWCTRL (0) #define UART_IRQN (UARTE0_UART0_IRQn) #endif /** @} */ diff --git a/cpu/nrf5x_common/periph/uart.c b/cpu/nrf5x_common/periph/uart.c index 12ade1daaa..148084071a 100644 --- a/cpu/nrf5x_common/periph/uart.c +++ b/cpu/nrf5x_common/periph/uart.c @@ -33,61 +33,54 @@ #include "periph/gpio.h" #ifdef CPU_MODEL_NRF52840XXAA +#define UART_INVALID (uart >= UART_NUMOF) +#define REG_BAUDRATE dev(uart)->BAUDRATE +#define REG_CONFIG dev(uart)->CONFIG #define PSEL_RXD dev(uart)->PSEL.RXD #define PSEL_TXD dev(uart)->PSEL.TXD -#define PSEL_RTS dev(uart)->PSEL.RTS -#define PSEL_CTS dev(uart)->PSEL.CTS #define UART_IRQN uart_config[uart].irqn #define UART_PIN_RX uart_config[uart].rx_pin #define UART_PIN_TX uart_config[uart].tx_pin #define UART_PIN_RTS uart_config[uart].rts_pin #define UART_PIN_CTS uart_config[uart].cts_pin -#define UART_HWFLOWCTRL (uart_config[uart].rts_pin != GPIO_UNDEF && \ - uart_config[uart].cts_pin != GPIO_UNDEF) +#define UART_HWFLOWCTRL (uart_config[uart].rts_pin != (uint8_t)GPIO_UNDEF && \ + uart_config[uart].cts_pin != (uint8_t)GPIO_UNDEF) #define ISR_CTX isr_ctx[uart] + /** * @brief Allocate memory for the interrupt context */ static uart_isr_ctx_t isr_ctx[UART_NUMOF]; -#else -#define PSEL_RXD dev(uart)->PSELRXD -#define PSEL_TXD dev(uart)->PSELTXD -#define PSEL_RTS dev(uart)->PSELRTS -#define PSEL_CTS dev(uart)->PSELCTS -#define UART_0_ISR isr_uart0 -#ifndef UART_PIN_RTS -#define UART_PIN_RTS GPIO_UNDEF -#endif -#ifndef UART_PIN_CTS -#define UART_PIN_CTS GPIO_UNDEF -#endif -#ifndef UART_HWFLOWCTRL -#define UART_HWFLOWCTRL 0 -#endif -#define ISR_CTX isr_ctx -/** - * @brief Allocate memory for the interrupt context - */ -static uart_isr_ctx_t isr_ctx; -#endif +static uint8_t rx_buf[UART_NUMOF]; -#ifdef CPU_MODEL_NRF52840XXAA static inline NRF_UARTE_Type *dev(uart_t uart) { return uart_config[uart].dev; } -static uint8_t rx_buf[UART_NUMOF]; -#else -static inline NRF_UART_Type *dev(uart_t uart) -{ - (void)uart; - return NRF_UART0; -} -#endif + +#else /* nrf51 and nrf52832 etc */ + +#define UART_INVALID (uart != 0) +#define REG_BAUDRATE NRF_UART0->BAUDRATE +#define REG_CONFIG NRF_UART0->CONFIG +#define PSEL_RXD NRF_UART0->PSELRXD +#define PSEL_TXD NRF_UART0->PSELTXD +#define UART_0_ISR isr_uart0 +#define ISR_CTX isr_ctx + +/** + * @brief Allocate memory for the interrupt context + */ +static uart_isr_ctx_t isr_ctx; + +#endif /* CPU_MODEL_NRF52840XXAA */ + int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) { - assert(uart < UART_NUMOF); + if (UART_INVALID) { + return UART_NODEV; + } /* remember callback addresses and argument */ ISR_CTX.rx_cb = rx_cb; @@ -95,11 +88,11 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) #ifdef CPU_FAM_NRF51 /* power on the UART device */ - dev(uart)->POWER = 1; + NRF_UART0->POWER = 1; #endif /* reset configuration registers */ - dev(uart)->CONFIG = 0; + REG_CONFIG = 0; /* configure RX pin */ if (rx_cb) { @@ -111,66 +104,81 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) gpio_init(UART_PIN_TX, GPIO_OUT); PSEL_TXD = UART_PIN_TX; +#ifdef CPU_MODEL_NRF52840XXAA /* enable HW-flow control if defined */ if (UART_HWFLOWCTRL) { /* set pin mode for RTS and CTS pins */ gpio_init(UART_PIN_RTS, GPIO_OUT); gpio_init(UART_PIN_CTS, GPIO_IN); /* configure RTS and CTS pins to use */ - PSEL_RTS = UART_PIN_RTS; - PSEL_CTS = UART_PIN_CTS; - dev(uart)->CONFIG |= UART_CONFIG_HWFC_Msk; /* enable HW flow control */ + dev(uart)->PSEL.RTS = UART_PIN_RTS; + dev(uart)->PSEL.CTS = UART_PIN_CTS; + REG_CONFIG |= UART_CONFIG_HWFC_Msk; /* enable HW flow control */ } else { - PSEL_RTS = 0xffffffff; /* pin disconnected */ - PSEL_CTS = 0xffffffff; /* pin disconnected */ + dev(uart)->PSEL.RTS = 0xffffffff; /* pin disconnected */ + dev(uart)->PSEL.CTS = 0xffffffff; /* pin disconnected */ } +#else +#if UART_HWFLOWCTRL + /* set pin mode for RTS and CTS pins */ + gpio_init(UART_PIN_RTS, GPIO_OUT); + gpio_init(UART_PIN_CTS, GPIO_IN); + /* configure RTS and CTS pins to use */ + NRF_UART0->PSELRTS = UART_PIN_RTS; + NRF_UART0->PSELCTS = UART_PIN_CTS; + REG_CONFIG |= UART_CONFIG_HWFC_Msk; /* enable HW flow control */ +#else + NRF_UART0->PSELRTS = 0xffffffff; /* pin disconnected */ + NRF_UART0->PSELCTS = 0xffffffff; /* pin disconnected */ +#endif +#endif /* select baudrate */ switch (baudrate) { case 1200: - dev(uart)->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud1200; + REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud1200; break; case 2400: - dev(uart)->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud2400; + REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud2400; break; case 4800: - dev(uart)->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud4800; + REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud4800; break; case 9600: - dev(uart)->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud9600; + REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud9600; break; case 14400: - dev(uart)->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud14400; + REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud14400; break; case 19200: - dev(uart)->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud19200; + REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud19200; break; case 28800: - dev(uart)->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud28800; + REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud28800; break; case 38400: - dev(uart)->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud38400; + REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud38400; break; case 57600: - dev(uart)->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud57600; + REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud57600; break; case 76800: - dev(uart)->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud76800; + REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud76800; break; case 115200: - dev(uart)->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud115200; + REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud115200; break; case 230400: - dev(uart)->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud230400; + REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud230400; break; case 250000: - dev(uart)->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud250000; + REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud250000; break; case 460800: - dev(uart)->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud460800; + REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud460800; break; case 921600: - dev(uart)->BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud921600; + REG_BAUDRATE = UART_BAUDRATE_BAUDRATE_Baud921600; break; default: return UART_NOBAUD; @@ -179,33 +187,37 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) /* enable the UART device */ #ifdef CPU_MODEL_NRF52840XXAA dev(uart)->ENABLE = UARTE_ENABLE_ENABLE_Enabled; - dev(uart)->RXD.MAXCNT = 1; - dev(uart)->RXD.PTR = (uint32_t)&rx_buf[uart]; #else - dev(uart)->ENABLE = UART_ENABLE_ENABLE_Enabled; - /* enable TX and RX*/ - dev(uart)->TASKS_STARTTX = 1; + NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Enabled; + NRF_UART0->TASKS_STARTTX = 1; #endif if (rx_cb) { +#ifdef CPU_MODEL_NRF52840XXAA + dev(uart)->RXD.MAXCNT = 1; + dev(uart)->RXD.PTR = (uint32_t)&rx_buf[uart]; + dev(uart)->INTENSET = UARTE_INTENSET_ENDRX_Msk; + dev(uart)->SHORTS |= UARTE_SHORTS_ENDRX_STARTRX_Msk; dev(uart)->TASKS_STARTRX = 1; +#else + NRF_UART0->INTENSET = UART_INTENSET_RXDRDY_Msk; + NRF_UART0->TASKS_STARTRX = 1; +#endif + /* enable global and receiving interrupt */ NVIC_EnableIRQ(UART_IRQN); -#ifdef CPU_MODEL_NRF52840XXAA - dev(uart)->INTENSET = UARTE_INTENSET_RXDRDY_Msk; -#else - dev(uart)->INTENSET = UART_INTENSET_RXDRDY_Msk; -#endif } return UART_OK; } + +#ifdef CPU_MODEL_NRF52840XXAA /* nrf52840 (using EasyDMA) */ + void uart_write(uart_t uart, const uint8_t *data, size_t len) { assert(uart < UART_NUMOF); -#ifdef CPU_MODEL_NRF52840XXAA /* nrf52840 uses EasyDMA to transmit data */ /* reset endtx flag */ dev(uart)->EVENTS_ENDTX = 0; /* set data to transfer to DMA TX pointer */ @@ -215,7 +227,46 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len) dev(uart)->TASKS_STARTTX = 1; /* wait for the end of transmission */ while (dev(uart)->EVENTS_ENDTX == 0) {} -#else +} + +void uart_poweron(uart_t uart) +{ + assert(uart < UART_NUMOF); + + if (isr_ctx[uart].rx_cb) { + NRF_UART0->TASKS_STARTRX = 1; + } +} + +void uart_poweroff(uart_t uart) +{ + assert(uart < UART_NUMOF); + + dev(uart)->TASKS_STOPRX = 1; +} + +static inline void irq_handler(uart_t uart) +{ + if (dev(uart)->EVENTS_ENDRX == 1) { + dev(uart)->EVENTS_ENDRX = 0; + + /* make sure we actually received new data */ + if (dev(uart)->RXD.AMOUNT == 0) { + return; + } + /* Process received byte */ + isr_ctx[uart].rx_cb(isr_ctx[uart].arg, rx_buf[uart]); + } + + cortexm_isr_end(); +} + +#else /* nrf51 and nrf52832 etc */ + +void uart_write(uart_t uart, const uint8_t *data, size_t len) +{ + (void)uart; + for (size_t i = 0; i < len; i++) { /* This section of the function is not thread safe: - another thread may mess up with the uart at the same time. @@ -226,61 +277,47 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len) thread may have not transmitted his data but will still exit the while loop. */ - /* reset ready flag */ - dev(uart)->EVENTS_TXDRDY = 0; + NRF_UART0->EVENTS_TXDRDY = 0; /* write data into transmit register */ - dev(uart)->TXD = data[i]; + NRF_UART0->TXD = data[i]; /* wait for any transmission to be done */ - while (dev(uart)->EVENTS_TXDRDY == 0) {} + while (NRF_UART0->EVENTS_TXDRDY == 0) {} } -#endif } void uart_poweron(uart_t uart) { - assert(uart < UART_NUMOF); + (void)uart; - dev(uart)->TASKS_STARTRX = 1; - dev(uart)->TASKS_STARTTX = 1; + NRF_UART0->TASKS_STARTTX = 1; + if (isr_ctx.rx_cb) { + NRF_UART0->TASKS_STARTRX = 1; + } } void uart_poweroff(uart_t uart) { - assert(uart < UART_NUMOF); - -#ifndef CPU_MODEL_NRF52840XXAA - dev(uart)->TASKS_SUSPEND; -#else (void)uart; -#endif + + NRF_UART0->TASKS_SUSPEND; } static inline void irq_handler(uart_t uart) { - assert(uart < UART_NUMOF); -#ifdef CPU_MODEL_NRF52840XXAA /* nrf52840 uses EasyDMA to receive data */ - if (dev(uart)->EVENTS_RXDRDY == 1) { - dev(uart)->EVENTS_RXDRDY = 0; - /* RXRDY doesn't mean that received byte is in RAM - so wait for ENDRX event */ - while(dev(uart)->EVENTS_ENDRX == 0) {} - dev(uart)->EVENTS_ENDRX = 0; - /* Process received byte */ - ISR_CTX.rx_cb(ISR_CTX.arg, rx_buf[uart]); - /* Restart RX task */ - dev(uart)->TASKS_STARTRX = 1; + (void)uart; + + if (NRF_UART0->EVENTS_RXDRDY == 1) { + NRF_UART0->EVENTS_RXDRDY = 0; + uint8_t byte = (uint8_t)(NRF_UART0->RXD & 0xff); + isr_ctx.rx_cb(isr_ctx.arg, byte); } -#else - if (dev(uart)->EVENTS_RXDRDY == 1) { - dev(uart)->EVENTS_RXDRDY = 0; - uint8_t byte = (uint8_t)(dev(uart)->RXD & 0xff); - ISR_CTX.rx_cb(ISR_CTX.arg, byte); - } -#endif + cortexm_isr_end(); } +#endif /* CPU_MODEL_NRF52840XXAA */ + #ifdef UART_0_ISR void UART_0_ISR(void) {