feat(usb): add CherryUSB support for multiple USB controllers selection

This commit is contained in:
LiPeng
2025-07-28 11:33:10 +08:00
committed by Li Peng
parent 0ac445cbd6
commit 8f9eeedae1
9 changed files with 111 additions and 22 deletions

View File

@@ -1,5 +1,23 @@
menu "Example Configuration"
choice EXAMPLE_USB_DEVICE_RHPORT
prompt "USB Device Peripheral"
default EXAMPLE_USB_DEVICE_RHPORT_HS if IDF_TARGET_ESP32P4
default EXAMPLE_USB_DEVICE_RHPORT_FS
help
Allows set the USB Peripheral Controller for USB device.
- High-speed (USB OTG2.0 Peripheral for High-, Full- and Low-speed)
- Full-speed (USB OTG1.1 Peripheral for Full- and Low-speed)
config EXAMPLE_USB_DEVICE_RHPORT_HS
bool "OTG2.0"
depends on IDF_TARGET_ESP32P4
config EXAMPLE_USB_DEVICE_RHPORT_FS
bool "OTG1.1"
endchoice
config EXAMPLE_CHERRYUSB_CDC_ACM_TWO_CHANNEL
bool "Enable usb cdc acm two channel"
default n

View File

@@ -46,10 +46,13 @@ static TaskHandle_t s_task_handle = NULL;
/*!< config descriptor size */
#define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN * 4)
#define CDC_FS_MAX_MPS 64
#define CDC_HS_MAX_MPS 512
#ifdef CONFIG_USB_HS
#define CDC_MAX_MPS 512
#define CDC_MAX_MPS CDC_HS_MAX_MPS
#else
#define CDC_MAX_MPS 64
#define CDC_MAX_MPS CDC_FS_MAX_MPS
#endif
typedef struct {
@@ -68,27 +71,43 @@ static ep_status_t s_ep_status[CDC_ACM_CHANNEL_NUM] = {
#endif
};
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#define WRITE_BUFFER_SIZE ALIGN_UP(ALIGN_UP(2048, CDC_MAX_MPS), CONFIG_USB_ALIGN_SIZE)
#if CONFIG_EXAMPLE_CHERRYUSB_SET_READ_BUFFER_SIZE_MPS
#define READ_BUFFER_SIZE CDC_MAX_MPS
#define READ_BUFFER_SIZE ALIGN_UP(CDC_MAX_MPS, CONFIG_USB_ALIGN_SIZE)
#else
#define READ_BUFFER_SIZE 2048
#define READ_BUFFER_SIZE WRITE_BUFFER_SIZE
#endif
static uint32_t s_mps = CDC_MAX_MPS;
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];
static DRAM_DMA_ALIGNED_ATTR uint8_t write_buffer[CDC_ACM_CHANNEL_NUM][WRITE_BUFFER_SIZE];
#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[] = {
static const uint8_t config_descriptor_fs[] = {
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),
CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_FS_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),
CDC_ACM_DESCRIPTOR_INIT(0x02, CDC_INT_EP1, CDC_OUT_EP1, CDC_IN_EP1, CDC_FS_MAX_MPS, 0x02),
#endif
};
#ifdef CONFIG_USB_HS
static const uint8_t config_descriptor_hs[] = {
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_HS_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_HS_MAX_MPS, 0x02),
#endif
};
#endif
static const uint8_t device_quality_descriptor[] = {
///////////////////////////////////////
/// device qualifier descriptor
@@ -122,7 +141,14 @@ static const uint8_t *device_descriptor_callback(uint8_t speed)
static const uint8_t *config_descriptor_callback(uint8_t speed)
{
return config_descriptor;
#ifdef CONFIG_USB_HS
if (speed >= USB_SPEED_HIGH) {
s_mps = CDC_HS_MAX_MPS;
return config_descriptor_hs;
}
s_mps = CDC_FS_MAX_MPS;
#endif
return config_descriptor_fs;
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
@@ -270,14 +296,22 @@ static void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
if (ep_status->write_len == 0) {
memcpy(write_buffer[i], read_buffer[i], nbytes);
ep_status->write_len = nbytes;
#if CONFIG_EXAMPLE_CHERRYUSB_SET_READ_BUFFER_SIZE_MPS
usbd_ep_start_read(0, ep, read_buffer[i], s_mps);
#else
usbd_ep_start_read(0, ep, read_buffer[i], sizeof(read_buffer[0]));
#endif
} 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]));
#if CONFIG_EXAMPLE_CHERRYUSB_SET_READ_BUFFER_SIZE_MPS
usbd_ep_start_read(0, ep, read_buffer[i], s_mps);
#else
usbd_ep_start_read(0, ep, read_buffer[i], sizeof(read_buffer[i]));
#endif
}
break;
}
@@ -291,7 +325,7 @@ 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) {
if ((nbytes % s_mps) == 0 && nbytes) {
usbd_ep_start_write(0, ep, NULL, 0);
} else {
for (size_t i = 0; i < CDC_ACM_CHANNEL_NUM; i++) {
@@ -354,7 +388,12 @@ static void cdc_acm_init(void)
usbd_add_endpoint(0, &cdc_out_ep1);
usbd_add_endpoint(0, &cdc_in_ep1);
#endif
usbd_initialize(0, ESP_USBD_BASE, usbd_event_handler);
#if CONFIG_EXAMPLE_USB_DEVICE_RHPORT_HS
usbd_initialize(0, ESP_USB_HS0_BASE, usbd_event_handler);
#else
usbd_initialize(0, ESP_USB_FS0_BASE, usbd_event_handler);
#endif
}
void usbd_cdc_acm_set_dtr(uint8_t busid, uint8_t intf, bool dtr)
@@ -389,7 +428,11 @@ void cdc_acm_task(void *arg)
ep_status->read_len = 0;
ep_status->rx_busy_flag = true;
#if CONFIG_EXAMPLE_CHERRYUSB_SET_READ_BUFFER_SIZE_MPS
usbd_ep_start_read(0, ep_status->rx_addr, read_buffer[i], s_mps);
#else
usbd_ep_start_read(0, ep_status->rx_addr, read_buffer[i], sizeof(read_buffer[0]));
#endif
}
}
for (size_t i = 0; i < sizeof(s_ep_status) / sizeof(s_ep_status[0]); i++) {
@@ -408,7 +451,11 @@ void cdc_acm_task(void *arg)
if (ep_status->rx_busy_flag == false) {
if (ep_status->read_len == 0) {
ep_status->rx_busy_flag = true;
#if CONFIG_EXAMPLE_CHERRYUSB_SET_READ_BUFFER_SIZE_MPS
usbd_ep_start_read(0, ep_status->rx_addr, read_buffer[i], s_mps);
#else
usbd_ep_start_read(0, ep_status->rx_addr, read_buffer[i], sizeof(read_buffer[i]));
#endif
}
}
}

