Skip to content

Commit 37ff95b

Browse files
committed
[nrf fromtree] drivers: serial: nrfx_uarte: Improve RX FIFO workaround
Current workaround fails to detect data in FIFO if the last received data was equal to the magic byte used in the workaround and length of the transfer was short (less than HW FIFO size which is 5). In order to reduce chances of failure additional measure is added. Data is added to the FIFO if some byte arrives after ENDRX. Each byte triggers RXDRDY event. We attempt to clear RXDRDY event as one of the first things when entering ISR and then when RX FIFO is flushed RXDRDY event is checked. If it is set, it means that there was a byte coming after ENDRX so FIFO was not empty. Workaround will fail in case when ISR latency is long enough that byte to FIFO comes before ISR is handled. Upstream PR: zephyrproject-rtos/zephyr#80201 Signed-off-by: Krzysztof Chruściński <[email protected]>
1 parent d426c7a commit 37ff95b

File tree

1 file changed

+39
-10
lines changed

1 file changed

+39
-10
lines changed

drivers/serial/uart_nrfx_uarte.c

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,7 @@ static int uarte_nrfx_rx_enable(const struct device *dev, uint8_t *buf,
10451045

10461046
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_ENDRX);
10471047
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXSTARTED);
1048+
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXDRDY);
10481049

10491050
async_rx->enabled = true;
10501051

@@ -1501,6 +1502,13 @@ static uint8_t rx_flush(const struct device *dev, uint8_t *buf)
15011502
return 0;
15021503
}
15031504

1505+
/* If event is set that means it came after ENDRX so there was at least
1506+
* one byte in the RX FIFO.
1507+
*/
1508+
if (nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_RXDRDY)) {
1509+
return rx_amount;
1510+
}
1511+
15041512
if (IS_ENABLED(UARTE_ANY_CACHE) && (config->flags & UARTE_CFG_FLAG_CACHEABLE)) {
15051513
sys_cache_data_invd_range(buf, UARTE_HW_RX_FIFO_SIZE);
15061514
}
@@ -1558,12 +1566,8 @@ static void rxto_isr(const struct device *dev)
15581566
async_rx->flush_cnt = rx_flush(dev, config->rx_flush_buf);
15591567
}
15601568

1561-
#ifdef CONFIG_UART_NRFX_UARTE_ENHANCED_RX
1562-
NRF_UARTE_Type *uarte = get_uarte_instance(dev);
15631569
#ifdef UARTE_HAS_FRAME_TIMEOUT
1564-
nrf_uarte_shorts_disable(uarte, NRF_UARTE_SHORT_FRAME_TIMEOUT_STOPRX);
1565-
#endif
1566-
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXDRDY);
1570+
nrf_uarte_shorts_disable(get_uarte_instance(dev), NRF_UARTE_SHORT_FRAME_TIMEOUT_STOPRX);
15671571
#endif
15681572

15691573
if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
@@ -1700,19 +1704,44 @@ static void uarte_nrfx_isr_async(const void *arg)
17001704
struct uarte_nrfx_data *data = dev->data;
17011705
struct uarte_async_rx *async_rx = &data->async->rx;
17021706
uint32_t imask = nrf_uarte_int_enable_check(uarte, UINT32_MAX);
1707+
bool endrx = false;
1708+
bool rxdrdy = false;
1709+
1710+
/* Part of a workaround for RX FIFO flushing issue. One way to detect if
1711+
* there was data in the RX FIFO is to check if RXDRDY event came after ENDRX.
1712+
* To detect that we try to clear RXDRDY event immediately after detecting
1713+
* that ENDRX event occur. Then in RXTO event handling when FIFO is flushed
1714+
* RXDRDY event is checked and if it is set then it means that there was at
1715+
* least one byte in the FIFO (that arrived after ENDRX). It is not perfect
1716+
* because it will fail if ISR is handled with latency but together with
1717+
* watermarking the buffer it should significantly reduce the chance of
1718+
* failure.
1719+
*/
1720+
if (event_check_clear(uarte, NRF_UARTE_EVENT_ENDRX, NRF_UARTE_INT_ENDRX_MASK, imask)) {
1721+
if (RX_FLUSH_WORKAROUND) {
1722+
if (nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_RXDRDY)) {
1723+
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXDRDY);
1724+
rxdrdy = true;
1725+
}
1726+
}
1727+
endrx = true;
1728+
}
17031729

17041730
if (!(HW_RX_COUNTING_ENABLED(config) || IS_ENABLED(UARTE_HAS_FRAME_TIMEOUT))
1705-
&& event_check_clear(uarte, NRF_UARTE_EVENT_RXDRDY, NRF_UARTE_INT_RXDRDY_MASK, imask)) {
1706-
rxdrdy_isr(dev);
1707-
1731+
&& (imask & NRF_UARTE_INT_RXDRDY_MASK)) {
1732+
if (rxdrdy) {
1733+
rxdrdy_isr(dev);
1734+
} else if (nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_RXDRDY)) {
1735+
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXDRDY);
1736+
rxdrdy_isr(dev);
1737+
}
17081738
}
17091739

17101740
if (event_check_clear(uarte, NRF_UARTE_EVENT_ERROR, NRF_UARTE_INT_ERROR_MASK, imask)) {
17111741
error_isr(dev);
17121742
}
17131743

1714-
if (event_check_clear(uarte, NRF_UARTE_EVENT_ENDRX, NRF_UARTE_INT_ENDRX_MASK, imask)) {
1715-
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_ENDRX);
1744+
if (endrx) {
17161745
endrx_isr(dev);
17171746
}
17181747

0 commit comments

Comments
 (0)