Skip to content

Commit 8171692

Browse files
nordic-krchnordicjm
authored andcommitted
[nrf fromtree] drivers: serial: nrfx_uarte: Improve RX FIFO flushing workaround
Improved a workaround. When FIFO is not empty then FLUSHRX task will generate RXSTARTED event to indicated that DMA transfer was started. This property can be used to detect when FIFO was not empty and workaroud a HW bug where RX.AMOUNT register is not updated after flushing empty FIFO. Signed-off-by: Krzysztof Chruściński <[email protected]> (cherry picked from commit 68903ca)
1 parent 922989e commit 8171692

File tree

2 files changed

+22
-76
lines changed

2 files changed

+22
-76
lines changed

drivers/serial/Kconfig.nrfx

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,6 @@ config UART_ASYNC_TX_CACHE_SIZE
5757
in RAM, because EasyDMA in UARTE peripherals can only transfer data
5858
from RAM.
5959

60-
config UART_NRFX_UARTE_RX_FLUSH_MAGIC_BYTE
61-
hex "Byte used for RX FIFO flush workaround"
62-
default 0xAA
63-
range 0x00 0xFF
64-
help
65-
Byte used to fill the buffer before RX FIFO is flushed into it. Due to the
66-
HW anomaly a workaround need to be applied which checks if content of the
67-
buffer changed. There are cases when specific value of the magic byte is
68-
used if it is known that certain bytes are less likely to occur.
69-
7060
if HAS_HW_NRF_UART0 || HAS_HW_NRF_UARTE0
7161
nrfx_uart_num = 0
7262
rsource "Kconfig.nrfx_uart_instance"

drivers/serial/uart_nrfx_uarte.c

Lines changed: 22 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
#include <zephyr/logging/log.h>
2626
LOG_MODULE_REGISTER(uart_nrfx_uarte, CONFIG_UART_LOG_LEVEL);
2727

28+
#if !defined(CONFIG_ARCH_POSIX)
2829
#define RX_FLUSH_WORKAROUND 1
30+
#endif
2931

3032
#define UARTE(idx) DT_NODELABEL(uart##idx)
3133
#define UARTE_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(UARTE(idx), prop)
@@ -695,9 +697,6 @@ static void uarte_disable_locked(const struct device *dev, uint32_t dis_mask, ui
695697

696698
nrf_uarte_disable(get_uarte_instance(dev));
697699
}
698-
#endif
699-
700-
#ifdef UARTE_ANY_ASYNC
701700

702701
static void rx_timeout(struct k_timer *timer);
703702
static void tx_timeout(struct k_timer *timer);
@@ -1437,85 +1436,45 @@ static void endrx_isr(const struct device *dev)
14371436
#endif
14381437
}
14391438

1440-
/* Function for flushing internal RX fifo. Function can be called in case
1441-
* flushed data is discarded or when data is valid and needs to be retrieved.
1439+
/** @brief RX FIFO flushing
14421440
*
1443-
* However, UARTE does not update RXAMOUNT register if fifo is empty. Old value
1444-
* remains. In certain cases it makes it impossible to distinguish between
1445-
* case when fifo was empty and not. Function is trying to minimize chances of
1446-
* error with following measures:
1447-
* - RXAMOUNT is read before flushing and compared against value after flushing
1448-
* if they differ it indicates that data was flushed
1449-
* - user buffer is dirtied and if RXAMOUNT did not changed it is checked if
1450-
* it is still dirty. If not then it indicates that data was flushed
1451-
*
1452-
* In other cases function indicates that fifo was empty. It means that if
1453-
* number of bytes in the fifo equal last rx transfer length and data is equal
1454-
* to dirty marker it will be discarded.
1441+
* Due to the HW bug which does not update RX.AMOUNT register when FIFO was empty
1442+
* a workaround is applied which checks RXSTARTED event. If that event is set it
1443+
* means that FIFO was not empty.
14551444
*
14561445
* @param dev Device.
1457-
* @param buf Buffer for flushed data, null indicates that flushed data can be
1458-
* dropped but we still want to get amount of data flushed.
1459-
* @param len Buffer size, not used if @p buf is null.
14601446
*
14611447
* @return number of bytes flushed from the fifo.
14621448
*/
1463-
1464-
static uint8_t rx_flush(const struct device *dev, uint8_t *buf)
1449+
static uint8_t rx_flush(const struct device *dev)
14651450
{
1466-
/* Flushing RX fifo requires buffer bigger than 4 bytes to empty fifo*/
1467-
static const uint8_t dirty = CONFIG_UART_NRFX_UARTE_RX_FLUSH_MAGIC_BYTE;
14681451
NRF_UARTE_Type *uarte = get_uarte_instance(dev);
14691452
const struct uarte_nrfx_config *config = dev->config;
1470-
uint32_t prev_rx_amount;
14711453
uint32_t rx_amount;
14721454

1473-
if (IS_ENABLED(RX_FLUSH_WORKAROUND)) {
1474-
memset(buf, dirty, UARTE_HW_RX_FIFO_SIZE);
1475-
if (IS_ENABLED(UARTE_ANY_CACHE) && (config->flags & UARTE_CFG_FLAG_CACHEABLE)) {
1476-
sys_cache_data_flush_range(buf, UARTE_HW_RX_FIFO_SIZE);
1477-
}
1478-
prev_rx_amount = nrf_uarte_rx_amount_get(uarte);
1479-
} else {
1480-
prev_rx_amount = 0;
1481-
}
1482-
1483-
nrf_uarte_rx_buffer_set(uarte, buf, UARTE_HW_RX_FIFO_SIZE);
1484-
/* Final part of handling RXTO event is in ENDRX interrupt
1485-
* handler. ENDRX is generated as a result of FLUSHRX task.
1486-
*/
1487-
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_ENDRX);
1455+
nrf_uarte_rx_buffer_set(uarte, config->rx_flush_buf, UARTE_HW_RX_FIFO_SIZE);
14881456
nrf_uarte_task_trigger(uarte, NRF_UARTE_TASK_FLUSHRX);
14891457
while (!nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_ENDRX)) {
14901458
/* empty */
14911459
}
14921460
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_ENDRX);
1493-
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXSTARTED);
14941461