View File

@@ -1,3 +1,3 @@
## IDF Component Manager Manifest File
dependencies:
cherry-embedded/cherryusb: ~=1.5.0~4
cherry-embedded/cherryusb: ~=1.5.1~8

View File

@@ -9,8 +9,8 @@ This example demonstrates how to use the CherryUSB host driver. Currently, this
## How to use example
If you need to enable support for FTDI, please enable the following configuration
Run `idf.py menuconfig` and in `Component config → CherryUSB Configuration → Enable usb host mode → Enable usb ftdi driver` enable.
By default, all drivers supported by the routine are enabled. If you need to trim or disable unnecessary drivers, please disable the corresponding driver configuration.
Run `idf.py menuconfig` and in `Component config → CherryUSB Configuration → Enable usb host mode`, Uncheck the drivers you dont need.
### Hardware Required
* Development board with USB-OTG support

View File

@@ -1,5 +1,23 @@
menu "Example Configuration"
choice EXAMPLE_USB_HOST_RHPORT
prompt "USB Host Peripheral"
default EXAMPLE_USB_HOST_RHPORT_HS if IDF_TARGET_ESP32P4
default EXAMPLE_USB_HOST_RHPORT_FS
help
Allows set the USB Peripheral Controller for USB host.
- High-speed (USB OTG2.0 Peripheral for High-, Full- and Low-speed)
- Full-speed (USB OTG1.1 Peripheral for Full- and Low-speed)
config EXAMPLE_USB_HOST_RHPORT_HS
bool "OTG2.0"
depends on IDF_TARGET_ESP32P4
config EXAMPLE_USB_HOST_RHPORT_FS
bool "OTG1.1"
endchoice
config EXAMPLE_HAL_USE_ESP32_S3_USB_OTG
bool "Use dev kit ESP32-S3-USB-OTG"
depends on IDF_TARGET_ESP32S3

