When we try to test the stability of the UARTE peripheral, we find that when inserting and removing the RX pin, the uarte_handler callback function is very likely to goes to NRFX_UARTE_EVT_ERROR state with error_code = 4. We try to reinitialize the UARTE by uninit and re-init it, but then the uarte_handler only goes to NRFX_UARTE_EVT_RX_DOWN state, and cannot receive any data.
In our test case, we send 11 uint8_t data at 1000000 baud rate every 10ms to the nrf52840dk. UARTE instance 1, TX on P0.27, RX on P0.26. with nrfx_uarte.h library. Also we have enable the interal pull up on the RX pin.
The code shows the uarte_handler function, and init/de-init function
// uarte_handler
static void uarte_handler(nrfx_uarte_event_t const *p_event, void *p_context)
{
nrfx_err_t status;
(void)status;
uint8_t index;
nrfx_uarte_t *p_inst = p_context;
switch (p_event->type) {
case NRFX_UARTE_EVT_RX_DONE:
// NRFX_LOG_INFO("--> RX done");
index = (++m_rx_buffers.w_pos % RINGBUFF_SIZE);
status = nrfx_uarte_rx(p_inst, (uint8_t *)(m_rx_buffers.buff + index),
sizeof(struct split_msgq_trans));
NRFX_ASSERT(status == NRFX_SUCCESS);
m_rx_buffers.w_pos = index;
if (!bad_crc) {
k_work_schedule(&uarte_work, K_NO_WAIT);
} else {
struct k_work_sync sync;
k_work_cancel_delayable_sync(&uarte_work, &sync);
split_uarte_deinit(p_inst);
split_uart_init(p_inst);
NRFX_LOG_ERROR("delayable work stopped");
bad_crc = 0;
}
break;
case NRFX_UARTE_EVT_TX_DONE:
NRFX_LOG_INFO("--> TX done");
NRFX_LOG_INFO("--> Bytes transfered: %u", p_event->data.tx.bytes);
break;
case NRFX_UARTE_EVT_ERROR:
NRFX_LOG_ERROR("--> UARTE Error: %d", p_event->data.error.error_mask);
NRFX_LOG_ERROR("--> Rx bytes: %d", p_event->data.error.rx.bytes);
struct k_work_sync sync;
k_work_cancel_delayable_sync(&uarte_work, &sync);
LOG_DBG("NRFX_UARTE_EVT_ERROR: delayable work stopped");
split_uarte_deinit(p_inst);
split_uart_init(p_inst);
break;
default:
break;
}
}
// Initialize function
static void split_uart_init(nrfx_uarte_t *p_inst)
{
nrfx_err_t status;
uint32_t key;
if (false == uart_status) {
nrfx_uarte_config_t uarte_config =
NRFX_UARTE_DEFAULT_CONFIG(UARTE_TX_PIN, UARTE_RX_PIN);
uarte_config.baudrate = NRF_UARTE_BAUDRATE_1000000;
uarte_config.p_context = p_inst;
status = nrfx_uarte_init(p_inst, &uarte_config, uarte_handler);
NRFX_ASSERT(status == NRFX_SUCCESS);
// nrfy_gpio_cfg_input(UARTE_RX_PIN, NRF_GPIO_PIN_PULLUP);
nrfy_gpio_cfg(UARTE_RX_PIN, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
nrfy_gpio_cfg(UARTE_TX_PIN, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
#if defined(__ZEPHYR__)
IRQ_DIRECT_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_UARTE_INST_GET(UARTE_INST_IDX)),
IRQ_PRIO_LOWEST, NRFX_UARTE_INST_HANDLER_GET(UARTE_INST_IDX), 0);
#endif
status = nrfx_uarte_rx(&uarte_inst, (uint8_t *)m_rx_buffers.buff,
sizeof(split_msgq_trans_t));
NRFX_ASSERT(status == NRFX_SUCCESS);
key = irq_lock();
uart_status = true;
irq_unlock(key);
}
}
// de-initialize function
static void split_uarte_deinit(nrfx_uarte_t *p_inst)
{
if (uart_status) {
uint32_t key = irq_lock();
uart_status = false;
nrfx_uarte_uninit(p_inst);
m_rx_buffers.r_pos = 0;
m_rx_buffers.w_pos = 0;
memset(m_rx_buffers.buff, 0, sizeof(m_rx_buffers.buff));
irq_unlock(key);
}
}