Dear Everyone,
We're using the PAN B611 evaluation board (ENW89861AXKF) which features a PAN B611-1C Bluetooth 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 call to 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