Hello, All:
I have a problem, when I turn on bluetooth scanning, my UART can't process the received data in time.
When I only use UART to send and receive data, it is normal, but after turning on the Bluetooth scanning function (after turning on the scanning, the scanned data will be transmitted to the peer device in the scanning callback), I found that the UART data cannot be received in time.
The data from the peer end will not be reported until 7 minutes or 8 minutes later. Does the data transfer process of the scan callback part have any effect on the UART?
This problem does not appear immediately. It will appear occasionally after working for a period of time, and the probability of appearing is still quite large.
This delay can have a big impact.
I am using an nRF52840 with a baud rate of 1000000 and flow control turned on.
Here's my configuration and part of the uart driver I'm using:
.overlay file:
&uart0 {
compatible = "nordic,nrf-uarte";
status = "okay";
current-speed = <1000000>;
hw-flow-control;
tx-pin = <6>;
rx-pin = <4>;
rts-pin = <41>;
cts-pin = <8>;
};
UART driver .c file:
#include <drivers/uart.h>
#include <kernel.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(mt_uart, CONFIG_MT_UART_LOG_LEVEL);
#define UART_NAME "UART_0"
struct uart_data {
void * fifo_reserved;
uint8_t data[CONFIG_MT_UART_FIFO_SIZE];
uint16_t len;
};
static const struct device * m_uart;
static struct k_work_delayable uart_work;
static void (*m_cb)(uint8_t *data, uint16_t length);
static K_SEM_DEFINE(uart_init_sem, 0, 1);
static K_FIFO_DEFINE(fifo_uart_tx);
static K_FIFO_DEFINE(fifo_uart_rx);
static void uart_work_handler(struct k_work *item)
{
struct uart_data *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, K_MSEC(CONFIG_MT_UART_RX_TIMEOUT));
return;
}
uart_rx_enable(m_uart, buf->data, sizeof(buf->data), 100);
}
static void _uart_tx_abort(struct uart_event *evt, uint8_t **ta_buf,
size_t *ta_len)
{
struct uart_data *buf;
if (!*ta_buf) {
*ta_buf = (uint8_t *)evt->data.tx.buf;
}
*ta_len += evt->data.tx.len;
buf = CONTAINER_OF(*ta_len, struct uart_data, data);
(void)uart_tx(m_uart, &buf->data[*ta_len], buf->len - *ta_len,
SYS_FOREVER_MS);
}
static void _uart_tx_done(struct uart_event *evt, uint8_t **ta_buf,
size_t *ta_len)
{
struct uart_data *buf;
if ((evt->data.tx.len == 0) || (!evt->data.tx.buf)) {
LOG_WRN("Invalid UART_TX_DONE event.");
return;
}
if (*ta_buf) {
buf = CONTAINER_OF(*ta_buf, struct uart_data, data);
*ta_buf = NULL;
*ta_len = 0;
} else {
buf = CONTAINER_OF(evt->data.tx.buf, struct uart_data, data);
}
k_free(buf);
buf = k_fifo_get(&fifo_uart_tx, K_NO_WAIT);
if (!buf) {
LOG_DBG("Uart tx fifo is empty.");
return;
}
if (uart_tx(m_uart, buf->data, buf->len, SYS_FOREVER_MS)) {
LOG_ERR("Failed to send data over UART");
}
}
static void uart_cb(const struct device *dev, struct uart_event *evt,
void *user_data)
{
const char *s[] = { "TX_DONE", "TX_ABORTED", "RX_READY", "RX_BUF_REQ",
"RX_BUF_REL", "RX_DISABLE", "RX_STOP" };
LOG_INF("Evt %s.", s[evt->type]);
/* Uart tx aborted buffer. */
static uint8_t *ta_buf = NULL;
static size_t ta_len = 0;
static uint8_t *current_buf;
static bool buf_release;
struct uart_data *buf;
switch (evt->type) {
case UART_TX_DONE:
_uart_tx_done(evt, &ta_buf, &ta_len);
break;
case UART_TX_ABORTED:
_uart_tx_abort(evt, &ta_buf, &ta_len);
break;
case UART_RX_RDY:
buf = CONTAINER_OF(evt->data.rx.buf, struct uart_data, data);
buf->len = evt->data.rx.len + evt->data.rx.offset;
if (buf->len < CONFIG_MT_UART_FIFO_SIZE) {
current_buf = evt->data.rx.buf;
buf_release = true;
uart_rx_disable(m_uart);
} else if (!buf_release) {
k_fifo_put(&fifo_uart_rx, buf);
}
break;
case UART_RX_BUF_REQUEST:
buf = k_malloc(sizeof(*buf));
if (buf) {
buf->len = 0;
uart_rx_buf_rsp(m_uart, buf->data, sizeof(buf->data));
} else {
LOG_WRN("Not able to allocate UART receive buffer");
}
break;
case UART_RX_BUF_RELEASED:
buf = CONTAINER_OF(evt->data.rx.buf, struct uart_data, data);
if (buf_release) {
if (current_buf != evt->data.rx_buf.buf) {
k_free(buf);
buf_release = false;
current_buf = NULL;
} else {
k_fifo_put(&fifo_uart_rx, buf);
}
}
break;
case UART_RX_DISABLED:
uart_work_handler(NULL);
break;
case UART_RX_STOPPED:
// Nothing to do here.
LOG_WRN("Uart rx stop reason: %d.", evt->data.rx_stop.reason);
break;
default:
break;
}
}
int mt_uart_tx(void *data, uint16_t len)
{
__ASSERT(data != NULL, "Invalid input.");
__ASSERT(len != 0, "Invalid input.");
for (uint16_t pos = 0; pos != len;) {
struct uart_data *tx = k_malloc(sizeof(*tx));
if (!tx) {
LOG_WRN("Unable to allocate UART sending buffer.");
return -1;
}
int ofs = len - pos;
tx->len = (ofs > CONFIG_MT_UART_FIFO_SIZE) ? CONFIG_MT_UART_FIFO_SIZE : ofs;
memcpy(tx->data, (uint8_t *)data + pos, tx->len);
pos += tx->len;
int err = uart_tx(m_uart, tx->data, tx->len, SYS_FOREVER_MS);
if (err) {
k_fifo_put(&fifo_uart_tx, tx);
}
}
return 0;
}
void mt_uart_init(void (*cb)(uint8_t *, uint16_t))
{
__ASSERT(cb != NULL, "Invalid input.");
int err = 0;
m_cb = *cb;
m_uart = device_get_binding(UART_NAME);
__ASSERT(m_uart != NULL, "Uart not found.");
err = uart_callback_set(m_uart, uart_cb, NULL);
__ASSERT(err == 0, "Uart callback set fail %d.", err);
k_work_init_delayable(&uart_work, uart_work_handler);
k_sem_give(&uart_init_sem);
struct uart_data *buf = k_malloc(sizeof(*buf));
__ASSERT(buf != NULL, "Not able to allocate UART receive buffer");
buf->len = 0;
err = uart_rx_enable(m_uart, buf->data, sizeof(buf->data), 50);
__ASSERT(err == 0, "Uart failed to enable receive %d.", err);
LOG_INF("Uart init success.");
return;
}
static void uart_dpt_thread(void)
{
k_sem_take(&uart_init_sem, K_FOREVER);
for (;;) {
struct uart_data *buf = k_fifo_get(&fifo_uart_rx, K_FOREVER);
m_cb(buf->data, buf->len);
k_free(buf);
}
}
K_THREAD_DEFINE(uart_dpt_thread_id, CONFIG_MT_UART_THREAD_STACK_SIZE,
uart_dpt_thread, NULL, NULL, NULL, CONFIG_MT_UART_THREAD_PRIORITY,
0, 0);
Kconfig file:
config MT_UART_LOG_LEVEL
int "log level of uart module"
range 0 4
default 3
help
Indicate log level.
config MT_UART_FIFO_SIZE
int "Uart fifo size"
range 64 16384
default 64
config MT_UART_RX_TIMEOUT
int "Uart receive timeout"
range 50 1000
default 50
config MT_UART_THREAD_PRIORITY
int "thread priority"
default 7
config MT_UART_THREAD_STACK_SIZE
int "Thread stack size"
default 1024
help
The stack size used by the thread.
prj.conf file:
CONFIG_SERIAL=y CONFIG_UART_ASYNC_API=y CONFIG_UART_0_NRF_TX_BUFFER_SIZE=64 CONFIG_UART_0_NRF_HW_ASYNC=y CONFIG_UART_0_NRF_HW_ASYNC_TIMER=2 CONFIG_MT_UART_FIFO_SIZE=512
Is there any problem?
Hope to get your reply soon, thanks!
