Skip to content

Commit 8c67fdc

Browse files
committed
feat: Add support for communication via CP210x and CH34x serial converters
Extends USB serial flashing beyond CDC ACM to support CP210x (Silicon Labs) and CH34x (WinChipHead) serial converters, enabling flashing through most common USB-to-serial bridge chips.
1 parent ba7fd5c commit 8c67fdc

File tree

4 files changed

+73
-30
lines changed

4 files changed

+73
-30
lines changed

examples/esp32_usb_cdc_acm_example/main/main.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@
2020
#include "usb/usb_host.h"
2121
#include "usb/cdc_acm_host.h"
2222

23-
#define ESPRESSIF_VID 0x303a
24-
#define ESP_SERIAL_JTAG_PID 0x1001
25-
2623
static const char *TAG = "usb_flasher";
2724
static SemaphoreHandle_t device_disconnected_sem;
2825

@@ -81,8 +78,8 @@ void app_main(void)
8178

8279
while (true) {
8380
const loader_esp32_usb_cdc_acm_config_t config = {
84-
.device_vid = ESPRESSIF_VID,
85-
.device_pid = ESP_SERIAL_JTAG_PID,
81+
.device_vid = USB_VID_PID_AUTO_DETECT,
82+
.device_pid = USB_VID_PID_AUTO_DETECT,
8683
.connection_timeout_ms = 1000,
8784
.out_buffer_size = 4096,
8885
.device_disconnected_callback = device_disconnected_callback,

idf_component.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,13 @@ dependencies:
88
rules:
99
- if: "idf_version >=4.4"
1010
- if: "target in [esp32s2, esp32s3, esp32p4]"
11+
usb_host_cp210x_vcp:
12+
version: "^2.2"
13+
rules:
14+
- if: "idf_version >=4.4"
15+
- if: "target in [esp32s2, esp32s3, esp32p4]"
16+
usb_host_ch34x_vcp:
17+
version: "^2.2"
18+
rules:
19+
- if: "idf_version >=4.4"
20+
- if: "target in [esp32s2, esp32s3, esp32p4]"

port/esp32_usb_cdc_acm_port.c

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
#include <stdio.h>
1818
#include "esp_log.h"
1919
#include "esp_timer.h"
20+
#include "usb/cdc_acm_host.h"
21+
#include "usb/vcp_cp210x.h"
22+
#include "usb/vcp_ch34x.h"
23+
#include "esp_loader_io.h"
2024
#include "esp32_usb_cdc_acm_port.h"
2125

22-
#define ESP_SERIAL_JTAG_PID 0x1001
23-
2426
static const char *TAG = "usb_cdc_acm_port";
2527

2628
static cdc_acm_dev_hdl_t s_acm_device;
@@ -104,18 +106,18 @@ static void usb_serial_jtag_enter_booloader(void)
104106
static void usb_serial_converter_reset_target(void)
105107
{
106108
xStreamBufferReset(s_rx_stream_buffer);
107-
cdc_acm_host_set_control_line_state(s_acm_device, true, true);
109+
cdc_acm_host_set_control_line_state(s_acm_device, false, true);
108110
loader_port_delay_ms(SERIAL_FLASHER_RESET_HOLD_TIME_MS);
109-
cdc_acm_host_set_control_line_state(s_acm_device, true, false);
111+
cdc_acm_host_set_control_line_state(s_acm_device, false, false);
110112
}
111113

112114
static void usb_serial_converter_enter_bootloader(void)
113115
{
114-
cdc_acm_host_set_control_line_state(s_acm_device, true, false);
115-
116-
usb_serial_converter_reset_target();
117-
116+
xStreamBufferReset(s_rx_stream_buffer);
117+
cdc_acm_host_set_control_line_state(s_acm_device, false, true);
118118
loader_port_delay_ms(SERIAL_FLASHER_BOOT_HOLD_TIME_MS);
119+
cdc_acm_host_set_control_line_state(s_acm_device, true, false);
120+
loader_port_delay_ms(SERIAL_FLASHER_RESET_HOLD_TIME_MS);
119121
cdc_acm_host_set_control_line_state(s_acm_device, false, false);
120122
}
121123

@@ -169,11 +171,6 @@ esp_loader_error_t loader_port_esp32_usb_cdc_acm_init(const loader_esp32_usb_cdc
169171
s_device_disconnected_callback = config->device_disconnected_callback;
170172
s_acm_host_serial_state_callback = config->acm_host_serial_state_callback;
171173

172-
/* Different reset and enter bootloader sequences are needed depending on whether the target
173-
* device is connected via internal USB Serial/JTAG or an USB to serial converter which
174-
* connects to target UART and BOOT/RST pins. See pages 1207 and 1208 of the ESP32-S3 TRM */
175-
s_is_usb_serial_jtag = config->device_pid == ESP_SERIAL_JTAG_PID;
176-
177174
s_rx_stream_buffer = xStreamBufferCreate(1024, 1);
178175

179176
if (s_rx_stream_buffer == NULL) {
@@ -189,20 +186,42 @@ esp_loader_error_t loader_port_esp32_usb_cdc_acm_init(const loader_esp32_usb_cdc
189186
.data_cb = handle_usb_data
190187
};
191188

192-
esp_err_t err = cdc_acm_host_open(config->device_vid,
193-
config->device_pid,
194-
0,
195-
&dev_config,
196-
&s_acm_device);
189+
const bool auto_detect = (config->device_vid == USB_VID_PID_AUTO_DETECT ||
190+
config->device_pid == USB_VID_PID_AUTO_DETECT);
197191

198-
if (err != ESP_OK) {
199-
ESP_LOGE(TAG, "Failed to open the USB device");
200-
esp_loader_error_t deinit_status = loader_port_esp32_usb_cdc_acm_deinit();
201-
assert(deinit_status == ESP_LOADER_SUCCESS);
202-
return ESP_LOADER_ERROR_FAIL;
192+
if (auto_detect) {
193+
if (cdc_acm_host_open(ESPRESSIF_VID, ESP_SERIAL_JTAG_PID, 0, &dev_config, &s_acm_device) == ESP_OK) {
194+
s_is_usb_serial_jtag = true;
195+
return ESP_LOADER_SUCCESS;
196+
}
197+
if (cp210x_vcp_open(CP210X_PID_AUTO, 0, &dev_config, &s_acm_device) == ESP_OK) {
198+
s_is_usb_serial_jtag = false;
199+
return ESP_LOADER_SUCCESS;
200+
}
201+
if (ch34x_vcp_open(CH34X_PID_AUTO, 0, &dev_config, &s_acm_device) == ESP_OK) {
202+
s_is_usb_serial_jtag = false;
203+
return ESP_LOADER_SUCCESS;
204+
}
205+
} else {
206+
esp_err_t err;
207+
if (config->device_vid == SILICON_LABS_VID) {
208+
err = cp210x_vcp_open(config->device_pid, 0, &dev_config, &s_acm_device);
209+
} else if (config->device_vid == NANJING_QINHENG_MICROE_VID) {
210+
err = ch34x_vcp_open(config->device_pid, 0, &dev_config, &s_acm_device);
211+
} else {
212+
err = cdc_acm_host_open(config->device_vid, config->device_pid, 0, &dev_config, &s_acm_device);
213+
}
214+
215+
if (err == ESP_OK) {
216+
s_is_usb_serial_jtag = (config->device_vid == ESPRESSIF_VID);
217+
return ESP_LOADER_SUCCESS;
218+
}
203219
}
204220

205-
return ESP_LOADER_SUCCESS;
221+
ESP_LOGE(TAG, "Failed to open any USB device");
222+
esp_loader_error_t deinit_status = loader_port_esp32_usb_cdc_acm_deinit();
223+
assert(deinit_status == ESP_LOADER_SUCCESS);
224+
return ESP_LOADER_ERROR_FAIL;
206225
}
207226

208227

port/esp32_usb_cdc_acm_port.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
#pragma once
1717

18-
#include "esp_loader_io.h"
18+
#include "esp_loader.h"
1919
#include "usb/usb_host.h"
2020
#include "usb/cdc_acm_host.h"
2121
#include "freertos/stream_buffer.h"
@@ -24,6 +24,23 @@
2424
extern "C" {
2525
#endif
2626

27+
#define USB_VID_PID_AUTO_DETECT (0) // Use for VID/PID in config to enable auto-detection
28+
29+
#define ESPRESSIF_VID (0x303a)
30+
#define ESP_SERIAL_JTAG_PID (0x1001)
31+
32+
// VID and PID definitions from esp-usb library, only these are supported
33+
#define SILICON_LABS_VID (0x10C4) // Silicon Labs
34+
#define CP210X_PID (0xEA60) // Single i.e. CP2101 - CP2104
35+
#define CP2105_PID (0xEA70) // Dual
36+
#define CP2108_PID (0xEA71) // Quad
37+
38+
#define NANJING_QINHENG_MICROE_VID (0x1A86) // Nanjing Qinheng Microelectronics
39+
#define CH340_PID (0x7522)
40+
#define CH340_PID_1 (0x7523)
41+
#define CH341_PID (0x5523)
42+
43+
2744
typedef void (*loader_port_esp32_usb_cdc_acm_callback_t) (void);
2845

2946
typedef struct {

0 commit comments

Comments
 (0)