mirror of
https://github.com/espressif/esp-idf.git
synced 2025-10-03 10:30:58 +02:00
feat(examples/peripherals/usb/cherryusb/device/cherryusb_serial_device): add CherryUSB serial device example
This commit is contained in:
@@ -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)
|
@@ -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
|
||||||
|
```
|
@@ -0,0 +1,3 @@
|
|||||||
|
idf_component_register(SRCS "device_cdc_main.c"
|
||||||
|
INCLUDE_DIRS "."
|
||||||
|
)
|
@@ -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
|
@@ -0,0 +1,444 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#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
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,3 @@
|
|||||||
|
## IDF Component Manager Manifest File
|
||||||
|
dependencies:
|
||||||
|
cherry-embedded/cherryusb: ~=1.5.0~4
|
@@ -0,0 +1,4 @@
|
|||||||
|
CONFIG_CHERRYUSB=y
|
||||||
|
CONFIG_CHERRYUSB_DEVICE=y
|
||||||
|
CONFIG_CHERRYUSB_DEVICE_DWC2_ESP=y
|
||||||
|
CONFIG_CHERRYUSB_DEVICE_CDC_ACM=y
|
Reference in New Issue
Block a user