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?