RXTO not generated by Bluetooth LE UART service application. SDK v3.3.0

Dear Everyone,

We're using the PAN B611 evaluation board (ENW89861AXKF) which features a PAN B611-1C BluetoothRegistered Low Energy (LE) module which is based on the Nordic Semiconductor nRF54L15 single-chip controller.

We have followed the instructions from:
https://pideu.panasonic.de/development-hub/panb611/software/getting_started/

We have imported and built Bluetooth LE UART service. SDK version is v3.3.0

This seem to be the source code imported by nrfconnect sdk:
github.com/.../main.c

The service seems to work, however one specific thing doesn't which may be required in our future application.

We have USB-UART to connect board with a PC. Using the Tera Term we can write messages and once we insert '\r' or \n' we see message in correct characteristic. However we can't reliably get event UART_RX_DISABLED.

static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data)
{
	ARG_UNUSED(dev);

	static size_t aborted_len;
	struct uart_data_t *buf;
	static uint8_t *aborted_buf;
	static bool disable_req;

	switch (evt->type) {
	case UART_TX_DONE:
		LOG_DBG("UART_TX_DONE");
		if ((evt->data.tx.len == 0) ||
		    (!evt->data.tx.buf)) {
			return;
		}

		if (aborted_buf) {
			buf = CONTAINER_OF(aborted_buf, struct uart_data_t,
					   data[0]);
			aborted_buf = NULL;
			aborted_len = 0;
		} else {
			buf = CONTAINER_OF(evt->data.tx.buf, struct uart_data_t,
					   data[0]);
		}

		k_free(buf);

		buf = k_fifo_get(&fifo_uart_tx_data, K_NO_WAIT);
		if (!buf) {
			return;
		}

		if (uart_tx(uart, buf->data, buf->len, SYS_FOREVER_MS)) {
			LOG_WRN("Failed to send data over UART");
		}

		break;

	case UART_RX_RDY:
		LOG_DBG("UART_RX_RDY");
		buf = CONTAINER_OF(evt->data.rx.buf, struct uart_data_t, data[0]);
		buf->len += evt->data.rx.len;

		if (disable_req) {
			return;
		}

		if ((evt->data.rx.buf[buf->len - 1] == '\n') ||
		    (evt->data.rx.buf[buf->len - 1] == '\r')) {
			disable_req = true;
			uart_rx_disable(uart);
		}

		break;

	case UART_RX_DISABLED:
		LOG_DBG("UART_RX_DISABLED");
		disable_req = false;

		buf = k_malloc(sizeof(*buf));
		if (buf) {
			buf->len = 0;
		} else {
			LOG_WRN("Not able to allocate UART receive buffer");
			k_work_reschedule(&uart_work, UART_WAIT_FOR_BUF_DELAY);
			return;
		}

		uart_rx_enable(uart, buf->data, sizeof(buf->data),
			       UART_WAIT_FOR_RX);

		break;

	case UART_RX_BUF_REQUEST:
		LOG_DBG("UART_RX_BUF_REQUEST");
		buf = k_malloc(sizeof(*buf));
		if (buf) {
			buf->len = 0;
			uart_rx_buf_rsp(uart, buf->data, sizeof(buf->data));
		} else {
			LOG_WRN("Not able to allocate UART receive buffer");
		}

		break;

	case UART_RX_BUF_RELEASED:
		LOG_DBG("UART_RX_BUF_RELEASED");
		buf = CONTAINER_OF(evt->data.rx_buf.buf, struct uart_data_t,
				   data[0]);

		if (buf->len > 0) {
			k_fifo_put(&fifo_uart_rx_data, buf);
		} else {
			k_free(buf);
		}

		break;

	case UART_TX_ABORTED:
		LOG_DBG("UART_TX_ABORTED");
		if (!aborted_buf) {
			aborted_buf = (uint8_t *)evt->data.tx.buf;
		}

		aborted_len += evt->data.tx.len;
		buf = CONTAINER_OF((void *)aborted_buf, struct uart_data_t,
				   data);

		uart_tx(uart, &buf->data[aborted_len],
			buf->len - aborted_len, SYS_FOREVER_MS);

		break;

	default:
		break;
	}
}

Please see the two paths below:

a) without any breakpoints in firmware the app enters RX_RDY once, then it sets disable_req and then it never enters UART_RX_DISABLED. The bridge works because of implementation of UART_RX_BUF_RELEASED as we keep feeding released frames to queue

b) If we place brakepoint in RX_RDY, UART_RX_BUF_REQUEST and UART_RX_DISABLED then we properly enter UART_RX_DISABLED.

This leads us to believe there is a race condition somewhere. The issue seems to be fixed by delegating uart_rx_disable calto separate zephyr work executed after we leave ISR.

Similarly the issue can be fixed by adding an if (disable_req){return} in UART_RX_BUF_REQUEST which further leads me to believe that the internal state machine is disrupted by calling 
uart_rx_buf_rsp after uart_rx_disable.

Has anyone encountered similar issue before? Do you think that one of our workarounds is safe way to go?

Best Regards and thanks in advance for any future help!

Jakub

Related