Skip to content

Commit fc82ece

Browse files
committed
[nrf fromlist] 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 d57faae commit fc82ece

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
@@ -1046,6 +1046,7 @@ static int uarte_nrfx_rx_enable(const struct device *dev, uint8_t *buf,
10461046

10471047
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_ENDRX);
10481048
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXSTARTED);
1049+
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXDRDY);
10491050

10501051
async_rx->enabled = true;
10511052

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

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

1562-
#ifdef CONFIG_UART_NRFX_UARTE_ENHANCED_RX
1563-
NRF_UARTE_Type *uarte = get_uarte_instance(dev);
15641570
#ifdef UARTE_HAS_FRAME_TIMEOUT
1565-
nrf_uarte_shorts_disable(uarte, NRF_UARTE_SHORT_FRAME_TIMEOUT_STOPRX);
1566-
#endif
1567-
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXDRDY);
1571+
nrf_uarte_shorts_disable(get_uarte_instance(dev), NRF_UARTE_SHORT_FRAME_TIMEOUT_STOPRX);
15681572
#endif
15691573

15701574
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)