From f49a4b5d583538860658d9b5461549b4dc86371b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Thu, 4 Jul 2024 14:18:54 +0200 Subject: [PATCH] drivers: serial: nrfx_uarte: Add support for frame timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frame timeout is a hardware feature present in newer versions of UARTE (e.g. in NRF54X platforms) for detecting idle state on RX line and ending RX after configurable timeout. Signed-off-by: Krzysztof Chruściński --- drivers/serial/Kconfig.nrfx | 2 - drivers/serial/uart_nrfx_uarte.c | 67 ++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/drivers/serial/Kconfig.nrfx b/drivers/serial/Kconfig.nrfx index 16f667eaa50ee0..ae790980f42476 100644 --- a/drivers/serial/Kconfig.nrfx +++ b/drivers/serial/Kconfig.nrfx @@ -31,10 +31,8 @@ config UART_NRFX_UARTE config UART_NRFX_UARTE_LEGACY_SHIM bool "Legacy UARTE shim" depends on UART_NRFX_UARTE - depends on !SOC_SERIES_NRF54LX depends on !SOC_SERIES_NRF54HX || RISCV depends on !SOC_SERIES_NRF92X || RISCV - # New shim takes more ROM. Until it is fixed use legacy shim. default y config UART_NRFX_UARTE_ENHANCED_RX diff --git a/drivers/serial/uart_nrfx_uarte.c b/drivers/serial/uart_nrfx_uarte.c index 805b7b362fdca5..9d8260bc9f55a2 100644 --- a/drivers/serial/uart_nrfx_uarte.c +++ b/drivers/serial/uart_nrfx_uarte.c @@ -83,6 +83,11 @@ LOG_MODULE_REGISTER(uart_nrfx_uarte, CONFIG_UART_LOG_LEVEL); #define UARTE_HAS_ENDTX_STOPTX_SHORT 1 #endif +#if (UARTE_FOR_EACH_INSTANCE(INSTANCE_PROP, (+), (0), frame_timeout_supported)) == \ + (UARTE_FOR_EACH_INSTANCE(INSTANCE_PRESENT, (+), (0), frame_timeout_supported)) +#define UARTE_HAS_FRAME_TIMEOUT 1 +#endif + /* * RX timeout is divided into time slabs, this define tells how many divisions * should be made. More divisions - higher timeout accuracy and processor usage. @@ -113,7 +118,9 @@ struct uarte_async_rx { uint8_t *next_buf; size_t next_buf_len; #ifdef CONFIG_UART_NRFX_UARTE_ENHANCED_RX +#if !defined(UARTE_HAS_FRAME_TIMEOUT) uint32_t idle_cnt; +#endif k_timeout_t timeout; #else uint32_t total_byte_cnt; /* Total number of bytes received */ @@ -227,6 +234,9 @@ struct uarte_nrfx_config { /* None-zero in case of high speed instances. Baudrate is adjusted by that ratio. */ uint32_t clock_freq; #else +#ifdef UARTE_HAS_FRAME_TIMEOUT + uint32_t baudrate; +#endif nrf_uarte_baudrate_t nrf_baudrate; nrf_uarte_config_t hw_config; #endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */ @@ -373,10 +383,6 @@ static int uarte_nrfx_configure(const struct device *dev, struct uarte_nrfx_data *data = dev->data; nrf_uarte_config_t uarte_cfg; -#if NRF_UARTE_HAS_FRAME_TIMEOUT - uarte_cfg.frame_timeout = NRF_UARTE_FRAME_TIMEOUT_DIS; -#endif - #if defined(UARTE_CONFIG_STOP_Msk) switch (cfg->stop_bits) { case UART_CFG_STOP_BITS_1: @@ -433,6 +439,9 @@ static int uarte_nrfx_configure(const struct device *dev, return -ENOTSUP; } +#ifdef UARTE_HAS_FRAME_TIMEOUT + uarte_cfg.frame_timeout = NRF_UARTE_FRAME_TIMEOUT_EN; +#endif nrf_uarte_configure(get_uarte_instance(dev), &uarte_cfg); data->uart_config = *cfg; @@ -669,7 +678,8 @@ static int uarte_nrfx_init(const struct device *dev) NRF_UARTE_INT_RXSTARTED_MASK | NRF_UARTE_INT_ERROR_MASK | NRF_UARTE_INT_RXTO_MASK | - (IS_ENABLED(CONFIG_UART_NRFX_UARTE_ENHANCED_RX) ? NRF_UARTE_INT_RXDRDY_MASK : 0); + ((IS_ENABLED(CONFIG_UART_NRFX_UARTE_ENHANCED_RX) && + !IS_ENABLED(UARTE_HAS_FRAME_TIMEOUT)) ? NRF_UARTE_INT_RXDRDY_MASK : 0); #if !defined(CONFIG_UART_NRFX_UARTE_ENHANCED_RX) int ret = uarte_nrfx_rx_counting_init(dev); @@ -836,6 +846,15 @@ static void notify_rx_disable(const struct device *dev) user_callback(dev, (struct uart_event *)&evt); } +#ifdef UARTE_HAS_FRAME_TIMEOUT +static uint32_t us_to_bauds(uint32_t baudrate, int32_t timeout) +{ + uint64_t bauds = (uint64_t)baudrate * timeout / 1000000; + + return MIN((uint32_t)bauds, UARTE_FRAMETIMEOUT_COUNTERTOP_Msk); +} +#endif + static int uarte_nrfx_rx_enable(const struct device *dev, uint8_t *buf, size_t len, int32_t timeout) @@ -859,9 +878,22 @@ static int uarte_nrfx_rx_enable(const struct device *dev, uint8_t *buf, } #ifdef CONFIG_UART_NRFX_UARTE_ENHANCED_RX +#ifdef UARTE_HAS_FRAME_TIMEOUT + if (timeout != SYS_FOREVER_US) { + uint32_t baudrate = COND_CODE_1(CONFIG_UART_USE_RUNTIME_CONFIGURE, + (data->uart_config.baudrate), (cfg->baudrate)); + + async_rx->timeout = K_USEC(timeout); + nrf_uarte_frame_timeout_set(uarte, us_to_bauds(baudrate, timeout)); + nrf_uarte_shorts_enable(uarte, NRF_UARTE_SHORT_FRAME_TIMEOUT_STOPRX); + } else { + async_rx->timeout = K_NO_WAIT; + } +#else async_rx->timeout = (timeout == SYS_FOREVER_US) ? K_NO_WAIT : K_USEC(timeout / RX_TIMEOUT_DIV); async_rx->idle_cnt = 0; +#endif /* UARTE_HAS_FRAME_TIMEOUT */ #else async_rx->timeout_us = timeout; async_rx->timeout_slab = timeout / RX_TIMEOUT_DIV; @@ -1018,6 +1050,12 @@ static void rx_timeout(struct k_timer *timer) #if CONFIG_UART_NRFX_UARTE_ENHANCED_RX NRF_UARTE_Type *uarte = get_uarte_instance(dev); +#ifdef UARTE_HAS_FRAME_TIMEOUT + if (!nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_RXDRDY)) { + nrf_uarte_task_trigger(uarte, NRF_UARTE_TASK_STOPRX); + } + return; +#else /* UARTE_HAS_FRAME_TIMEOUT */ struct uarte_nrfx_data *data = dev->data; struct uarte_async_rx *async_rx = &data->async->rx; @@ -1041,6 +1079,7 @@ static void rx_timeout(struct k_timer *timer) } k_timer_start(&async_rx->timer, async_rx->timeout, K_NO_WAIT); +#endif /* UARTE_HAS_FRAME_TIMEOUT */ #else /* CONFIG_UART_NRFX_UARTE_ENHANCED_RX */ const struct uarte_nrfx_config *cfg = dev->config; struct uarte_nrfx_data *data = dev->data; @@ -1154,6 +1193,7 @@ static void rxstarted_isr(const struct device *dev) .type = UART_RX_BUF_REQUEST, }; +#ifndef UARTE_HAS_FRAME_TIMEOUT struct uarte_nrfx_data *data = dev->data; struct uarte_async_rx *async_rx = &data->async->rx; @@ -1171,6 +1211,7 @@ static void rxstarted_isr(const struct device *dev) k_timer_start(&async_rx->timer, timeout, timeout); } #endif /* CONFIG_UART_NRFX_UARTE_ENHANCED_RX */ +#endif /* !UARTE_HAS_FRAME_TIMEOUT */ user_callback(dev, &evt); } @@ -1370,7 +1411,9 @@ static void rxto_isr(const struct device *dev) #ifdef CONFIG_UART_NRFX_UARTE_ENHANCED_RX NRF_UARTE_Type *uarte = get_uarte_instance(dev); - +#ifdef UARTE_HAS_FRAME_TIMEOUT + nrf_uarte_shorts_disable(uarte, NRF_UARTE_SHORT_FRAME_TIMEOUT_STOPRX); +#endif nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXDRDY); #endif @@ -1466,6 +1509,9 @@ static void txstopped_isr(const struct device *dev) static void rxdrdy_isr(const struct device *dev) { +#if !defined(UARTE_HAS_FRAME_TIMEOUT) + struct uarte_nrfx_data *data = dev->data; + #if defined(CONFIG_UART_NRFX_UARTE_ENHANCED_RX) NRF_UARTE_Type *uarte = get_uarte_instance(dev); @@ -1475,6 +1521,7 @@ static void rxdrdy_isr(const struct device *dev) #else data->async->rx.cnt.cnt++; #endif +#endif /* !UARTE_HAS_FRAME_TIMEOUT */ } static bool event_check_clear(NRF_UARTE_Type *uarte, nrf_uarte_event_t event, @@ -1497,7 +1544,7 @@ static void uarte_nrfx_isr_async(const void *arg) struct uarte_async_rx *async_rx = &data->async->rx; uint32_t imask = nrf_uarte_int_enable_check(uarte, UINT32_MAX); - if (!HW_RX_COUNTING_ENABLED(config) + if (!(HW_RX_COUNTING_ENABLED(config) || IS_ENABLED(UARTE_HAS_FRAME_TIMEOUT)) && event_check_clear(uarte, NRF_UARTE_EVENT_RXDRDY, NRF_UARTE_INT_RXDRDY_MASK, imask)) { rxdrdy_isr(dev); @@ -2129,6 +2176,8 @@ static int uarte_nrfx_pm_action(const struct device *dev, IF_ENABLED(UARTE_HAS_STOP_CONFIG, (.stop = NRF_UARTE_STOP_ONE,))\ IF_ENABLED(UARTE_ODD_PARITY_ALLOWED, \ (.paritytype = NRF_UARTE_PARITYTYPE_EVEN,)) \ + IF_ENABLED(UARTE_HAS_FRAME_TIMEOUT, \ + (.frame_timeout = NRF_UARTE_FRAME_TIMEOUT_EN,)) \ } /* Macro for setting zephyr specific configuration structures. */ @@ -2172,7 +2221,9 @@ static int uarte_nrfx_pm_action(const struct device *dev, COND_CODE_1(CONFIG_UART_USE_RUNTIME_CONFIGURE, \ (IF_ENABLED(DT_CLOCKS_HAS_IDX(UARTE(idx), 0), \ (.clock_freq = UARTE_GET_FREQ(idx),))), \ - (.nrf_baudrate = UARTE_GET_BAUDRATE(idx), \ + (IF_ENABLED(UARTE_HAS_FRAME_TIMEOUT, \ + (.baudrate = UARTE_PROP(idx, current_speed),)) \ + .nrf_baudrate = UARTE_GET_BAUDRATE(idx), \ .hw_config = UARTE_NRF_CONFIG(idx),)) \ .pcfg = PINCTRL_DT_DEV_CONFIG_GET(UARTE(idx)), \ .uarte_regs = _CONCAT(NRF_UARTE, idx), \