Skip to content

Commit 13ba59a

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 f0a5638 commit 13ba59a

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

10441044
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_ENDRX);
10451045
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXSTARTED);
1046+
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXDRDY);
10461047

10471048
async_rx->enabled = true;
10481049

@@ -1499,6 +1500,13 @@ static uint8_t rx_flush(const struct device *dev, uint8_t *buf)
14991500
return 0;
15001501
}
15011502

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

1559-
#ifdef CONFIG_UART_NRFX_UARTE_ENHANCED_RX
1560-
NRF_UARTE_Type *uarte = get_uarte_instance(dev);
15611567
#ifdef UARTE_HAS_FRAME_TIMEOUT
1562-
nrf_uarte_shorts_disable(uarte, NRF_UARTE_SHORT_FRAME_TIMEOUT_STOPRX);
1563-
#endif
1564-
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXDRDY);
1568+
nrf_uarte_shorts_disable(get_uarte_instance(dev), NRF_UARTE_SHORT_FRAME_TIMEOUT_STOPRX);
15651569
#endif
15661570

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

17021728
if (!(HW_RX_COUNTING_ENABLED(config) || IS_ENABLED(UARTE_HAS_FRAME_TIMEOUT))
1703-
&& event_check_clear(uarte, NRF_UARTE_EVENT_RXDRDY, NRF_UARTE_INT_RXDRDY_MASK, imask)) {
1704-
rxdrdy_isr(dev);
1705-
1729+
&& (imask & NRF_UARTE_INT_RXDRDY_MASK)) {
1730+
if (rxdrdy) {
1731+
rxdrdy_isr(dev);
1732+
} else if (nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_RXDRDY)) {
1733+
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXDRDY);
1734+
rxdrdy_isr(dev);
1735+
}
17061736
}
17071737

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

1712-
if (event_check_clear(uarte, NRF_UARTE_EVENT_ENDRX, NRF_UARTE_INT_ENDRX_MASK, imask)) {
1713-
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_ENDRX);
1742+
if (endrx) {
17141743
endrx_isr(dev);
17151744
}
17161745

0 commit comments

Comments
 (0)