View File

@@ -346,8 +346,9 @@ static void usbh_hid_callback(void *arg, int nbytes)
{
struct usbh_hid *hid_class = (struct usbh_hid *)arg;
hid_int_in_t *hid_intin = (hid_int_in_t *)hid_class->user_data;
hid_intin->is_active = false;
if (nbytes <= 0) {
hid_intin->is_active = false;
return;
}
uint8_t sub_class = hid_class->hport->config.intf[hid_class->intf].altsetting[0].intf_desc.bInterfaceSubClass;
@@ -362,6 +363,7 @@ static void usbh_hid_callback(void *arg, int nbytes)
}
}
complete_cb(hid_intin->buffer, nbytes);
hid_intin->is_active = false;
}
static void intin_timer_cb(void *arg)
@@ -437,11 +439,8 @@ void usbh_hid_run(struct usbh_hid *hid_class)
hid_class->user_data = hid_intin;
//周期间隔低速、全速单位为1ms高速和超高速是125us
ret = USBH_GET_URB_INTERVAL(hid_class->intin->bInterval, hid_class->hport->speed);
ret = (hid_class->hport->speed < USB_SPEED_HIGH) ? (ret * 1000) : (ret * 125);
esp_timer_start_periodic(hid_intin->timer, USBH_GET_URB_INTERVAL(hid_class->intin->bInterval, hid_class->hport->speed));
esp_timer_start_periodic(hid_intin->timer, ret);
return;
error:
if (hid_intin->buffer) {

View File

@@ -1,3 +1,3 @@
## IDF Component Manager Manifest File
dependencies:
cherry-embedded/cherryusb: ~=1.5.0~4
cherry-embedded/cherryusb: ~=1.5.1~8

View File

@@ -43,7 +43,13 @@ void app_main(void)
#if CONFIG_EXAMPLE_CHERRYUSB_INIT_DEINIT_LOOP
reinit:
#endif
usbh_initialize(0, ESP_USBH_BASE);
#if CONFIG_EXAMPLE_USB_HOST_RHPORT_HS
usbh_initialize(0, ESP_USB_HS0_BASE);
#else
usbh_initialize(0, ESP_USB_FS0_BASE);
#endif
ESP_LOGI(TAG, "Init usb");
#if CONFIG_EXAMPLE_CHERRYUSB_INIT_DEINIT_LOOP

View File

@@ -10,6 +10,7 @@ CONFIG_CHERRYUSB_HOST_DWC2_ESP=y
CONFIG_CHERRYUSB_HOST_CDC_ACM=y
CONFIG_CHERRYUSB_HOST_HID=y
CONFIG_CHERRYUSB_HOST_MSC=y
CONFIG_CHERRYUSB_HOST_FTDI=y
CONFIG_CHERRYUSB_HOST_CH34X=y
CONFIG_CHERRYUSB_HOST_CP210X=y
CONFIG_CHERRYUSB_HOST_PL2303=y