From e2867d697da0f563436ded5ba02e8c206db67258 Mon Sep 17 00:00:00 2001 From: Marcus Chang Date: Mon, 1 Oct 2018 16:49:40 -0700 Subject: [PATCH] Fix hardware flow control on NRF52 series Due to buggy flow control logic in the UARTE, the stop signal is not being set as it is supposed to when the the module is not ready to receive data. This commit signals the sender to halt transmitting when a DMA buffer is full and only continue again when the atomic FIFO buffer has been emptied. This allows platforms with hardware flow control to minimize all buffers and rely on flow control instead. --- targets/TARGET_NORDIC/TARGET_NRF5x/README.md | 3 ++ .../TARGET_NRF5x/TARGET_NRF52/serial_api.c | 32 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/README.md b/targets/TARGET_NORDIC/TARGET_NRF5x/README.md index fb2f9cc840..05d2452e17 100644 --- a/targets/TARGET_NORDIC/TARGET_NRF5x/README.md +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/README.md @@ -137,6 +137,9 @@ const PinMapI2C PinMap_UART[] = { The table must be placed in a C compilation file. +#### Flow Control (RTS/CTS) + +When hardware flow control is enabled the DMA and FIFO buffers can be reduced to save RAM. CTS will be disabled when a DMA buffer is copied to the FIFO and enabled again when the FIFO has been emptied. Because of the dual buffering the FIFO buffer must be twice the size of the DMA buffer (less than half and data mmight be lost and more than half will be a waste of RAM). #### RTC2 diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/serial_api.c b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/serial_api.c index 9ffeb57966..9d7cf1ff73 100644 --- a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/serial_api.c +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/serial_api.c @@ -593,6 +593,20 @@ static void nordic_nrf5_uart_event_handler_endrx(int instance) if (available > 0) { + /* Check if hardware flow control is set and signal sender to stop. + * + * This signal is set manually because the flow control logic in the UARTE module + * only works when the module is receiving and not after an ENDRX event. + * + * The RTS signal is kept high until the atomic FIFO is empty. This allow systems + * with flow control to reduce their FIFO and DMA buffers. + */ + if ((nordic_nrf5_uart_state[instance].owner->hwfc == NRF_UART_HWFC_ENABLED) && + (nordic_nrf5_uart_state[instance].owner->rts != NRF_UART_PSEL_DISCONNECTED)) { + + nrf_gpio_pin_set(nordic_nrf5_uart_state[instance].owner->rts); + } + /* Copy data from DMA buffer to FIFO buffer. */ for (size_t index = 0; index < available; index++) { @@ -810,6 +824,7 @@ static void nordic_nrf5_uart_configure_object(serial_t *obj) /* Check if pin is set before configuring it. */ if (uart_object->rts != NRF_UART_PSEL_DISCONNECTED) { + nrf_gpio_pin_clear(uart_object->rts); nrf_gpio_cfg_output(uart_object->rts); } @@ -819,8 +834,9 @@ static void nordic_nrf5_uart_configure_object(serial_t *obj) nrf_gpio_cfg_input(uart_object->cts, NRF_GPIO_PIN_NOPULL); } + /* Only let UARTE module handle CTS, RTS is handled manually due to buggy UARTE logic. */ nrf_uarte_hwfc_pins_set(nordic_nrf5_uart_register[uart_object->instance], - uart_object->rts, + NRF_UART_PSEL_DISCONNECTED, uart_object->cts); } @@ -1429,6 +1445,20 @@ int serial_getc(serial_t *obj) uint8_t *byte = (uint8_t *) nrf_atfifo_item_get(fifo, &context); nrf_atfifo_item_free(fifo, &context); + /* Check if hardware flow control is set and the atomic FIFO buffer is empty. + * + * Receive is halted until the buffer has been completely handled to reduce RAM usage. + * + * This signal is set manually because the flow control logic in the UARTE module + * only works when the module is receiving and not after an ENDRX event. + */ + if ((nordic_nrf5_uart_state[instance].owner->hwfc == NRF_UART_HWFC_ENABLED) && + (nordic_nrf5_uart_state[instance].owner->rts != NRF_UART_PSEL_DISCONNECTED) && + (*head == *tail)) { + + nrf_gpio_pin_clear(nordic_nrf5_uart_state[instance].owner->rts); + } + return *byte; }