Cannot get Async UART0 to work with USB CDC

Hello,

I first got the USB CDC Zephyr sample with interrupt driven UART to work just fine. 

But because I want to to be able to TX outside of interrupts I tried to convert that sample to use Async UART while using USB CDC.  I have looked at all tickets that seem related to this but nothing works, maybe because I'm using a  newer SDK version, which is v2.4.2.

When I call uart_callback_set I get -ENOSYS.   I can see all callbacks for the API are not set which is why I get this.  (I print the pointers and they are 0)

from C:\ncs\v2.4.2\zephyr\include\zephyr\drivers\uart.h

static inline int uart_callback_set(const struct device *dev,
				    uart_callback_t callback,
				    void *user_data)
{
#ifdef CONFIG_UART_ASYNC_API
	const struct uart_driver_api *api =
			(const struct uart_driver_api *)dev->api;

	if (api->callback_set == NULL) {
		return -ENOSYS;
	}

	return api->callback_set(dev, callback, user_data);
#else
	ARG_UNUSED(dev);
	ARG_UNUSED(callback);
	ARG_UNUSED(user_data);
	return -ENOTSUP;
#endif
}

I have tried all kings of CONFIG options (from other tickets) and nothing seems to work.  I can see the ASYNC code is enabled in the file C:\ncs\v2.4.2\zephyr\drivers\serial\uart_nrfx_uarte.c.  I can not see the linkage with the calling of DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart) and driver API callbacks being set correctly. 

Last configs I tried are:

CONFIG_LOG=y

CONFIG_MAIN_STACK_SIZE=1536


CONFIG_STDOUT_CONSOLE=y

CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DEVICE_PRODUCT="Zephyr CDC ACM sample"
CONFIG_USB_DEVICE_SN="0123456789ABCDEG"
CONFIG_USB_DEVICE_MANUFACTURER="Zephyr USBD CDC ACM with MS"
CONFIG_USB_DEVICE_PID=0x0002
CONFIG_USB_DEVICE_VID=0x2fe3
CONFIG_USB_DRIVER_LOG_LEVEL_ERR=y
CONFIG_USB_DEVICE_LOG_LEVEL_ERR=y
CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n
CONFIG_USB_CDC_ACM=y
CONFIG_SERIAL=y

CONFIG_UART_ASYNC_API=y
CONFIG_UART_INTERRUPT_DRIVEN=y
CONFIG_UART_0_ASYNC=y
CONFIG_UART_0_INTERRUPT_DRIVEN=n
CONFIG_NRFX_UARTE0=y

CONFIG_UART_LINE_CTRL=y

&zephyr_udc0 {
	cdc_acm_uart0 {
		compatible = "zephyr,cdc-acm-uart";
	};
};

My Code

#include <zephyr/kernel.h>
#include <zephyr/device.h>


#include <zephyr/usb/usb_device.h>
#include <zephyr/usb/usbd.h>

#include <zephyr/drivers/uart.h>
#include <zephyr/sys/ring_buffer.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);

#define RING_BUF_SIZE 1024
uint8_t ring_buffer[RING_BUF_SIZE];
struct ring_buf ringbuf;

// static void interrupt_handler(const struct device *dev, void *user_data)
// {
// 	ARG_UNUSED(user_data);

// 	LOG_INF("11");

// 	while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {

// 		LOG_INF("222");

// 		if (uart_irq_rx_ready(dev)) {
// 			int recv_len, rb_len;
// 			uint8_t buffer[64];
// 			size_t len = MIN(ring_buf_space_get(&ringbuf), sizeof(buffer));

// 			recv_len = uart_fifo_read(dev, buffer, len);
// 			if (recv_len < 0) {
// 				LOG_ERR("Failed to read UART FIFO");
// 				recv_len = 0;
// 			};

// 			rb_len = ring_buf_put(&ringbuf, buffer, recv_len);
// 			if (rb_len < recv_len) {
// 				LOG_ERR("Drop %u bytes", recv_len - rb_len);
// 			}

// 			LOG_DBG("tty fifo -> ringbuf %d bytes", rb_len);
// 			if (rb_len) {
// 				uart_irq_tx_enable(dev);
// 			}
// 		}

// 		if (uart_irq_tx_ready(dev)) {
// 			uint8_t buffer[64];
// 			int rb_len, send_len;

