@@ -95,6 +95,17 @@ LOG_MODULE_REGISTER(uart_nrfx_uarte, CONFIG_UART_LOG_LEVEL);
9595#define UARTE_HAS_FRAME_TIMEOUT 1
9696#endif
9797
98+ /* Frame timeout has a bug that countdown counter may not be triggered in some
99+ * specific condition. It may happen if RX is manually started after ENDRX (STOPRX
100+ * task was not triggered) and there is ongoing reception of a byte. RXDRDY event
101+ * triggered by the reception of that byte may not trigger frame timeout counter.
102+ * If this is the last byte of a transfer then without the workaround there will
103+ * be no expected RX timeout.
104+ */
105+ #ifdef UARTE_HAS_FRAME_TIMEOUT
106+ #define RX_FRAMETIMEOUT_WORKAROUND 1
107+ #endif
108+
98109#define INSTANCE_NEEDS_CACHE_MGMT (unused , prefix , i , prop ) UARTE_IS_CACHEABLE(prefix##i)
99110
100111#if UARTE_FOR_EACH_INSTANCE (INSTANCE_NEEDS_CACHE_MGMT , (+ ), (0 ), _ )
@@ -251,6 +262,8 @@ struct uarte_nrfx_data {
251262#define UARTE_FLAG_LOW_POWER (UARTE_FLAG_LOW_POWER_TX | UARTE_FLAG_LOW_POWER_RX)
252263#define UARTE_FLAG_TRIG_RXTO BIT(2)
253264#define UARTE_FLAG_POLL_OUT BIT(3)
265+ /* Flag indicating that a workaround for not working frame timeout is active. */
266+ #define UARTE_FLAG_FTIMEOUT_WATCH BIT(4)
254267
255268/* If enabled then ENDTX is PPI'ed to TXSTOP */
256269#define UARTE_CFG_FLAG_PPI_ENDTX BIT(0)
@@ -1317,9 +1330,22 @@ static void rx_timeout(struct k_timer *timer)
13171330 NRF_UARTE_Type * uarte = get_uarte_instance (dev );
13181331
13191332#ifdef UARTE_HAS_FRAME_TIMEOUT
1320- if (!nrf_uarte_event_check (uarte , NRF_UARTE_EVENT_RXDRDY )) {
1321- nrf_uarte_task_trigger (uarte , NRF_UARTE_TASK_STOPRX );
1333+ struct uarte_nrfx_data * data = dev -> data ;
1334+ struct uarte_async_rx * async_rx = & data -> async -> rx ;
1335+ bool rxdrdy = nrf_uarte_event_check (uarte , NRF_UARTE_EVENT_RXDRDY );
1336+
1337+ if (IS_ENABLED (RX_FRAMETIMEOUT_WORKAROUND ) &&
1338+ (atomic_and (& data -> flags , ~UARTE_FLAG_FTIMEOUT_WATCH ) & UARTE_FLAG_FTIMEOUT_WATCH )) {
1339+ if (rxdrdy ) {
1340+ nrf_uarte_event_clear (uarte , NRF_UARTE_EVENT_RXDRDY );
1341+ k_timer_start (& async_rx -> timer , async_rx -> timeout , K_NO_WAIT );
1342+ }
1343+ } else {
1344+ if (!rxdrdy ) {
1345+ nrf_uarte_task_trigger (uarte , NRF_UARTE_TASK_STOPRX );
1346+ }
13221347 }
1348+
13231349 return ;
13241350#else /* UARTE_HAS_FRAME_TIMEOUT */
13251351 struct uarte_nrfx_data * data = dev -> data ;
@@ -1545,6 +1571,7 @@ static void endrx_isr(const struct device *dev)
15451571 async_rx -> offset = 0 ;
15461572
15471573 if (async_rx -> enabled ) {
1574+ bool start_timeout = false;
15481575 /* If there is a next buffer, then STARTRX will have already been
15491576 * invoked by the short (the next buffer will be filling up already)
15501577 * and here we just do the swap of which buffer the driver is following,
@@ -1570,6 +1597,11 @@ static void endrx_isr(const struct device *dev)
15701597 */
15711598 if (!nrf_uarte_event_check (uarte , NRF_UARTE_EVENT_RXSTARTED )) {
15721599 nrf_uarte_task_trigger (uarte , NRF_UARTE_TASK_STARTRX );
1600+ nrf_uarte_event_clear (uarte , NRF_UARTE_EVENT_RXTO );
1601+ if (IS_ENABLED (RX_FRAMETIMEOUT_WORKAROUND )) {
1602+ data -> flags |= UARTE_FLAG_FTIMEOUT_WATCH ;
1603+ start_timeout = true;
1604+ }
15731605 }
15741606 /* Remove the short until the subsequent next buffer is setup */
15751607 nrf_uarte_shorts_disable (uarte , NRF_UARTE_SHORT_ENDRX_STARTRX );
@@ -1578,6 +1610,11 @@ static void endrx_isr(const struct device *dev)
15781610 }
15791611
15801612 irq_unlock (key );
1613+ if (IS_ENABLED (UARTE_HAS_FRAME_TIMEOUT )) {
1614+ if (start_timeout && !K_TIMEOUT_EQ (async_rx -> timeout , K_NO_WAIT )) {
1615+ k_timer_start (& async_rx -> timer , async_rx -> timeout , K_NO_WAIT );
1616+ }
1617+ }
15811618 }
15821619
15831620#if !defined(CONFIG_UART_NRFX_UARTE_ENHANCED_RX )
@@ -1635,6 +1672,12 @@ static void rxto_isr(const struct device *dev)
16351672 struct uarte_nrfx_data * data = dev -> data ;
16361673 struct uarte_async_rx * async_rx = & data -> async -> rx ;
16371674
1675+ if (IS_ENABLED (RX_FRAMETIMEOUT_WORKAROUND )) {
1676+ if (atomic_test_and_clear_bit (& data -> flags , UARTE_FLAG_FTIMEOUT_WATCH )) {
1677+ k_timer_stop (& async_rx -> timer );
1678+ }
1679+ }
1680+
16381681 if (async_rx -> buf ) {
16391682#ifdef CONFIG_HAS_NORDIC_DMM
16401683 (void )dmm_buffer_in_release (config -> mem_reg , async_rx -> usr_buf , 0 , async_rx -> buf );
0 commit comments