Skip to content

Commit 0d3eec5

Browse files
pi-anlwiznet-grace
authored andcommitted
esp32: Use shared/tinyusb integration for S2 and S3 USB.
Uses newer TinyUSB synopsys/dwc2 driver for esp32s2 and esp32s3 rather than the IDF tinyusb component. This allows re-use of other tinyusb integration code and features shared between ports. Signed-off-by: Andrew Leech <[email protected]>
1 parent a9f1de2 commit 0d3eec5

File tree

9 files changed

+156
-81
lines changed

9 files changed

+156
-81
lines changed

ports/esp32/esp32_common.cmake

+40
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,37 @@ list(APPEND MICROPY_SOURCE_DRIVERS
5353
${MICROPY_DIR}/drivers/dht/dht.c
5454
)
5555

56+
string(CONCAT GIT_SUBMODULES "${GIT_SUBMODULES} " lib/tinyusb)
57+
if(MICROPY_PY_TINYUSB)
58+
set(TINYUSB_SRC "${MICROPY_DIR}/lib/tinyusb/src")
59+
string(TOUPPER OPT_MCU_${IDF_TARGET} tusb_mcu)
60+
61+
list(APPEND MICROPY_DEF_TINYUSB
62+
CFG_TUSB_MCU=${tusb_mcu}
63+
)
64+
65+
list(APPEND MICROPY_SOURCE_TINYUSB
66+
${TINYUSB_SRC}/tusb.c
67+
${TINYUSB_SRC}/common/tusb_fifo.c
68+
${TINYUSB_SRC}/device/usbd.c
69+
${TINYUSB_SRC}/device/usbd_control.c
70+
${TINYUSB_SRC}/class/cdc/cdc_device.c
71+
${TINYUSB_SRC}/portable/synopsys/dwc2/dcd_dwc2.c
72+
${MICROPY_DIR}/shared/tinyusb/mp_usbd.c
73+
${MICROPY_DIR}/shared/tinyusb/mp_usbd_cdc.c
74+
${MICROPY_DIR}/shared/tinyusb/mp_usbd_descriptor.c
75+
)
76+
77+
list(APPEND MICROPY_INC_TINYUSB
78+
${TINYUSB_SRC}
79+
${MICROPY_DIR}/shared/tinyusb/
80+
)
81+
82+
list(APPEND MICROPY_LINK_TINYUSB
83+
-Wl,--wrap=dcd_event_handler
84+
)
85+
endif()
86+
5687
list(APPEND MICROPY_SOURCE_PORT
5788
panichandler.c
5889
adc.c
@@ -100,6 +131,7 @@ list(APPEND MICROPY_SOURCE_QSTR
100131
${MICROPY_SOURCE_LIB}
101132
${MICROPY_SOURCE_PORT}
102133
${MICROPY_SOURCE_BOARD}
134+
${MICROPY_SOURCE_TINYUSB}
103135
)
104136

105137
list(APPEND IDF_COMPONENTS
@@ -134,6 +166,7 @@ list(APPEND IDF_COMPONENTS
134166
soc
135167
spi_flash
136168
ulp
169+
usb
137170
vfs
138171
)
139172

@@ -147,9 +180,11 @@ idf_component_register(
147180
${MICROPY_SOURCE_DRIVERS}
148181
${MICROPY_SOURCE_PORT}
149182
${MICROPY_SOURCE_BOARD}
183+
${MICROPY_SOURCE_TINYUSB}
150184
INCLUDE_DIRS
151185
${MICROPY_INC_CORE}
152186
${MICROPY_INC_USERMOD}
187+
${MICROPY_INC_TINYUSB}
153188
${MICROPY_PORT_DIR}
154189
${MICROPY_BOARD_DIR}
155190
${CMAKE_BINARY_DIR}
@@ -171,6 +206,7 @@ endif()
171206
target_compile_definitions(${MICROPY_TARGET} PUBLIC
172207
${MICROPY_DEF_CORE}
173208
${MICROPY_DEF_BOARD}
209+
${MICROPY_DEF_TINYUSB}
174210
MICROPY_ESP_IDF_4=1
175211
MICROPY_VFS_FAT=1
176212
MICROPY_VFS_LFS2=1
@@ -186,6 +222,10 @@ target_compile_options(${MICROPY_TARGET} PUBLIC
186222
-Wno-missing-field-initializers
187223
)
188224

225+
target_link_options(${MICROPY_TARGET} PUBLIC
226+
${MICROPY_LINK_TINYUSB}
227+
)
228+
189229
# Additional include directories needed for private NimBLE headers.
190230
target_include_directories(${MICROPY_TARGET} PUBLIC
191231
${IDF_PATH}/components/bt/host/nimble/nimble

ports/esp32/main.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include "shared/readline/readline.h"
5353
#include "shared/runtime/pyexec.h"
5454
#include "shared/timeutils/timeutils.h"
55+
#include "shared/tinyusb/mp_usbd.h"
5556
#include "mbedtls/platform_time.h"
5657

5758
#include "uart.h"
@@ -101,7 +102,7 @@ void mp_task(void *pvParameter) {
101102
#endif
102103
#if MICROPY_HW_ESP_USB_SERIAL_JTAG
103104
usb_serial_jtag_init();
104-
#elif MICROPY_HW_USB_CDC
105+
#elif MICROPY_HW_ENABLE_USBDEV
105106
usb_init();
106107
#endif
107108
#if MICROPY_HW_ENABLE_UART_REPL

ports/esp32/main_esp32s2/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ if(NOT MICROPY_PORT_DIR)
88
get_filename_component(MICROPY_PORT_DIR ${MICROPY_DIR}/ports/esp32 ABSOLUTE)
99
endif()
1010

11+
set(MICROPY_PY_TINYUSB ON)
12+
1113
include(${MICROPY_PORT_DIR}/esp32_common.cmake)

ports/esp32/main_esp32s3/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ if(NOT MICROPY_PORT_DIR)
88
get_filename_component(MICROPY_PORT_DIR ${MICROPY_DIR}/ports/esp32 ABSOLUTE)
99
endif()
1010

11+
set(MICROPY_PY_TINYUSB ON)
12+
1113
include(${MICROPY_PORT_DIR}/esp32_common.cmake)

ports/esp32/mpconfigport.h

+63-14
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,69 @@
194194

195195
#define MP_STATE_PORT MP_STATE_VM
196196

197+
#ifndef MICROPY_HW_ENABLE_USBDEV
198+
#define MICROPY_HW_ENABLE_USBDEV (SOC_USB_OTG_SUPPORTED)
199+
#endif
200+
201+
#if MICROPY_HW_ENABLE_USBDEV
202+
#define MICROPY_SCHEDULER_STATIC_NODES (1)
203+
204+
#ifndef MICROPY_HW_USB_VID
205+
#define USB_ESPRESSIF_VID 0x303A
206+
#if CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID
207+
#define MICROPY_HW_USB_VID (USB_ESPRESSIF_VID)
208+
#else
209+
#define MICROPY_HW_USB_VID (CONFIG_TINYUSB_DESC_CUSTOM_VID)
210+
#endif
211+
#endif
212+
213+
#ifndef MICROPY_HW_USB_PID
214+
#if CONFIG_TINYUSB_DESC_USE_DEFAULT_PID
215+
#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n))
216+
// A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
217+
// Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
218+
// Auto ProductID layout's Bitmap:
219+
// [MSB] HID | MSC | CDC [LSB]
220+
#define USB_TUSB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
221+
_PID_MAP(MIDI, 3)) // | _PID_MAP(AUDIO, 4) | _PID_MAP(VENDOR, 5) )
222+
#define MICROPY_HW_USB_PID (USB_TUSB_PID)
223+
#else
224+
#define MICROPY_HW_USB_PID (CONFIG_TINYUSB_DESC_CUSTOM_PID)
225+
#endif
226+
#endif
227+
228+
#ifndef MICROPY_HW_USB_MANUFACTURER_STRING
229+
#ifdef CONFIG_TINYUSB_DESC_MANUFACTURER_STRING
230+
#define MICROPY_HW_USB_MANUFACTURER_STRING CONFIG_TINYUSB_DESC_MANUFACTURER_STRING
231+
#else
232+
#define MICROPY_HW_USB_MANUFACTURER_STRING "MicroPython"
233+
#endif
234+
#endif
235+
236+
#ifndef MICROPY_HW_USB_PRODUCT_FS_STRING
237+
#ifdef CONFIG_TINYUSB_DESC_PRODUCT_STRING
238+
#define MICROPY_HW_USB_PRODUCT_FS_STRING CONFIG_TINYUSB_DESC_PRODUCT_STRING
239+
#else
240+
#define MICROPY_HW_USB_PRODUCT_FS_STRING "Board in FS mode"
241+
#endif
242+
#endif
243+
244+
#endif // MICROPY_HW_ENABLE_USBDEV
245+
246+
// Enable stdio over native USB peripheral CDC via TinyUSB
247+
#ifndef MICROPY_HW_USB_CDC
248+
#define MICROPY_HW_USB_CDC (MICROPY_HW_ENABLE_USBDEV)
249+
#endif
250+
251+
// Enable stdio over USB Serial/JTAG peripheral
252+
#ifndef MICROPY_HW_ESP_USB_SERIAL_JTAG
253+
#define MICROPY_HW_ESP_USB_SERIAL_JTAG (SOC_USB_SERIAL_JTAG_SUPPORTED && !MICROPY_HW_USB_CDC)
254+
#endif
255+
256+
#if MICROPY_HW_USB_CDC && MICROPY_HW_ESP_USB_SERIAL_JTAG
257+
#error "Invalid build config: Can't enable both native USB and USB Serial/JTAG peripheral"
258+
#endif
259+
197260
// type definitions for the specific machine
198261

199262
#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p)))
@@ -253,20 +316,6 @@ typedef long mp_off_t;
253316
// board specifics
254317
#define MICROPY_PY_SYS_PLATFORM "esp32"
255318

256-
// Enable stdio over native USB peripheral CDC via TinyUSB
257-
#ifndef MICROPY_HW_USB_CDC
258-
#define MICROPY_HW_USB_CDC (SOC_USB_OTG_SUPPORTED)
259-
#endif
260-
261-
// Enable stdio over USB Serial/JTAG peripheral
262-
#ifndef MICROPY_HW_ESP_USB_SERIAL_JTAG
263-
#define MICROPY_HW_ESP_USB_SERIAL_JTAG (SOC_USB_SERIAL_JTAG_SUPPORTED && !MICROPY_HW_USB_CDC)
264-
#endif
265-
266-
#if MICROPY_HW_USB_CDC && MICROPY_HW_ESP_USB_SERIAL_JTAG
267-
#error "Invalid build config: Can't enable both native USB and USB Serial/JTAG peripheral"
268-
#endif
269-
270319
// ESP32-S3 extended IO for 47 & 48
271320
#ifndef MICROPY_HW_ESP32S3_EXTENDED_IO
272321
#define MICROPY_HW_ESP32S3_EXTENDED_IO (1)

ports/esp32/mphalport.c

+22-5
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
#include "extmod/misc.h"
4343
#include "shared/timeutils/timeutils.h"
4444
#include "shared/runtime/pyexec.h"
45+
#include "shared/tinyusb/mp_usbd.h"
46+
#include "shared/tinyusb/mp_usbd_cdc.h"
4547
#include "mphalport.h"
4648
#include "usb.h"
4749
#include "usb_serial_jtag.h"
@@ -106,13 +108,19 @@ uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
106108
uintptr_t ret = 0;
107109
#if MICROPY_HW_ESP_USB_SERIAL_JTAG
108110
usb_serial_jtag_poll_rx();
109-
#endif
110-
if ((poll_flags & MP_STREAM_POLL_RD) && stdin_ringbuf.iget != stdin_ringbuf.iput) {
111+
if ((poll_flags & MP_STREAM_POLL_RD) && ringbuf_peek(&stdin_ringbuf) != -1) {
111112
ret |= MP_STREAM_POLL_RD;
112113
}
113114
if (poll_flags & MP_STREAM_POLL_WR) {
114115
ret |= MP_STREAM_POLL_WR;
115116
}
117+
#endif
118+
#if MICROPY_HW_USB_CDC
119+
ret |= mp_usbd_cdc_poll_interfaces(poll_flags);
120+
#endif
121+
#if MICROPY_PY_OS_DUPTERM
122+
ret |= mp_os_dupterm_poll(poll_flags);
123+
#endif
116124
return ret;
117125
}
118126

@@ -121,6 +129,9 @@ int mp_hal_stdin_rx_chr(void) {
121129
#if MICROPY_HW_ESP_USB_SERIAL_JTAG
122130
usb_serial_jtag_poll_rx();
123131
#endif
132+
#if MICROPY_HW_USB_CDC
133+
mp_usbd_cdc_poll_interfaces(0);
134+
#endif
124135
int c = ringbuf_get(&stdin_ringbuf);
125136
if (c != -1) {
126137
return c;
@@ -133,6 +144,7 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) {
133144
// Only release the GIL if many characters are being sent
134145
mp_uint_t ret = len;
135146
bool did_write = false;
147+
#if MICROPY_HW_ENABLE_UART_REPL || CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
136148
bool release_gil = len > MICROPY_PY_STRING_TX_GIL_THRESHOLD;
137149
#if MICROPY_DEBUG_PRINTERS && MICROPY_DEBUG_VERBOSE && MICROPY_PY_THREAD_GIL
138150
// If verbose debug output is enabled some strings are printed before the
@@ -146,9 +158,6 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) {
146158
#if MICROPY_HW_ESP_USB_SERIAL_JTAG
147159
usb_serial_jtag_tx_strn(str, len);
148160
did_write = true;
149-
#elif MICROPY_HW_USB_CDC
150-
usb_tx_strn(str, len);
151-
did_write = true;
152161
#endif
153162
#if MICROPY_HW_ENABLE_UART_REPL
154163
uart_stdout_tx_strn(str, len);
@@ -157,6 +166,14 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) {
157166
if (release_gil) {
158167
MP_THREAD_GIL_ENTER();
159168
}
169+
#endif // MICROPY_HW_ENABLE_UART_REPL || CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED
170+
#if MICROPY_HW_USB_CDC
171+
mp_uint_t cdc_res = mp_usbd_cdc_tx_strn(str, len);
172+
if (cdc_res > 0) {
173+
did_write = true;
174+
ret = MIN(cdc_res, ret);
175+
}
176+
#endif
160177
int dupterm_res = mp_os_dupterm_tx_strn(str, len);
161178
if (dupterm_res >= 0) {
162179
did_write = true;

ports/esp32/usb.c

+24-59
Original file line numberDiff line numberDiff line change
@@ -29,75 +29,40 @@
2929
#include "usb.h"
3030

3131
#if MICROPY_HW_USB_CDC
32+
#include "esp_rom_gpio.h"
33+
#include "esp_mac.h"
34+
#include "esp_private/usb_phy.h"
3235

33-
#include "esp_timer.h"
34-
#ifndef NO_QSTR
35-
#include "tinyusb.h"
36-
#include "tusb_cdc_acm.h"
37-
#endif
36+
#include "shared/tinyusb/mp_usbd.h"
3837

39-
#define CDC_ITF TINYUSB_CDC_ACM_0
38+
static usb_phy_handle_t phy_hdl;
4039

41-
static uint8_t usb_rx_buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE];
42-
43-
// This is called from FreeRTOS task "tusb_tsk" in espressif__esp_tinyusb (not an ISR).
44-
static void usb_callback_rx(int itf, cdcacm_event_t *event) {
45-
// espressif__esp_tinyusb places tinyusb rx data onto freertos ringbuffer which
46-
// this function forwards onto our stdin_ringbuf.
47-
for (;;) {
48-
size_t len = 0;
49-
esp_err_t ret = tinyusb_cdcacm_read(itf, usb_rx_buf, sizeof(usb_rx_buf), &len);
50-
if (ret != ESP_OK) {
51-
break;
52-
}
53-
if (len == 0) {
54-
break;
55-
}
56-
for (size_t i = 0; i < len; ++i) {
57-
if (usb_rx_buf[i] == mp_interrupt_char) {
58-
mp_sched_keyboard_interrupt();
59-
} else {
60-
ringbuf_put(&stdin_ringbuf, usb_rx_buf[i]);
61-
}
62-
}
63-
mp_hal_wake_main_task();
64-
}
65-
}
6640

6741
void usb_init(void) {
68-
// Initialise the USB with defaults.
69-
tinyusb_config_t tusb_cfg = {0};
70-
ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg));
42+
// ref: https://github.com/espressif/esp-usb/blob/4b6a798d0bed444fff48147c8dcdbbd038e92892/device/esp_tinyusb/tinyusb.c
7143

72-
// Initialise the USB serial interface.
73-
tinyusb_config_cdcacm_t acm_cfg = {
74-
.usb_dev = TINYUSB_USBDEV_0,
75-
.cdc_port = CDC_ITF,
76-
.rx_unread_buf_sz = 256,
77-
.callback_rx = &usb_callback_rx,
78-
#ifdef MICROPY_HW_USB_CUSTOM_RX_WANTED_CHAR_CB
79-
.callback_rx_wanted_char = &MICROPY_HW_USB_CUSTOM_RX_WANTED_CHAR_CB,
80-
#endif
81-
#ifdef MICROPY_HW_USB_CUSTOM_LINE_STATE_CB
82-
.callback_line_state_changed = (tusb_cdcacm_callback_t)&MICROPY_HW_USB_CUSTOM_LINE_STATE_CB,
83-
#endif
84-
#ifdef MICROPY_HW_USB_CUSTOM_LINE_CODING_CB
85-
.callback_line_coding_changed = &MICROPY_HW_USB_CUSTOM_LINE_CODING_CB,
86-
#endif
44+
// Configure USB PHY
45+
usb_phy_config_t phy_conf = {
46+
.controller = USB_PHY_CTRL_OTG,
47+
.otg_mode = USB_OTG_MODE_DEVICE,
8748
};
88-
ESP_ERROR_CHECK(tusb_cdc_acm_init(&acm_cfg));
49+
// Internal USB PHY
50+
phy_conf.target = USB_PHY_TARGET_INT;
51+
52+
// Init ESP USB Phy
53+
usb_new_phy(&phy_conf, &phy_hdl);
54+
55+
// Init MicroPython / TinyUSB
56+
mp_usbd_init();
8957

9058
}
9159

92-
void usb_tx_strn(const char *str, size_t len) {
93-
// Write out the data to the CDC interface, but only while the USB host is connected.
94-
uint64_t timeout = esp_timer_get_time() + (uint64_t)(MICROPY_HW_USB_CDC_TX_TIMEOUT_MS * 1000);
95-
while (tud_cdc_n_connected(CDC_ITF) && len && esp_timer_get_time() < timeout) {
96-
size_t l = tinyusb_cdcacm_write_queue(CDC_ITF, (uint8_t *)str, len);
97-
str += l;
98-
len -= l;
99-
tud_cdc_n_write_flush(CDC_ITF);
100-
}
60+
void mp_usbd_port_get_serial_number(char *serial_buf) {
61+
// use factory default MAC as serial ID
62+
uint8_t mac[8];
63+
esp_efuse_mac_get_default(mac);
64+
MP_STATIC_ASSERT(sizeof(mac) * 2 <= MICROPY_HW_USB_DESC_STR_MAX);
65+
mp_usbd_hex_str(serial_buf, mac, sizeof(mac));
10166
}
10267

10368
#endif // MICROPY_HW_USB_CDC

ports/esp32/usb.h

-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,5 @@
2929
#define MICROPY_HW_USB_CDC_TX_TIMEOUT_MS (500)
3030

3131
void usb_init(void);
32-
void usb_tx_strn(const char *str, size_t len);
3332

3433
#endif // MICROPY_INCLUDED_ESP32_USB_H

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[tool.codespell]
22
count = ""
33
ignore-regex = '\b[A-Z]{3}\b'
4-
ignore-words-list = "ans,asend,deques,dout,extint,hsi,iput,mis,numer,shft,technic,ure"
4+
ignore-words-list = "ans,asend,deques,dout,extint,hsi,iput,mis,numer,shft,synopsys,technic,ure"
55
quiet-level = 3
66
skip = """
77
*/build*,\

0 commit comments

Comments
 (0)