1495-
rx_amount = nrf_uarte_rx_amount_get(uarte);
1496-
if (!buf || !IS_ENABLED(RX_FLUSH_WORKAROUND)) {
1497-
return rx_amount;
1498-
}
1499-
1500-
if (rx_amount != prev_rx_amount) {
1501-
return rx_amount;
1502-
}
1503-
1504-
if (rx_amount > UARTE_HW_RX_FIFO_SIZE) {
1505-
return 0;
1506-
}
1507-
1508-
if (IS_ENABLED(UARTE_ANY_CACHE) && (config->flags & UARTE_CFG_FLAG_CACHEABLE)) {
1509-
sys_cache_data_invd_range(buf, UARTE_HW_RX_FIFO_SIZE);
1462+
if (!IS_ENABLED(RX_FLUSH_WORKAROUND)) {
1463+
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXSTARTED);
1464+
rx_amount = nrf_uarte_rx_amount_get(uarte);
1465+
} else if (nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_RXSTARTED)) {
1466+
nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_RXSTARTED);
1467+
rx_amount = nrf_uarte_rx_amount_get(uarte);
1468+
} else {
1469+
rx_amount = 0;
15101470
}
15111471

1512-
for (int i = 0; i < rx_amount; i++) {
1513-
if (buf[i] != dirty) {
1514-
return rx_amount;
1515-
}
1472+
if (IS_ENABLED(UARTE_ANY_CACHE) && (config->flags & UARTE_CFG_FLAG_CACHEABLE) &&
1473+
rx_amount) {
1474+
sys_cache_data_invd_range(config->rx_flush_buf, rx_amount);
15161475
}
15171476

1518-
return 0;
1477+
return rx_amount;
15191478
}
15201479

15211480
/* This handler is called when the receiver is stopped. If rx was aborted
@@ -1549,17 +1508,14 @@ static void rxto_isr(const struct device *dev)
15491508
async_rx->discard_fifo = false;
15501509
#if !defined(CONFIG_UART_NRFX_UARTE_ENHANCED_RX)
15511510
if (HW_RX_COUNTING_ENABLED(config)) {
1552-
uint8_t buf[UARTE_HW_RX_FIFO_SIZE];
1553-
15541511
/* It need to be included because TIMER+PPI got RXDRDY events
15551512
* and counted those flushed bytes.
15561513
*/
1557-
async_rx->total_user_byte_cnt += rx_flush(dev, buf);
1558-
(void)buf;
1514+
async_rx->total_user_byte_cnt += rx_flush(dev);
15591515
}
15601516
#endif
15611517
} else {
1562-
async_rx->flush_cnt = rx_flush(dev, config->rx_flush_buf);
1518+
async_rx->flush_cnt = rx_flush(dev);
15631519
}
15641520

15651521
#ifdef CONFIG_UART_NRFX_UARTE_ENHANCED_RX

0 commit comments

Comments
 (0)