peripheral_uart report Not able to allocate UART receive buffer

Hi,

I am programming with nrf52833,ncs v2.9.0,generating peripheral_uart to peripheral_hid_keyboard sdk.

And now with working serial times,err happend and log is Not able to allocate UART receive buffer.

LOG is

E: No connection for handle 0
E: No connection for handle 0
W: Not able to allocate UART receive buffer, UART_RX_BUF_REQUEST
W: Not able to allocate UART receive buffer, UART_RX_DISABLED
W: Not able to allocate UART receive buffer, uart_work_handler

My code is

static const struct device *uart = DEVICE_DT_GET(DT_CHOSEN(nordic_nus_uart));
static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data)
{
	ARG_UNUSED(dev);

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

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

		if (aborted_buf) {
			buf = CONTAINER_OF(aborted_buf, uart_data_t, data[0]);
			aborted_buf = NULL;
			aborted_len = 0;
		} else {
			buf = CONTAINER_OF(evt->data.tx.buf, 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, UART_TX_DONE");
		}

		break;

	case UART_RX_RDY:
		LOG_INF("UART_RX_RDY");	

		buf = CONTAINER_OF(evt->data.rx.buf, uart_data_t, data[0]);
		// 防止缓冲区溢出
		if (buf->len + evt->data.rx.len <= sizeof(buf->data)) {
			buf->len += evt->data.rx.len;
		} else {
			LOG_WRN("UART RX buffer overflow detected");
			buf->len = sizeof(buf->data); // 截断处理
		}

		//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_INF("UART_RX_DISABLED");

		disable_req = false;

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

	case UART_RX_BUF_REQUEST:
		LOG_INF("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, UART_RX_BUF_REQUEST");
		}

		break;

	case UART_RX_BUF_RELEASED:
		LOG_INF("UART_RX_BUF_RELEASED");

		buf = CONTAINER_OF(evt->data.rx_buf.buf, uart_data_t, data[0]);

		if (buf->len > 0) {
			k_fifo_put(&fifo_uart_rx_data, buf);
			//LOG_INF("k_fifo_put buf addr:%p", buf);
		} else {
			k_free(buf);
		}

		break;

	case UART_TX_ABORTED:
		LOG_INF("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, uart_data_t, data);
		if(!buf) {
			LOG_ERR("Invalid buffer in UART_TX_ABORTED");
			return;
		}
		uart_tx(uart, &buf->data[aborted_len],
			buf->len - aborted_len, SYS_FOREVER_MS);

		break;

	default:
		break;
	}
}

static void uart_work_handler(struct k_work *item)
{
	uart_data_t *buf;

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

	uart_rx_enable(uart, buf->data, sizeof(buf->data), UART_WAIT_FOR_RX);
}
static bool uart_test_async_api(const struct device *dev)
{
	const struct uart_driver_api *api =
			(const struct uart_driver_api *)dev->api;

	return (api->callback_set != NULL);
}



static int uart_init(void)
{
	int err;
	int pos;
	uart_data_t *rx;
	uart_data_t *tx;
	if (!device_is_ready(uart)) {
		return -ENODEV;
	}

	rx = k_malloc(sizeof(*rx));
	if (rx) {
		rx->len = 0;
	} else {
		return -ENOMEM;
	}

	k_work_init_delayable(&uart_work, uart_work_handler);


	if (IS_ENABLED(CONFIG_BT_NUS_UART_ASYNC_ADAPTER) && !uart_test_async_api(uart)) {
		/* Implement API adapter */
		uart_async_adapter_init(async_adapter, uart);
		uart = async_adapter;
	}

	err = uart_callback_set(uart, uart_cb, NULL);
	if (err) {
		k_free(rx);
		LOG_ERR("Cannot initialize UART callback");
		return err;
	}

	if (IS_ENABLED(CONFIG_UART_LINE_CTRL)) {
		while (true) {
			uint32_t dtr = 0;

			uart_line_ctrl_get(uart, UART_LINE_CTRL_DTR, &dtr);
			if (dtr) {
				break;
			}
			/* Give CPU resources to low priority threads. */
			k_sleep(K_MSEC(100));
		}

		err = uart_line_ctrl_set(uart, UART_LINE_CTRL_DCD, 1);
		if (err) {
			LOG_WRN("Failed to set DCD, ret code %d", err);
		}
		err = uart_line_ctrl_set(uart, UART_LINE_CTRL_DSR, 1);
		if (err) {
			LOG_WRN("Failed to set DSR, ret code %d", err);
		}
	}

	tx = k_malloc(sizeof(*tx));

	if (tx) {
		pos = snprintf(tx->data, sizeof(tx->data),
			       "Starting ...\r\n");

		if ((pos < 0) || (pos >= sizeof(tx->data))) {
			k_free(rx);
			k_free(tx);
			LOG_ERR("snprintf returned %d", pos);
			return -ENOMEM;
		}

		tx->len = pos;
	} else {
		k_free(rx);
		return -ENOMEM;
	}

	err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS);
	if (err) {
		k_free(rx);
		k_free(tx);
		LOG_ERR("Cannot display welcome message (err: %d)", err);
		return err;
	}

	err = uart_rx_enable(uart, rx->data, sizeof(rx->data), UART_WAIT_FOR_RX);
	if (err) {
		LOG_ERR("Cannot enable uart reception (err: %d)", err);
		/* Free the rx buffer only because the tx buffer will be handled in the callback */
		k_free(rx);
	}

	return err;
}

