UARTE RX error and crash when quik insert and remove RX pin

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);
	}
}

Parents Reply Children
No Data
Related