diff --git a/examples/peripherals/usb/device/cherryusb_serial_device/CMakeLists.txt b/examples/peripherals/usb/device/cherryusb_serial_device/CMakeLists.txt new file mode 100644 index 0000000000..e0a468eee7 --- /dev/null +++ b/examples/peripherals/usb/device/cherryusb_serial_device/CMakeLists.txt @@ -0,0 +1,7 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +idf_build_set_property(MINIMAL_BUILD ON) +project(cherryusb_serial_device) diff --git a/examples/peripherals/usb/device/cherryusb_serial_device/README.md b/examples/peripherals/usb/device/cherryusb_serial_device/README.md new file mode 100644 index 0000000000..48e1000333 --- /dev/null +++ b/examples/peripherals/usb/device/cherryusb_serial_device/README.md @@ -0,0 +1,85 @@ +| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | + +# CherryUSB Serial Device Example + +Starts a CDC Device, and sends back any received data from the host. + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +## How to use example + +This example can also be configured to act as double serial device. +Run `idf.py menuconfig` and in `Example Configuration → Enable usb cdc acm two channel` enable. + +### Hardware Required + +Any ESP board that have USB-OTG supported. + +#### Pin Assignment + +_Note:_ In case your board doesn't have micro-USB connector connected to USB-OTG peripheral, you may have to DIY a cable and connect **D+** and **D-** to the pins listed below. + +See common pin assignments for USB Device examples from [upper level](../../README.md#common-pin-assignments). + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +```bash +idf.py -p PORT flash monitor +``` + +(Replace PORT with the name of the serial port to use.) + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example output + +When running, the example will print the following output: + +``` +I (271) main_task: Started on CPU0 +I (291) main_task: Calling app_main() +[I/USB] cherryusb, version: v1.4.3 +[I/USB] ========== dwc2 udc params ========== +[I/USB] CID:00000000 +[I/USB] GSNPSID:4f54400a +[I/USB] GHWCFG1:00000000 +[I/USB] GHWCFG2:224dd930 +[I/USB] GHWCFG3:00c804b5 +[I/USB] GHWCFG4:d3f0a030 +[I/USB] dwc2 fsphy type:1, hsphy type:0, dma support:2 +[I/USB] dwc2 has 7 endpoints and dfifo depth(32-bit words) is 200, default config: 7 endpoints +[I/USB] ================================= +[I/USB] fifo0 size:0010, offset:0050 +[I/USB] fifo1 size:0010, offset:0060 +[I/USB] fifo2 size:0010, offset:0070 +[I/USB] fifo3 size:0010, offset:0080 +[I/USB] fifo4 size:0010, offset:0090 +[I/USB] fifo5 size:0010, offset:00a0 +[I/USB] fifo6 size:0010, offset:00b0 +I (391) device_cdc_main: usb cdc acm init done +I (721) device_cdc_main: intf:0, dtr:0 +I (721) device_cdc_main: intf:0, rts:0 +I (2981) device_cdc_main: intf:0, dtr:0 +I (2981) device_cdc_main: intf:0, rts:0 +I (2981) device_cdc_main: intf:0, dtr:0 +I (2981) device_cdc_main: intf:0, rts:0 +I (2981) device_cdc_main: intf:0, dtr:0 +I (2981) device_cdc_main: intf:0, rts:0 +I (2991) device_cdc_main: intf:0, dtr:0 +I (2991) device_cdc_main: intf:0, rts:0 +I (2991) device_cdc_main: intf:0, dtr:0 +I (2991) device_cdc_main: intf:0, rts:0 +I (3001) device_cdc_main: intf:0, dtr:0 +I (3001) device_cdc_main: intf:0, rts:0 +I (6011) device_cdc_main: actual out len:13 +I (6021) device_cdc_main: actual in len:13 +I (10411) device_cdc_main: actual out len:13 +I (10421) device_cdc_main: actual in len:13 +I (11111) device_cdc_main: intf:0, dtr:0 +I (11111) device_cdc_main: intf:0, rts:0 +``` diff --git a/examples/peripherals/usb/device/cherryusb_serial_device/main/CMakeLists.txt b/examples/peripherals/usb/device/cherryusb_serial_device/main/CMakeLists.txt new file mode 100644 index 0000000000..6795aeaca4 --- /dev/null +++ b/examples/peripherals/usb/device/cherryusb_serial_device/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "device_cdc_main.c" + INCLUDE_DIRS "." +) diff --git a/examples/peripherals/usb/device/cherryusb_serial_device/main/Kconfig.projbuild b/examples/peripherals/usb/device/cherryusb_serial_device/main/Kconfig.projbuild new file mode 100644 index 0000000000..68d6392626 --- /dev/null +++ b/examples/peripherals/usb/device/cherryusb_serial_device/main/Kconfig.projbuild @@ -0,0 +1,20 @@ +menu "Example Configuration" + + config EXAMPLE_CHERRYUSB_CDC_ACM_TWO_CHANNEL + bool "Enable usb cdc acm two channel" + default n + + config EXAMPLE_CHERRYUSB_INIT_DEINIT_LOOP + bool "Perform init deinit of cherryusb stack in a loop" + default n + + config EXAMPLE_CHERRYUSB_SET_READ_BUFFER_SIZE_MPS + bool "set usb read buffer size to MPS" + default y + help + If this option is disabled, a larger receive buffer will be configured for DMA at a time, + which may improve efficiency a little. However, when the host sends data with a length that + is an integer multiple of MPS, the host may not send ZLP, resulting in failure to report + the receipt of data in a timely manner. + +endmenu diff --git a/examples/peripherals/usb/device/cherryusb_serial_device/main/device_cdc_main.c b/examples/peripherals/usb/device/cherryusb_serial_device/main/device_cdc_main.c new file mode 100644 index 0000000000..6132154900 --- /dev/null +++ b/examples/peripherals/usb/device/cherryusb_serial_device/main/device_cdc_main.c @@ -0,0 +1,444 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" + +#include "usbd_core.h" +#include "usbd_cdc_acm.h" + +static char *TAG = "device_cdc_main"; + +#ifndef CONFIG_EXAMPLE_CHERRYUSB_CDC_ACM_TWO_CHANNEL +#define CDC_ACM_CHANNEL_NUM 1 +#else +#define CDC_ACM_CHANNEL_NUM 2 +#endif + +#define INTERFACES_NUM (2 * CDC_ACM_CHANNEL_NUM) + +#define NOTIFY_USB_CONFIGURED_BIT BIT0 +#define NOTIFY_EXIT_BIT BIT1 +#define NOTIFY_EP_BIT BIT2 + +static TaskHandle_t s_task_handle = NULL; + +/*!< endpoint address */ +#define CDC_IN_EP 0x81 +#define CDC_OUT_EP 0x01 +#define CDC_INT_EP 0x83 + +#define CDC_IN_EP1 0x82 +#define CDC_OUT_EP1 0x02 +#define CDC_INT_EP1 0x84 + +#define USBD_VID 0xFFFF +#define USBD_PID 0xFFFF +#define USBD_MAX_POWER 100 +#define USBD_LANGID_STRING 1033 + +/*!< config descriptor size */ +#define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN * 4) + +#ifdef CONFIG_USB_HS +#define CDC_MAX_MPS 512 +#else +#define CDC_MAX_MPS 64 +#endif + +typedef struct { + uint8_t rx_addr; + uint8_t tx_addr; + bool rx_busy_flag; + bool tx_busy_flag; + uint32_t read_len; + uint32_t write_len; +} ep_status_t; + +static ep_status_t s_ep_status[CDC_ACM_CHANNEL_NUM] = { + { CDC_OUT_EP, CDC_IN_EP, false, false, 0, 0 }, +#ifdef CONFIG_EXAMPLE_CHERRYUSB_CDC_ACM_TWO_CHANNEL + { CDC_OUT_EP1, CDC_IN_EP1, false, false, 0, 0 }, +#endif +}; + +#if CONFIG_EXAMPLE_CHERRYUSB_SET_READ_BUFFER_SIZE_MPS +#define READ_BUFFER_SIZE CDC_MAX_MPS +#else +#define READ_BUFFER_SIZE 2048 +#endif +static DRAM_DMA_ALIGNED_ATTR uint8_t read_buffer[CDC_ACM_CHANNEL_NUM][READ_BUFFER_SIZE]; +static DRAM_DMA_ALIGNED_ATTR uint8_t write_buffer[CDC_ACM_CHANNEL_NUM][2048]; + +#ifdef CONFIG_USBDEV_ADVANCE_DESC +static const uint8_t device_descriptor[] = { + USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01) +}; + +static const uint8_t config_descriptor[] = { + USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTERFACES_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), + CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02), +#ifdef CONFIG_EXAMPLE_CHERRYUSB_CDC_ACM_TWO_CHANNEL + CDC_ACM_DESCRIPTOR_INIT(0x02, CDC_INT_EP1, CDC_OUT_EP1, CDC_IN_EP1, CDC_MAX_MPS, 0x02), +#endif +}; + +static const uint8_t device_quality_descriptor[] = { + /////////////////////////////////////// + /// device qualifier descriptor + /////////////////////////////////////// + 0x0a, + USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, + 0x00, + 0x02, + 0x00, + 0x00, + 0x00, + 0x40, + 0x00, + 0x00, +}; + +static const char *string_descriptors[] = { + (const char[]) + { + 0x09, 0x04 + }, /* Langid */ + "CherryUSB", /* Manufacturer */ + "CherryUSB CDC MULTI DEMO", /* Product */ + "2025060518", /* Serial Number */ +}; + +static const uint8_t *device_descriptor_callback(uint8_t speed) +{ + return device_descriptor; +} + +static const uint8_t *config_descriptor_callback(uint8_t speed) +{ + return config_descriptor; +} + +static const uint8_t *device_quality_descriptor_callback(uint8_t speed) +{ + return device_quality_descriptor; +} + +static const char *string_descriptor_callback(uint8_t speed, uint8_t index) +{ + if (index > 3) { + return NULL; + } + return string_descriptors[index]; +} + +const struct usb_descriptor cdc_descriptor = { + .device_descriptor_callback = device_descriptor_callback, + .config_descriptor_callback = config_descriptor_callback, + .device_quality_descriptor_callback = device_quality_descriptor_callback, + .string_descriptor_callback = string_descriptor_callback +}; +#else +/*!< global descriptor */ +static const uint8_t cdc_descriptor[] = { + USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01), + USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, INTERFACES_NUM, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), + CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02), +#ifdef CONFIG_EXAMPLE_CHERRYUSB_CDC_ACM_TWO_CHANNEL + CDC_ACM_DESCRIPTOR_INIT(0x02, CDC_INT_EP1, CDC_OUT_EP1, CDC_IN_EP1, CDC_MAX_MPS, 0x02), +#endif + /////////////////////////////////////// + /// string0 descriptor + /////////////////////////////////////// + USB_LANGID_INIT(USBD_LANGID_STRING), + /////////////////////////////////////// + /// string1 descriptor + /////////////////////////////////////// + 0x14, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + 'C', 0x00, /* wcChar0 */ + 'h', 0x00, /* wcChar1 */ + 'e', 0x00, /* wcChar2 */ + 'r', 0x00, /* wcChar3 */ + 'r', 0x00, /* wcChar4 */ + 'y', 0x00, /* wcChar5 */ + 'U', 0x00, /* wcChar6 */ + 'S', 0x00, /* wcChar7 */ + 'B', 0x00, /* wcChar8 */ + /////////////////////////////////////// + /// string2 descriptor + /////////////////////////////////////// + 0x26, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + 'C', 0x00, /* wcChar0 */ + 'h', 0x00, /* wcChar1 */ + 'e', 0x00, /* wcChar2 */ + 'r', 0x00, /* wcChar3 */ + 'r', 0x00, /* wcChar4 */ + 'y', 0x00, /* wcChar5 */ + 'U', 0x00, /* wcChar6 */ + 'S', 0x00, /* wcChar7 */ + 'B', 0x00, /* wcChar8 */ + ' ', 0x00, /* wcChar9 */ + 'C', 0x00, /* wcChar10 */ + 'D', 0x00, /* wcChar11 */ + 'C', 0x00, /* wcChar12 */ + ' ', 0x00, /* wcChar13 */ + 'D', 0x00, /* wcChar14 */ + 'E', 0x00, /* wcChar15 */ + 'M', 0x00, /* wcChar16 */ + 'O', 0x00, /* wcChar17 */ + /////////////////////////////////////// + /// string3 descriptor + /////////////////////////////////////// + 0x16, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + '2', 0x00, /* wcChar0 */ + '0', 0x00, /* wcChar1 */ + '2', 0x00, /* wcChar2 */ + '5', 0x00, /* wcChar3 */ + '0', 0x00, /* wcChar4 */ + '6', 0x00, /* wcChar5 */ + '0', 0x00, /* wcChar6 */ + '5', 0x00, /* wcChar7 */ + '1', 0x00, /* wcChar8 */ + '8', 0x00, /* wcChar9 */ +#ifdef CONFIG_USB_HS + /////////////////////////////////////// + /// device qualifier descriptor + /////////////////////////////////////// + 0x0a, + USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, + 0x00, + 0x02, + 0x00, + 0x00, + 0x00, + 0x40, + 0x00, + 0x00, +#endif + 0x00 +}; +#endif + +void usbd_event_handler(uint8_t busid, uint8_t event) +{ + switch (event) { + case USBD_EVENT_RESET: + break; + case USBD_EVENT_CONNECTED: + break; + case USBD_EVENT_DISCONNECTED: + break; + case USBD_EVENT_RESUME: + break; + case USBD_EVENT_SUSPEND: + break; + case USBD_EVENT_CONFIGURED: { + BaseType_t HPTaskAwoken = pdFALSE; + xTaskNotifyFromISR(s_task_handle, NOTIFY_USB_CONFIGURED_BIT, eSetBits, &HPTaskAwoken); + if (HPTaskAwoken == pdTRUE) { + portYIELD_FROM_ISR(); + } + break; + } + case USBD_EVENT_SET_REMOTE_WAKEUP: + break; + case USBD_EVENT_CLR_REMOTE_WAKEUP: + break; + + default: + break; + } +} + +static void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + ESP_EARLY_LOGI(TAG, "ep 0x%02X actual out len:%d", ep, nbytes); + BaseType_t HPTaskAwoken = pdFALSE; + for (size_t i = 0; i < CDC_ACM_CHANNEL_NUM; i++) { + ep_status_t *ep_status = &s_ep_status[i]; + if (ep_status->rx_addr == ep) { + if (nbytes > 0) { + if (ep_status->write_len == 0) { + memcpy(write_buffer[i], read_buffer[i], nbytes); + ep_status->write_len = nbytes; + usbd_ep_start_read(0, ep, read_buffer[i], sizeof(read_buffer[0])); + } else { + ep_status->read_len = nbytes; + ep_status->rx_busy_flag = false; + } + xTaskNotifyFromISR(s_task_handle, NOTIFY_EP_BIT, eSetBits, &HPTaskAwoken); + } else { + usbd_ep_start_read(0, ep_status->rx_addr, read_buffer[i], sizeof(read_buffer[i])); + } + break; + } + } + if (HPTaskAwoken == pdTRUE) { + portYIELD_FROM_ISR(); + } +} + +static void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + BaseType_t HPTaskAwoken = pdFALSE; + ESP_EARLY_LOGI(TAG, "ep 0x%02X actual in len:%d", ep, nbytes); + if ((nbytes % CDC_MAX_MPS) == 0 && nbytes) { + usbd_ep_start_write(0, ep, NULL, 0); + } else { + for (size_t i = 0; i < CDC_ACM_CHANNEL_NUM; i++) { + ep_status_t *ep_status = &s_ep_status[i]; + if (ep_status->tx_addr == ep) { + ep_status->write_len = 0; + ep_status->tx_busy_flag = false; + xTaskNotifyFromISR(s_task_handle, NOTIFY_EP_BIT, eSetBits, &HPTaskAwoken); + break; + } + } + } + if (HPTaskAwoken == pdTRUE) { + portYIELD_FROM_ISR(); + } +} + +struct usbd_endpoint cdc_out_ep = { + .ep_addr = CDC_OUT_EP, + .ep_cb = usbd_cdc_acm_bulk_out +}; + +struct usbd_endpoint cdc_in_ep = { + .ep_addr = CDC_IN_EP, + .ep_cb = usbd_cdc_acm_bulk_in +}; + +struct usbd_interface intf0; +struct usbd_interface intf1; + +#ifdef CONFIG_EXAMPLE_CHERRYUSB_CDC_ACM_TWO_CHANNEL +struct usbd_endpoint cdc_out_ep1 = { + .ep_addr = CDC_OUT_EP1, + .ep_cb = usbd_cdc_acm_bulk_out +}; + +struct usbd_endpoint cdc_in_ep1 = { + .ep_addr = CDC_IN_EP1, + .ep_cb = usbd_cdc_acm_bulk_in +}; + +struct usbd_interface intf2; +struct usbd_interface intf3; +#endif + +static void cdc_acm_init(void) +{ +#ifdef CONFIG_USBDEV_ADVANCE_DESC + usbd_desc_register(0, &cdc_descriptor); +#else + usbd_desc_register(0, cdc_descriptor); +#endif + usbd_add_interface(0, usbd_cdc_acm_init_intf(0, &intf0)); + usbd_add_interface(0, usbd_cdc_acm_init_intf(0, &intf1)); + usbd_add_endpoint(0, &cdc_out_ep); + usbd_add_endpoint(0, &cdc_in_ep); +#ifdef CONFIG_EXAMPLE_CHERRYUSB_CDC_ACM_TWO_CHANNEL + usbd_add_interface(0, usbd_cdc_acm_init_intf(0, &intf2)); + usbd_add_interface(0, usbd_cdc_acm_init_intf(0, &intf3)); + usbd_add_endpoint(0, &cdc_out_ep1); + usbd_add_endpoint(0, &cdc_in_ep1); +#endif + usbd_initialize(0, ESP_USBD_BASE, usbd_event_handler); +} + +void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr) +{ + ESP_EARLY_LOGI(TAG, "intf:%u, dtr:%d", intf, dtr); +} + +void usbd_cdc_acm_set_rts(uint8_t busid, uint8_t intf, bool rts) +{ + ESP_EARLY_LOGI(TAG, "intf:%u, rts:%d", intf, rts); +} + +void cdc_acm_task(void *arg) +{ + uint32_t notify_value = 0; + ESP_LOGI(TAG, "usb cdc acm task start"); + // Initialize the USB driver and CDC interface + cdc_acm_init(); + ESP_LOGI(TAG, "usb cdc acm init done"); + + while (1) { + xTaskNotifyWait(0, 0xFFFFFFFF, ¬ify_value, portMAX_DELAY); + if (notify_value & NOTIFY_EXIT_BIT) { + break; + } + if (notify_value & NOTIFY_USB_CONFIGURED_BIT) { + /* setup first out ep read transfer */ + for (size_t i = 0; i < sizeof(s_ep_status) / sizeof(s_ep_status[0]); i++) { + ep_status_t *ep_status = &s_ep_status[i]; + ep_status->write_len = 0; + ep_status->tx_busy_flag = false; + + ep_status->read_len = 0; + ep_status->rx_busy_flag = true; + usbd_ep_start_read(0, ep_status->rx_addr, read_buffer[i], sizeof(read_buffer[0])); + } + } + for (size_t i = 0; i < sizeof(s_ep_status) / sizeof(s_ep_status[0]); i++) { + ep_status_t *ep_status = &s_ep_status[i]; + if (ep_status->tx_busy_flag == false) { + if (ep_status->write_len == 0 && ep_status->read_len > 0) { + memcpy(&write_buffer[i][0], &read_buffer[i][0], ep_status->read_len); + ep_status->write_len = ep_status->read_len; + ep_status->read_len = 0; + } + if (ep_status->write_len > 0) { + ep_status->tx_busy_flag = true; + usbd_ep_start_write(0, ep_status->tx_addr, write_buffer[i], ep_status->write_len); + } + } + if (ep_status->rx_busy_flag == false) { + if (ep_status->read_len == 0) { + ep_status->rx_busy_flag = true; + usbd_ep_start_read(0, ep_status->rx_addr, read_buffer[i], sizeof(read_buffer[i])); + } + } + } + } + + usbd_deinitialize(0); + ESP_LOGW(TAG, "task exit"); + s_task_handle = NULL; + vTaskDelete(NULL); +} + +void app_main(void) +{ +#if EXAMPLE_CHERRYUSB_INIT_DEINIT_LOOP +reinit : +#endif + + xTaskCreatePinnedToCore(&cdc_acm_task, "cdc_acm_task", 1024 * 3, NULL, 10, &s_task_handle, 0); + +#if EXAMPLE_CHERRYUSB_INIT_DEINIT_LOOP + for (int i = 10; i >= 0; i--) { + ESP_LOGW(TAG, "Deinit usb after %d seconds...", i); + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + ESP_LOGW(TAG, "Notify deinit usb"); + xTaskNotify(s_task_handle, NOTIFY_EXIT_BIT, eSetBits); + while (s_task_handle) { + vTaskDelay(100 / portTICK_PERIOD_MS); + } + goto reinit; +#endif + +} diff --git a/examples/peripherals/usb/device/cherryusb_serial_device/main/idf_component.yml b/examples/peripherals/usb/device/cherryusb_serial_device/main/idf_component.yml new file mode 100644 index 0000000000..8a39822972 --- /dev/null +++ b/examples/peripherals/usb/device/cherryusb_serial_device/main/idf_component.yml @@ -0,0 +1,3 @@ +## IDF Component Manager Manifest File +dependencies: + cherry-embedded/cherryusb: ~=1.5.0~4 diff --git a/examples/peripherals/usb/device/cherryusb_serial_device/sdkconfig.defaults b/examples/peripherals/usb/device/cherryusb_serial_device/sdkconfig.defaults new file mode 100644 index 0000000000..b239994c16 --- /dev/null +++ b/examples/peripherals/usb/device/cherryusb_serial_device/sdkconfig.defaults @@ -0,0 +1,4 @@ +CONFIG_CHERRYUSB=y +CONFIG_CHERRYUSB_DEVICE=y +CONFIG_CHERRYUSB_DEVICE_DWC2_ESP=y +CONFIG_CHERRYUSB_DEVICE_CDC_ACM=y