Best regard

Martin

Parents
  • Hello Martin,

    The error log messages like Not able to allocate UART receive buffer and repeated warnings on UART_RX_BUF_REQUEST, UART_RX_DISABLED, and in uart_work_handler indicate that your application is running out of heap memory when trying to allocate new UART receive buffers with k_malloc().
    This is a common issue in Nordic UART Service (NUS) and Zephyr-based UART async applications, especially when:
    The heap is too small for the number/size of buffers you are allocating.
    Buffers are not being freed properly, leading to memory leaks.
    Data is not being processed and released quickly enough, causing buffer buildup.

    But I can see in the comment that you have already set CONFIG_HEAP_MEM_POOL_SIZE=8192 and are still seeing errors like "Not able to allocate UART receive buffer," the heap size may be a cause, but it is not the only possible reason.

    Looking at the code, I can see you have correctly freed buffers in the UART callback for TX and RX buffers with no data. However, you must also free RX buffers after processing them from fifo_uart_rx_data. 

    Here in your code

    case UART_RX_BUF_RELEASED:
        LOG_INF("UART_RX_BUF_RELEASED");
    
        buf = CONTAINER_OF(evt->data.rx_buf.buf, uart_data_t, data[0]);
    
        if (buf->len > 0) {
            k_fifo_put(&fifo_uart_rx_data, buf);
            //LOG_INF("k_fifo_put buf addr:%p", buf);
        } else {
            k_free(buf);
        }
    
        break;

    when a buffer is released and contains data (buf->len > 0), you put it into the FIFO (fifo_uart_rx_data) for further processing. However, you do not free the buffer at this point—you only free it immediately if it is empty.

    Why does this mean you must free it later?
    • Once the buffer is placed in the FIFO, it is no longer managed by the UART driver. It is now your application's responsibility to process and eventually free it.
    • If you do not free the buffer after processing it from the FIFO, it will remain allocated, leading to a memory leak and eventually causing "Not able to allocate UART receive buffer" errors as the heap is exhausted.
  • Hi,

    Losting that, there is a thread working continuously to free this buffer.

    This issue will happend after code working more than two hours.I am confuse of this

    #define STACKSIZE 4096
    #define PRIORITY 7
    
    void ble_write_thread(void)
    {
    	for (;;) {
    		/* Wait indefinitely for data to be sent over bluetooth */
    		int i = 0, j = 0;
    		uint8_t command[32] = {0};
    		uint8_t analys_data[128] = {0};
    		uart_data_t *buf;
    		buf = k_fifo_get(&fifo_uart_rx_data, K_FOREVER);
    		uart_data_t data;
    		memcpy(&data, buf, sizeof(uart_data_t));
    
    		if(buf) {
    		    //fifo_uart_rx_data will be free here.
    			k_free(buf);
    		}
    	    //…… other code,but no delay
    	}
    }
    K_THREAD_DEFINE(ble_write_thread_id, STACKSIZE, ble_write_thread, NULL, NULL, NULL, PRIORITY, 0, 0);

Reply
  • Hi,

    Losting that, there is a thread working continuously to free this buffer.

    This issue will happend after code working more than two hours.I am confuse of this

    #define STACKSIZE 4096
    #define PRIORITY 7
    
    void ble_write_thread(void)
    {
    	for (;;) {
    		/* Wait indefinitely for data to be sent over bluetooth */
    		int i = 0, j = 0;
    		uint8_t command[32] = {0};
    		uint8_t analys_data[128] = {0};
    		uart_data_t *buf;
    		buf = k_fifo_get(&fifo_uart_rx_data, K_FOREVER);
    		uart_data_t data;
    		memcpy(&data, buf, sizeof(uart_data_t));
    
    		if(buf) {
    		    //fifo_uart_rx_data will be free here.
    			k_free(buf);
    		}
    	    //…… other code,but no delay
    	}
    }
    K_THREAD_DEFINE(ble_write_thread_id, STACKSIZE, ble_write_thread, NULL, NULL, NULL, PRIORITY, 0, 0);

Children
No Data
Related