From e2da880b5fcf9c200123035f675753f5488ffecc Mon Sep 17 00:00:00 2001 From: Stephen Caudle Date: Thu, 23 Jul 2015 23:39:51 -0400 Subject: Cleanup nRF51 serial driver Use values from bitfields header. Also convert notify1 function to be non-blocking, which seems to be how most of the other serial drivers are implemented. --- demos/NRF51/RT-WVSHARE_BLE400/main.c | 4 +- os/hal/ports/NRF51/NRF51822/serial_lld.c | 188 ++++++++++++++++++++----------- os/hal/ports/NRF51/NRF51822/serial_lld.h | 22 +++- 3 files changed, 140 insertions(+), 74 deletions(-) diff --git a/demos/NRF51/RT-WVSHARE_BLE400/main.c b/demos/NRF51/RT-WVSHARE_BLE400/main.c index 4f5e49d..d0b18cc 100644 --- a/demos/NRF51/RT-WVSHARE_BLE400/main.c +++ b/demos/NRF51/RT-WVSHARE_BLE400/main.c @@ -39,8 +39,8 @@ int main(void) { SerialConfig serial_config = { .speed = 38400, - .tx_pin = UART_TX, - .rx_pin = UART_RX, + .tx_pad = UART_TX, + .rx_pad = UART_RX, }; /* diff --git a/os/hal/ports/NRF51/NRF51822/serial_lld.c b/os/hal/ports/NRF51/NRF51822/serial_lld.c index 1783b92..bc4a9b6 100644 --- a/os/hal/ports/NRF51/NRF51822/serial_lld.c +++ b/os/hal/ports/NRF51/NRF51822/serial_lld.c @@ -32,9 +32,6 @@ /* Driver local definitions. */ /*===========================================================================*/ -#define INVALID_BAUDRATE 0xFFFFFFFF -#define INVALID_PIN 0xFF - /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ @@ -53,8 +50,8 @@ SerialDriver SD1; */ static const SerialConfig default_config = { .speed = 38400, - .tx_pin = INVALID_PIN, - .rx_pin = INVALID_PIN, + .tx_pad = NRF51_SERIAL_PAD_DISCONNECTED, + .rx_pad = NRF51_SERIAL_PAD_DISCONNECTED, }; /*===========================================================================*/ @@ -64,27 +61,62 @@ static const SerialConfig default_config = { /* * @brief Maps a baudrate speed to a BAUDRATE register value. */ -static uint32_t regval_from_baudrate(uint32_t speed) + +/** + * @brief Common UART configuration. + * + */ +static void configure_uart(const SerialConfig *config) { - switch (speed) { - case 1200: return 0x0004F000; - case 2400: return 0x0009D000; - case 4800: return 0x0013B000; - case 9600: return 0x00275000; - case 14400: return 0x003B0000; - case 19200: return 0x004EA000; - case 28800: return 0x0075F000; - case 38400: return 0x009D5000; - case 57600: return 0x00EBF000; - case 76800: return 0x013A9000; - case 115200: return 0x01D7E000; - case 230400: return 0x03AFB000; - case 250000: return 0x04000000; - case 460800: return 0x075F7000; - case 921600: return 0x0EBEDFA4; - case 1000000: return 0x10000000; + /* TODO: Add support for CTS/RTS! */ + uint32_t speed = UART_BAUDRATE_BAUDRATE_Baud250000; + + switch (config->speed) { + case 1200: speed = UART_BAUDRATE_BAUDRATE_Baud1200; break; + case 2400: speed = UART_BAUDRATE_BAUDRATE_Baud2400; break; + case 4800: speed = UART_BAUDRATE_BAUDRATE_Baud4800; break; + case 9600: speed = UART_BAUDRATE_BAUDRATE_Baud9600; break; + case 14400: speed = UART_BAUDRATE_BAUDRATE_Baud14400; break; + case 19200: speed = UART_BAUDRATE_BAUDRATE_Baud19200; break; + case 28800: speed = UART_BAUDRATE_BAUDRATE_Baud28800; break; + case 38400: speed = UART_BAUDRATE_BAUDRATE_Baud38400; break; + case 57600: speed = UART_BAUDRATE_BAUDRATE_Baud57600; break; + case 76800: speed = UART_BAUDRATE_BAUDRATE_Baud76800; break; + case 115200: speed = UART_BAUDRATE_BAUDRATE_Baud115200; break; + case 230400: speed = UART_BAUDRATE_BAUDRATE_Baud230400; break; + case 250000: speed = UART_BAUDRATE_BAUDRATE_Baud250000; break; + case 460800: speed = UART_BAUDRATE_BAUDRATE_Baud460800; break; + case 921600: speed = UART_BAUDRATE_BAUDRATE_Baud921600; break; + case 1000000: speed = UART_BAUDRATE_BAUDRATE_Baud1M; break; + default: osalDbgAssert(0, "invalid baudrate"); break; + }; + + /* Configure PINs */ + if (config->tx_pad != NRF51_SERIAL_PAD_DISCONNECTED) { + palSetPadMode(IOPORT1, config->tx_pad, PAL_MODE_OUTPUT_PUSHPULL); + NRF_UART0->PSELTXD = config->tx_pad; + } + if (config->rx_pad != NRF51_SERIAL_PAD_DISCONNECTED) { + palSetPadMode(IOPORT1, config->rx_pad, PAL_MODE_INPUT); + NRF_UART0->PSELRXD = config->rx_pad; + } + + NRF_UART0->BAUDRATE = speed; + NRF_UART0->CONFIG = (UART_CONFIG_PARITY_Excluded << UART_CONFIG_PARITY_Pos); + NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Enabled; + NRF_UART0->EVENTS_RXDRDY = 0; + NRF_UART0->EVENTS_TXDRDY = 0; + + NRF_UART0->CONFIG &= ~(UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos); + + NRF_UART0->PSELRTS = NRF51_SERIAL_PAD_DISCONNECTED; + NRF_UART0->PSELCTS = NRF51_SERIAL_PAD_DISCONNECTED; + + if (config->rx_pad != NRF51_SERIAL_PAD_DISCONNECTED) { + while (NRF_UART0->EVENTS_RXDRDY != 0) { + (void)NRF_UART0->RXD; + } } - return INVALID_BAUDRATE; } @@ -94,16 +126,25 @@ static uint32_t regval_from_baudrate(uint32_t speed) #if NRF51_SERIAL_USE_UART0 || defined(__DOXYGEN__) static void notify1(io_queue_t *qp) { + SerialDriver *sdp = &SD1; + (void)qp; - msg_t b = oqGetI(&SD1.oqueue); - if (b < Q_OK) { - chnAddFlagsI(&SD1, CHN_OUTPUT_EMPTY); + if (NRF_UART0->PSELTXD == NRF51_SERIAL_PAD_DISCONNECTED) return; + + if (!sdp->tx_busy) { + msg_t b = chOQGetI(&sdp->oqueue); + + if (b < Q_OK) { + chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); + NRF_UART0->TASKS_STOPTX = 1; + return; + } + sdp->tx_busy = 1; + NRF_UART0->TASKS_STARTTX = 1; + NRF_UART0->TXD = b; } - SD1.thread = chThdGetSelfX(); - NRF_UART0->TXD = b; - chEvtWaitAny((eventmask_t) 1); } #endif @@ -117,24 +158,49 @@ OSAL_IRQ_HANDLER(Vector48) { OSAL_IRQ_PROLOGUE(); - if (NRF_UART0->EVENTS_RXDRDY) { + SerialDriver *sdp = &SD1; + uint32_t isr = NRF_UART0->INTENSET; + + if ((NRF_UART0->EVENTS_RXDRDY != 0) && (isr & UART_INTENSET_RXDRDY_Msk)) { + // Clear UART RX event flag NRF_UART0->EVENTS_RXDRDY = 0; + osalSysLockFromISR(); - if (iqIsEmptyI(&SD1.iqueue)) - chnAddFlagsI(&SD1, CHN_INPUT_AVAILABLE); - if (iqPutI(&SD1.iqueue, NRF_UART0->RXD) < Q_OK) - chnAddFlagsI(&SD1, SD_OVERRUN_ERROR); + if (chIQIsEmptyI(&sdp->iqueue)) + chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); + if (chIQPutI(&sdp->iqueue, NRF_UART0->RXD) < Q_OK) + chnAddFlagsI(sdp, SD_OVERRUN_ERROR); osalSysUnlockFromISR(); } - if (NRF_UART0->EVENTS_TXDRDY) { + if ((NRF_UART0->EVENTS_TXDRDY != 0) && (isr & UART_INTENSET_TXDRDY_Msk)) { + msg_t b; + + // Clear UART TX event flag. NRF_UART0->EVENTS_TXDRDY = 0; + osalSysLockFromISR(); - chEvtSignalI(SD1.thread, (eventmask_t) 1); + b = chOQGetI(&sdp->oqueue); osalSysUnlockFromISR(); + + if (b < Q_OK) { + osalSysLockFromISR(); + chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); + osalSysUnlockFromISR(); + NRF_UART0->TASKS_STOPTX = 1; + sdp->tx_busy = 0; + } else { + sdp->tx_busy = 1; + NRF_UART0->TXD = b; + } } /* TODO: Error handling for EVENTS_ERROR */ + if ((NRF_UART0->EVENTS_ERROR != 0) && (isr & UART_INTENSET_ERROR_Msk)) { + // Clear UART ERROR event flag. + NRF_UART0->EVENTS_ERROR = 0; + } + OSAL_IRQ_EPILOGUE(); } @@ -168,45 +234,31 @@ void sd_lld_init(void) { */ void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) { - if (config == NULL) { + if (config == NULL) config = &default_config; - } + + osalDbgAssert( + (config->rx_pad < TOTAL_GPIO_PADS) || (config->tx_pad < TOTAL_GPIO_PADS), + "must configure at least an RX or TX pad"); if (sdp->state == SD_STOP) { #if NRF51_SERIAL_USE_UART0 == TRUE if (sdp == &SD1) { - uint32_t regval; - - /* TODO: Add support for CTS/RTS! */ - - /* Configure PINs */ - NRF_UART0->PSELRTS = ~0; - NRF_UART0->PSELCTS = ~0; - if (config->tx_pin != INVALID_PIN) { - palSetPadMode(IOPORT1, config->tx_pin, PAL_MODE_OUTPUT_PUSHPULL); - NRF_UART0->PSELTXD = config->tx_pin; - } - if (config->rx_pin != INVALID_PIN) { - palSetPadMode(IOPORT1, config->rx_pin, PAL_MODE_INPUT); - NRF_UART0->PSELRXD = config->rx_pin; - } + configure_uart(config); - regval = regval_from_baudrate(config->speed); - osalDbgAssert(regval != INVALID_BAUDRATE, "invalid baudrate speed"); - NRF_UART0->BAUDRATE = regval; + // Enable UART interrupt + NRF_UART0->INTENCLR = (uint32_t)-1; + NRF_UART0->INTENSET = UART_INTENSET_ERROR_Msk; + if (config->rx_pad != NRF51_SERIAL_PAD_DISCONNECTED) + NRF_UART0->INTENSET |= UART_INTENSET_RXDRDY_Msk; + if (config->tx_pad != NRF51_SERIAL_PAD_DISCONNECTED) + NRF_UART0->INTENSET |= UART_INTENSET_TXDRDY_Msk; - /* Enable interrupts for RX, TX and ERROR */ - NRF_UART0->INTENSET = 0x284; + nvicEnableVector(UART0_IRQn, NRF51_SERIAL_UART0_PRIORITY); - NRF_UART0->EVENTS_RXDRDY = 0; - NRF_UART0->EVENTS_TXDRDY = 0; - - nvicEnableVector(UART0_IRQn, 12); - - NRF_UART0->ENABLE = 4; - NRF_UART0->TASKS_STARTRX = 1; - NRF_UART0->TASKS_STARTTX = 1; + if (config->rx_pad != NRF51_SERIAL_PAD_DISCONNECTED) + NRF_UART0->TASKS_STARTRX = 1; } #endif @@ -229,9 +281,9 @@ void sd_lld_stop(SerialDriver *sdp) { #if NRF51_SERIAL_USE_UART0 == TRUE if (&SD1 == sdp) { nvicDisableVector(UART0_IRQn); + NRF_UART0->ENABLE = UART_ENABLE_ENABLE_Disabled; } #endif - } } diff --git a/os/hal/ports/NRF51/NRF51822/serial_lld.h b/os/hal/ports/NRF51/NRF51822/serial_lld.h index 62f1302..8da3998 100644 --- a/os/hal/ports/NRF51/NRF51822/serial_lld.h +++ b/os/hal/ports/NRF51/NRF51822/serial_lld.h @@ -40,13 +40,25 @@ * @{ */ /** - * @brief USART1 driver enable switch. - * @details If set to @p TRUE the support for USART1 is included. + * @brief SD1 driver enable switch. + * @details If set to @p TRUE the support for SD1 is included. * @note The default is @p FALSE. */ #if !defined(NRF51_SERIAL_USE_UART0) || defined(__DOXYGEN__) #define NRF51_SERIAL_USE_UART0 FALSE #endif + +/** + * @brief UART0 interrupt priority level setting. + */ +#if !defined(NRF51_SERIAL_UART0_PRIORITY) || defined(__DOXYGEN__) +#define NRF51_SERIAL_UART0_PRIORITY 12 +#endif + +/* Value indicating that no pad is connected to this UART register. */ +#define NRF51_SERIAL_PAD_DISCONNECTED 0xFFFFFFFFU +#define NRF51_SERIAL_INVALID_BAUDRATE 0xFFFFFFFFU + /** @} */ /*===========================================================================*/ @@ -71,8 +83,8 @@ typedef struct { */ uint32_t speed; /* End of the mandatory fields.*/ - uint8_t tx_pin; - uint8_t rx_pin; + uint32_t tx_pad; + uint32_t rx_pad; } SerialConfig; /** @@ -90,6 +102,8 @@ typedef struct { uint8_t ib[SERIAL_BUFFERS_SIZE]; \ /* Output circular buffer.*/ \ uint8_t ob[SERIAL_BUFFERS_SIZE]; \ + /* 1 if port is busy transmitting, 0 otherwise. */ \ + uint8_t tx_busy; \ /* End of the mandatory fields.*/ \ thread_t *thread; -- cgit v1.2.3