Increase double buffer size for async UART caused EACCES

Hi, 

I'm trying to increase the UART buffer size for the asynchronous UART API, but I'm encountering an error. When the message size is set to 255, I can successfully receive data from my GPS sensor. However, when I increase the message size to 512, I get an error code of -13 (EACCES) from UART_RX_BUF_REQUEST. The only variable I changed is #define MSG_SIZE 512.

I would greatly appreciate any insights or suggestions from the forum.

Question:

1. What could be causing this EACCES error when increasing the UART buffer size?

2. What steps can I take to resolve this issue and increase message size to 1024?

Here is the code I use for testing:

main.c

#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
#define LOG_MODULE_NAME main
LOG_MODULE_REGISTER(LOG_MODULE_NAME);

#define MSG_SIZE 512
#define MSG_QUEUE_SIZE	5
struct uart_data{
	char msg[MSG_SIZE];
	int len;
};
K_MSGQ_DEFINE(uart_msgq, sizeof(struct uart_data), MSG_QUEUE_SIZE, 1);

#define UART0_NODE DT_NODELABEL(uart0)
static const struct device *uart_dev = DEVICE_DT_GET(DT_NODELABEL(uart0));

static const struct gpio_dt_spec ldo = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
static const struct gpio_dt_spec led4 = GPIO_DT_SPEC_GET(DT_ALIAS(led4), gpios);
uint8_t uart_double_buffer[2][MSG_SIZE];
uint8_t *uart_buf_next = uart_double_buffer[1];
K_SEM_DEFINE(uart_tx_done, 0, 1);


static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data)
{
    switch (evt->type)
    {
    case UART_RX_RDY:
        LOG_INF("UART_RX_RDY %d byte, offset %d", evt->data.rx.len, evt->data.rx.offset);
		struct uart_data k_data;
		char* buf_ptr = evt->data.rx.buf + evt->data.rx.offset;
		memcpy(k_data.msg, buf_ptr, evt->data.rx.len);
		k_data.len = evt->data.rx.len;
		if (k_msgq_put(&uart_msgq, &k_data, K_NO_WAIT)!=0)
			k_msgq_purge(&uart_msgq);
		break;
	case UART_RX_BUF_REQUEST:
		LOG_INF("UART_RX_BUF_REQUEST");
		int ret = uart_rx_buf_rsp(uart_dev, uart_buf_next, MSG_SIZE);
		LOG_INF("uart_rx_buf_rsp:%d",ret);
		break;
	case UART_RX_BUF_RELEASED:
		LOG_INF("UART_RX_BUF_RELEASED");
		// memset(evt->data.rx_buf.buf, 0 , MSG_SIZE);
		uart_buf_next = evt->data.rx_buf.buf;
		break;
	default:
		LOG_INF("UART evt:%d",evt->type);
		break;
    }
}


int gps_on(void){
	if (!gpio_is_ready_dt(&ldo)) {
		return -1;
	}
	int ret = gpio_pin_configure_dt(&ldo, GPIO_OUTPUT_ACTIVE);
	ret = gpio_pin_configure_dt(&led4, GPIO_OUTPUT_ACTIVE);
	return 0;
}

void init_uart(void){
	int err;
	if (!device_is_ready(uart_dev)) 
		LOG_INF("UART device not found!");
	err = uart_callback_set(uart_dev, uart_cb, NULL);
		LOG_INF("uart_callback_set %d",err);
	err = uart_rx_enable(uart_dev, uart_double_buffer[0], MSG_SIZE, 200);
		LOG_INF("uart_rx_enable %d",err);
}

int main(void)
{
	
	init_uart();
	gps_on();
	LOG_INF("started");
	struct uart_data tx_buf;
	while (k_msgq_get(&uart_msgq, &tx_buf, K_FOREVER) == 0) {
		LOG_INF("%s",tx_buf.msg);
	}

	return 0;
}

KConfig

CONFIG_SERIAL=y
CONFIG_UART_ASYNC_API=y

CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=n

CONFIG_LOG=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=n
CONFIG_RTT_CONSOLE=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_LOG_BACKEND_RTT=y
CONFIG_LOG_BACKEND_UART=n

CONFIG_MAIN_STACK_SIZE=4096
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048

I've already tried the following:

- double MAIN_STACK_SIZE

- double SYSTEM_WORKQUEUE_STACK_SIZE

- searching uart EACCES related problems

- re-visit Nordic academy about UART driver

- Take a look at UART driver documents(https://docs.zephyrproject.org/latest/hardware/peripherals/uart.html#uart-async-api)

Additional Information:

- ncs 2.6.1

- nRF Connect for vs code v2024.3.25, windows

- nRF52832 QFAA

Parents
  • Hello,

    The UARTE DMA pointer on the nRF52832 is 8 bit wide, which limits the max. buffer size to 256 bytes.

    Best regards,

    Vidar

  • Thanks for the quick reply! So, it seems like a hardware limitation with the asynchronous UARTE.

    If so, are there any ways to work around this limitation? Because I'm looking for the most efficient way to handle a UART device that transmit 50KB total file size with 1024 bytes in one transaction. My though on bypass the limitation:

    1. Increase maximum number of messages that can be queued. e.g. 
      K_MSGQ_DEFINE(uart_rx_msgqsizeof(struct uart_msg_queue_item), 5, 1);
      (does the mcu perform fast enough to put data from uart isr to message queue? will there any byte loss?)
    2. Disable DMA with KConfig/command in asynchronous UART API. 
    3. if 1&2 not possible, is switching to interrupt-based approach be the only solution in this case? 

    Any insights or recommendations would be greatly appreciated!

Reply
  • Thanks for the quick reply! So, it seems like a hardware limitation with the asynchronous UARTE.

    If so, are there any ways to work around this limitation? Because I'm looking for the most efficient way to handle a UART device that transmit 50KB total file size with 1024 bytes in one transaction. My though on bypass the limitation:

    1. Increase maximum number of messages that can be queued. e.g. 
      K_MSGQ_DEFINE(uart_rx_msgqsizeof(struct uart_msg_queue_item), 5, 1);
      (does the mcu perform fast enough to put data from uart isr to message queue? will there any byte loss?)
    2. Disable DMA with KConfig/command in asynchronous UART API. 
    3. if 1&2 not possible, is switching to interrupt-based approach be the only solution in this case? 

    Any insights or recommendations would be greatly appreciated!

Children
Related