// 			rb_len = ring_buf_get(&ringbuf, buffer, sizeof(buffer));
// 			if (!rb_len) {
// 				LOG_DBG("Ring buffer empty, disable TX IRQ");
// 				uart_irq_tx_disable(dev);
// 				continue;
// 			}

// 			send_len = uart_fifo_fill(dev, buffer, rb_len);
// 			if (send_len < rb_len) {
// 				LOG_ERR("Drop %d bytes", rb_len - send_len);
// 			}

// 			LOG_DBG("ringbuf -> tty fifo %d bytes", send_len);
// 		}
// 	}
// }

static uint8_t rx_buf[64] = {0}; //A buffer to store incoming UART data 

static void async_interrupt_cb(const struct device *dev, struct uart_event *evt, void *user_data)
{
	switch (evt->type) {
	
	case UART_TX_DONE:
		// do something
		break;

	case UART_TX_ABORTED:
		// do something
		break;
		
	case UART_RX_RDY:
		LOG_INF("UART_RX_RDY");
		break;

	case UART_RX_BUF_REQUEST:
		LOG_INF("UART_RX_BUF_REQUEST");
		break;

	case UART_RX_BUF_RELEASED:
		LOG_INF("UART_RX_BUF_RELEASED");
		break;
		
	case UART_RX_DISABLED:
		// do something
		break;

	case UART_RX_STOPPED:
		// do something
		break;
		
	default:
		break;
	}
}

int main(void) {

	const struct device *dev;
	uint32_t baudrate, dtr = 0U;
	int ret;

	//
	// Setup USB
	//

	dev = DEVICE_DT_GET_ONE(zephyr_cdc_acm_uart);
	if (!device_is_ready(dev)) {
		LOG_ERR("CDC ACM device not ready");
		return 0;
	}

	ret = usb_enable(NULL);

	LOG_INF("Configured.......");

	if (ret != 0) {
		LOG_ERR("Failed to enable USB");
		return 0;
	}

	ring_buf_init(&ringbuf, sizeof(ring_buffer), ring_buffer);

	LOG_INF("Wait for DTR");

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

	LOG_INF("DTR set");

		/* They are optional, we use them to test the interrupt endpoint */
	ret = uart_line_ctrl_set(dev, UART_LINE_CTRL_DCD, 1);
	if (ret) {
		LOG_WRN("Failed to set DCD, ret code %d", ret);
	}

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

	/* Wait 100ms for the host to do all settings */
	k_msleep(100);

	ret = uart_line_ctrl_get(dev, UART_LINE_CTRL_BAUD_RATE, &baudrate);
	if (ret) {
		LOG_WRN("Failed to get baudrate, ret code %d", ret);
	} else {
		LOG_INF("Baudrate detected: %d", baudrate);
	}


	//uart_irq_callback_set(dev, interrupt_handler);
	ret = uart_callback_set(dev, async_interrupt_cb, NULL);
	if (ret != 0) { // :TODO:
		LOG_ERR("Failed to register UART UART cb: %i", ret);
		return 0;
	}

	/* Enable rx interrupts */
	//uart_irq_rx_enable(dev);

	ret = uart_rx_enable(dev, rx_buf, sizeof(rx_buf), 100);
	if (ret != 0) { // :TODO:
		LOG_ERR("Failed to enable UART RX");
		return 0;
	}

	LOG_INF("Starting Observer Demo\n");

	LOG_ERR("Exiting %s thread", __func__);
	return 0;
}

When I connect with pyserial I always get the error NOSYS, 88.  You will note I can make some sort of connection to get the baudrate.  (below)

*** Booting Zephyr OS build v3.3.99-ncs1-1 ***
[00:00:00.416,503] <inf> main: Configured.......
[00:00:00.416,534] <inf> main: Wait for DTR
[00:00:00.420,562] <inf> usb_cdc_acm: Device suspended
[00:00:00.518,188] <inf> usb_cdc_acm: Device resumed
[00:00:00.869,995] <inf> usb_cdc_acm: Device configured
[00:00:04.319,244] <inf> main: DTR set
[00:00:04.433,929] <inf> main: Baudrate detected: 115200
[00:00:04.433,959] <err> main: Failed to register UART UART cb: -88

After spending hours on this I don't know what else to try.  Any help with this would be very much appreciated.

Async UART0 (with EasyDMA) is supposed to work with USB CDC, they are compatible?

Parents Reply Children
No Data
Related