From 4247921c4ebfced79aa7ccfbb835c9f60ad6f0fc Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Thu, 23 May 2024 17:23:41 +1000 Subject: [PATCH 1/6] 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 --- ports/esp32/esp32_common.cmake | 40 ++++++++++++ ports/esp32/main.c | 3 +- ports/esp32/main_esp32s2/CMakeLists.txt | 2 + ports/esp32/main_esp32s3/CMakeLists.txt | 2 + ports/esp32/mpconfigport.h | 77 ++++++++++++++++++----- ports/esp32/mphalport.c | 27 ++++++-- ports/esp32/usb.c | 83 +++++++------------------ ports/esp32/usb.h | 1 - pyproject.toml | 2 +- 9 files changed, 156 insertions(+), 81 deletions(-) diff --git a/ports/esp32/esp32_common.cmake b/ports/esp32/esp32_common.cmake index 7c5089639a5f2..e59e2dcd7a444 100644 --- a/ports/esp32/esp32_common.cmake +++ b/ports/esp32/esp32_common.cmake @@ -53,6 +53,37 @@ list(APPEND MICROPY_SOURCE_DRIVERS ${MICROPY_DIR}/drivers/dht/dht.c ) +string(CONCAT GIT_SUBMODULES "${GIT_SUBMODULES} " lib/tinyusb) +if(MICROPY_PY_TINYUSB) + set(TINYUSB_SRC "${MICROPY_DIR}/lib/tinyusb/src") + string(TOUPPER OPT_MCU_${IDF_TARGET} tusb_mcu) + + list(APPEND MICROPY_DEF_TINYUSB + CFG_TUSB_MCU=${tusb_mcu} + ) + + list(APPEND MICROPY_SOURCE_TINYUSB + ${TINYUSB_SRC}/tusb.c + ${TINYUSB_SRC}/common/tusb_fifo.c + ${TINYUSB_SRC}/device/usbd.c + ${TINYUSB_SRC}/device/usbd_control.c + ${TINYUSB_SRC}/class/cdc/cdc_device.c + ${TINYUSB_SRC}/portable/synopsys/dwc2/dcd_dwc2.c + ${MICROPY_DIR}/shared/tinyusb/mp_usbd.c + ${MICROPY_DIR}/shared/tinyusb/mp_usbd_cdc.c + ${MICROPY_DIR}/shared/tinyusb/mp_usbd_descriptor.c + ) + + list(APPEND MICROPY_INC_TINYUSB + ${TINYUSB_SRC} + ${MICROPY_DIR}/shared/tinyusb/ + ) + + list(APPEND MICROPY_LINK_TINYUSB + -Wl,--wrap=dcd_event_handler + ) +endif() + list(APPEND MICROPY_SOURCE_PORT panichandler.c adc.c @@ -100,6 +131,7 @@ list(APPEND MICROPY_SOURCE_QSTR ${MICROPY_SOURCE_LIB} ${MICROPY_SOURCE_PORT} ${MICROPY_SOURCE_BOARD} + ${MICROPY_SOURCE_TINYUSB} ) list(APPEND IDF_COMPONENTS @@ -134,6 +166,7 @@ list(APPEND IDF_COMPONENTS soc spi_flash ulp + usb vfs ) @@ -147,9 +180,11 @@ idf_component_register( ${MICROPY_SOURCE_DRIVERS} ${MICROPY_SOURCE_PORT} ${MICROPY_SOURCE_BOARD} + ${MICROPY_SOURCE_TINYUSB} INCLUDE_DIRS ${MICROPY_INC_CORE} ${MICROPY_INC_USERMOD} + ${MICROPY_INC_TINYUSB} ${MICROPY_PORT_DIR} ${MICROPY_BOARD_DIR} ${CMAKE_BINARY_DIR} @@ -171,6 +206,7 @@ endif() target_compile_definitions(${MICROPY_TARGET} PUBLIC ${MICROPY_DEF_CORE} ${MICROPY_DEF_BOARD} + ${MICROPY_DEF_TINYUSB} MICROPY_ESP_IDF_4=1 MICROPY_VFS_FAT=1 MICROPY_VFS_LFS2=1 @@ -186,6 +222,10 @@ target_compile_options(${MICROPY_TARGET} PUBLIC -Wno-missing-field-initializers ) +target_link_options(${MICROPY_TARGET} PUBLIC + ${MICROPY_LINK_TINYUSB} +) + # Additional include directories needed for private NimBLE headers. target_include_directories(${MICROPY_TARGET} PUBLIC ${IDF_PATH}/components/bt/host/nimble/nimble diff --git a/ports/esp32/main.c b/ports/esp32/main.c index ca5a0e3c2097c..03dc0807a025c 100644 --- a/ports/esp32/main.c +++ b/ports/esp32/main.c @@ -52,6 +52,7 @@ #include "shared/readline/readline.h" #include "shared/runtime/pyexec.h" #include "shared/timeutils/timeutils.h" +#include "shared/tinyusb/mp_usbd.h" #include "mbedtls/platform_time.h" #include "uart.h" @@ -101,7 +102,7 @@ void mp_task(void *pvParameter) { #endif #if MICROPY_HW_ESP_USB_SERIAL_JTAG usb_serial_jtag_init(); - #elif MICROPY_HW_USB_CDC + #elif MICROPY_HW_ENABLE_USBDEV usb_init(); #endif #if MICROPY_HW_ENABLE_UART_REPL diff --git a/ports/esp32/main_esp32s2/CMakeLists.txt b/ports/esp32/main_esp32s2/CMakeLists.txt index 40188abff8e57..bc5ab939c3ce3 100644 --- a/ports/esp32/main_esp32s2/CMakeLists.txt +++ b/ports/esp32/main_esp32s2/CMakeLists.txt @@ -8,4 +8,6 @@ if(NOT MICROPY_PORT_DIR) get_filename_component(MICROPY_PORT_DIR ${MICROPY_DIR}/ports/esp32 ABSOLUTE) endif() +set(MICROPY_PY_TINYUSB ON) + include(${MICROPY_PORT_DIR}/esp32_common.cmake) diff --git a/ports/esp32/main_esp32s3/CMakeLists.txt b/ports/esp32/main_esp32s3/CMakeLists.txt index 40188abff8e57..bc5ab939c3ce3 100644 --- a/ports/esp32/main_esp32s3/CMakeLists.txt +++ b/ports/esp32/main_esp32s3/CMakeLists.txt @@ -8,4 +8,6 @@ if(NOT MICROPY_PORT_DIR) get_filename_component(MICROPY_PORT_DIR ${MICROPY_DIR}/ports/esp32 ABSOLUTE) endif() +set(MICROPY_PY_TINYUSB ON) + include(${MICROPY_PORT_DIR}/esp32_common.cmake) diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 5dfb16447dec0..f1687cf168ff6 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -194,6 +194,69 @@ #define MP_STATE_PORT MP_STATE_VM +#ifndef MICROPY_HW_ENABLE_USBDEV +#define MICROPY_HW_ENABLE_USBDEV (SOC_USB_OTG_SUPPORTED) +#endif + +#if MICROPY_HW_ENABLE_USBDEV +#define MICROPY_SCHEDULER_STATIC_NODES (1) + +#ifndef MICROPY_HW_USB_VID +#define USB_ESPRESSIF_VID 0x303A +#if CONFIG_TINYUSB_DESC_USE_ESPRESSIF_VID +#define MICROPY_HW_USB_VID (USB_ESPRESSIF_VID) +#else +#define MICROPY_HW_USB_VID (CONFIG_TINYUSB_DESC_CUSTOM_VID) +#endif +#endif + +#ifndef MICROPY_HW_USB_PID +#if CONFIG_TINYUSB_DESC_USE_DEFAULT_PID +#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n)) +// A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. +// Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. +// Auto ProductID layout's Bitmap: +// [MSB] HID | MSC | CDC [LSB] +#define USB_TUSB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ + _PID_MAP(MIDI, 3)) // | _PID_MAP(AUDIO, 4) | _PID_MAP(VENDOR, 5) ) +#define MICROPY_HW_USB_PID (USB_TUSB_PID) +#else +#define MICROPY_HW_USB_PID (CONFIG_TINYUSB_DESC_CUSTOM_PID) +#endif +#endif + +#ifndef MICROPY_HW_USB_MANUFACTURER_STRING +#ifdef CONFIG_TINYUSB_DESC_MANUFACTURER_STRING +#define MICROPY_HW_USB_MANUFACTURER_STRING CONFIG_TINYUSB_DESC_MANUFACTURER_STRING +#else +#define MICROPY_HW_USB_MANUFACTURER_STRING "MicroPython" +#endif +#endif + +#ifndef MICROPY_HW_USB_PRODUCT_FS_STRING +#ifdef CONFIG_TINYUSB_DESC_PRODUCT_STRING +#define MICROPY_HW_USB_PRODUCT_FS_STRING CONFIG_TINYUSB_DESC_PRODUCT_STRING +#else +#define MICROPY_HW_USB_PRODUCT_FS_STRING "Board in FS mode" +#endif +#endif + +#endif // MICROPY_HW_ENABLE_USBDEV + +// Enable stdio over native USB peripheral CDC via TinyUSB +#ifndef MICROPY_HW_USB_CDC +#define MICROPY_HW_USB_CDC (MICROPY_HW_ENABLE_USBDEV) +#endif + +// Enable stdio over USB Serial/JTAG peripheral +#ifndef MICROPY_HW_ESP_USB_SERIAL_JTAG +#define MICROPY_HW_ESP_USB_SERIAL_JTAG (SOC_USB_SERIAL_JTAG_SUPPORTED && !MICROPY_HW_USB_CDC) +#endif + +#if MICROPY_HW_USB_CDC && MICROPY_HW_ESP_USB_SERIAL_JTAG +#error "Invalid build config: Can't enable both native USB and USB Serial/JTAG peripheral" +#endif + // type definitions for the specific machine #define MICROPY_MAKE_POINTER_CALLABLE(p) ((void *)((mp_uint_t)(p))) @@ -253,20 +316,6 @@ typedef long mp_off_t; // board specifics #define MICROPY_PY_SYS_PLATFORM "esp32" -// Enable stdio over native USB peripheral CDC via TinyUSB -#ifndef MICROPY_HW_USB_CDC -#define MICROPY_HW_USB_CDC (SOC_USB_OTG_SUPPORTED) -#endif - -// Enable stdio over USB Serial/JTAG peripheral -#ifndef MICROPY_HW_ESP_USB_SERIAL_JTAG -#define MICROPY_HW_ESP_USB_SERIAL_JTAG (SOC_USB_SERIAL_JTAG_SUPPORTED && !MICROPY_HW_USB_CDC) -#endif - -#if MICROPY_HW_USB_CDC && MICROPY_HW_ESP_USB_SERIAL_JTAG -#error "Invalid build config: Can't enable both native USB and USB Serial/JTAG peripheral" -#endif - // ESP32-S3 extended IO for 47 & 48 #ifndef MICROPY_HW_ESP32S3_EXTENDED_IO #define MICROPY_HW_ESP32S3_EXTENDED_IO (1) diff --git a/ports/esp32/mphalport.c b/ports/esp32/mphalport.c index 7d0154cc05315..3f267401366cb 100644 --- a/ports/esp32/mphalport.c +++ b/ports/esp32/mphalport.c @@ -42,6 +42,8 @@ #include "extmod/misc.h" #include "shared/timeutils/timeutils.h" #include "shared/runtime/pyexec.h" +#include "shared/tinyusb/mp_usbd.h" +#include "shared/tinyusb/mp_usbd_cdc.h" #include "mphalport.h" #include "usb.h" #include "usb_serial_jtag.h" @@ -106,13 +108,19 @@ uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) { uintptr_t ret = 0; #if MICROPY_HW_ESP_USB_SERIAL_JTAG usb_serial_jtag_poll_rx(); - #endif - if ((poll_flags & MP_STREAM_POLL_RD) && stdin_ringbuf.iget != stdin_ringbuf.iput) { + if ((poll_flags & MP_STREAM_POLL_RD) && ringbuf_peek(&stdin_ringbuf) != -1) { ret |= MP_STREAM_POLL_RD; } if (poll_flags & MP_STREAM_POLL_WR) { ret |= MP_STREAM_POLL_WR; } + #endif + #if MICROPY_HW_USB_CDC + ret |= mp_usbd_cdc_poll_interfaces(poll_flags); + #endif + #if MICROPY_PY_OS_DUPTERM + ret |= mp_os_dupterm_poll(poll_flags); + #endif return ret; } @@ -121,6 +129,9 @@ int mp_hal_stdin_rx_chr(void) { #if MICROPY_HW_ESP_USB_SERIAL_JTAG usb_serial_jtag_poll_rx(); #endif + #if MICROPY_HW_USB_CDC + mp_usbd_cdc_poll_interfaces(0); + #endif int c = ringbuf_get(&stdin_ringbuf); if (c != -1) { return c; @@ -133,6 +144,7 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) { // Only release the GIL if many characters are being sent mp_uint_t ret = len; bool did_write = false; + #if MICROPY_HW_ENABLE_UART_REPL || CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED bool release_gil = len > MICROPY_PY_STRING_TX_GIL_THRESHOLD; #if MICROPY_DEBUG_PRINTERS && MICROPY_DEBUG_VERBOSE && MICROPY_PY_THREAD_GIL // 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) { #if MICROPY_HW_ESP_USB_SERIAL_JTAG usb_serial_jtag_tx_strn(str, len); did_write = true; - #elif MICROPY_HW_USB_CDC - usb_tx_strn(str, len); - did_write = true; #endif #if MICROPY_HW_ENABLE_UART_REPL uart_stdout_tx_strn(str, len); @@ -157,6 +166,14 @@ mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) { if (release_gil) { MP_THREAD_GIL_ENTER(); } + #endif // MICROPY_HW_ENABLE_UART_REPL || CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED + #if MICROPY_HW_USB_CDC + mp_uint_t cdc_res = mp_usbd_cdc_tx_strn(str, len); + if (cdc_res > 0) { + did_write = true; + ret = MIN(cdc_res, ret); + } + #endif int dupterm_res = mp_os_dupterm_tx_strn(str, len); if (dupterm_res >= 0) { did_write = true; diff --git a/ports/esp32/usb.c b/ports/esp32/usb.c index 4207e77df210b..d643a7bc77410 100644 --- a/ports/esp32/usb.c +++ b/ports/esp32/usb.c @@ -29,75 +29,40 @@ #include "usb.h" #if MICROPY_HW_USB_CDC +#include "esp_rom_gpio.h" +#include "esp_mac.h" +#include "esp_private/usb_phy.h" -#include "esp_timer.h" -#ifndef NO_QSTR -#include "tinyusb.h" -#include "tusb_cdc_acm.h" -#endif +#include "shared/tinyusb/mp_usbd.h" -#define CDC_ITF TINYUSB_CDC_ACM_0 +static usb_phy_handle_t phy_hdl; -static uint8_t usb_rx_buf[CONFIG_TINYUSB_CDC_RX_BUFSIZE]; - -// This is called from FreeRTOS task "tusb_tsk" in espressif__esp_tinyusb (not an ISR). -static void usb_callback_rx(int itf, cdcacm_event_t *event) { - // espressif__esp_tinyusb places tinyusb rx data onto freertos ringbuffer which - // this function forwards onto our stdin_ringbuf. - for (;;) { - size_t len = 0; - esp_err_t ret = tinyusb_cdcacm_read(itf, usb_rx_buf, sizeof(usb_rx_buf), &len); - if (ret != ESP_OK) { - break; - } - if (len == 0) { - break; - } - for (size_t i = 0; i < len; ++i) { - if (usb_rx_buf[i] == mp_interrupt_char) { - mp_sched_keyboard_interrupt(); - } else { - ringbuf_put(&stdin_ringbuf, usb_rx_buf[i]); - } - } - mp_hal_wake_main_task(); - } -} void usb_init(void) { - // Initialise the USB with defaults. - tinyusb_config_t tusb_cfg = {0}; - ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); + // ref: https://github.com/espressif/esp-usb/blob/4b6a798d0bed444fff48147c8dcdbbd038e92892/device/esp_tinyusb/tinyusb.c - // Initialise the USB serial interface. - tinyusb_config_cdcacm_t acm_cfg = { - .usb_dev = TINYUSB_USBDEV_0, - .cdc_port = CDC_ITF, - .rx_unread_buf_sz = 256, - .callback_rx = &usb_callback_rx, - #ifdef MICROPY_HW_USB_CUSTOM_RX_WANTED_CHAR_CB - .callback_rx_wanted_char = &MICROPY_HW_USB_CUSTOM_RX_WANTED_CHAR_CB, - #endif - #ifdef MICROPY_HW_USB_CUSTOM_LINE_STATE_CB - .callback_line_state_changed = (tusb_cdcacm_callback_t)&MICROPY_HW_USB_CUSTOM_LINE_STATE_CB, - #endif - #ifdef MICROPY_HW_USB_CUSTOM_LINE_CODING_CB - .callback_line_coding_changed = &MICROPY_HW_USB_CUSTOM_LINE_CODING_CB, - #endif + // Configure USB PHY + usb_phy_config_t phy_conf = { + .controller = USB_PHY_CTRL_OTG, + .otg_mode = USB_OTG_MODE_DEVICE, }; - ESP_ERROR_CHECK(tusb_cdc_acm_init(&acm_cfg)); + // Internal USB PHY + phy_conf.target = USB_PHY_TARGET_INT; + + // Init ESP USB Phy + usb_new_phy(&phy_conf, &phy_hdl); + + // Init MicroPython / TinyUSB + mp_usbd_init(); } -void usb_tx_strn(const char *str, size_t len) { - // Write out the data to the CDC interface, but only while the USB host is connected. - uint64_t timeout = esp_timer_get_time() + (uint64_t)(MICROPY_HW_USB_CDC_TX_TIMEOUT_MS * 1000); - while (tud_cdc_n_connected(CDC_ITF) && len && esp_timer_get_time() < timeout) { - size_t l = tinyusb_cdcacm_write_queue(CDC_ITF, (uint8_t *)str, len); - str += l; - len -= l; - tud_cdc_n_write_flush(CDC_ITF); - } +void mp_usbd_port_get_serial_number(char *serial_buf) { + // use factory default MAC as serial ID + uint8_t mac[8]; + esp_efuse_mac_get_default(mac); + MP_STATIC_ASSERT(sizeof(mac) * 2 <= MICROPY_HW_USB_DESC_STR_MAX); + mp_usbd_hex_str(serial_buf, mac, sizeof(mac)); } #endif // MICROPY_HW_USB_CDC diff --git a/ports/esp32/usb.h b/ports/esp32/usb.h index a4c7d40701dfc..5e5eea34e5694 100644 --- a/ports/esp32/usb.h +++ b/ports/esp32/usb.h @@ -29,6 +29,5 @@ #define MICROPY_HW_USB_CDC_TX_TIMEOUT_MS (500) void usb_init(void); -void usb_tx_strn(const char *str, size_t len); #endif // MICROPY_INCLUDED_ESP32_USB_H diff --git a/pyproject.toml b/pyproject.toml index e44afe37e0ebb..1650bd088ea22 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.codespell] count = "" ignore-regex = '\b[A-Z]{3}\b' -ignore-words-list = "ans,asend,deques,dout,extint,hsi,iput,mis,numer,shft,technic,ure" +ignore-words-list = "ans,asend,deques,dout,extint,hsi,iput,mis,numer,shft,synopsys,technic,ure" quiet-level = 3 skip = """ */build*,\ From 641f60045f8014ad480e4297b982753edcb5b5c6 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Thu, 23 May 2024 17:23:41 +1000 Subject: [PATCH 2/6] shared/tinyusb: Remove MICROPY_HW_USB_EXTERNAL_TINYUSB. No longer needed as shared tinyusb is now used by the esp32 port. Signed-off-by: Andrew Leech --- shared/tinyusb/mp_usbd_cdc.c | 8 +------- shared/tinyusb/mp_usbd_cdc.h | 4 ---- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/shared/tinyusb/mp_usbd_cdc.c b/shared/tinyusb/mp_usbd_cdc.c index c6a88e467d398..0fbecb0a8657f 100644 --- a/shared/tinyusb/mp_usbd_cdc.c +++ b/shared/tinyusb/mp_usbd_cdc.c @@ -149,13 +149,7 @@ static void usbd_cdc_run_bootloader_task(mp_sched_node_t *node) { } #endif -void -#if MICROPY_HW_USB_EXTERNAL_TINYUSB -mp_usbd_line_state_cb -#else -tud_cdc_line_state_cb -#endif - (uint8_t itf, bool dtr, bool rts) { +void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { #if MICROPY_HW_USB_CDC && !MICROPY_EXCLUDE_SHARED_TINYUSB_USBD_CDC if (dtr) { // A host application has started to open the cdc serial port. diff --git a/shared/tinyusb/mp_usbd_cdc.h b/shared/tinyusb/mp_usbd_cdc.h index 1abe0fa0a41b3..648cf12881e31 100644 --- a/shared/tinyusb/mp_usbd_cdc.h +++ b/shared/tinyusb/mp_usbd_cdc.h @@ -35,8 +35,4 @@ uintptr_t mp_usbd_cdc_poll_interfaces(uintptr_t poll_flags); void tud_cdc_rx_cb(uint8_t itf); mp_uint_t mp_usbd_cdc_tx_strn(const char *str, mp_uint_t len); -#if MICROPY_HW_USB_EXTERNAL_TINYUSB -void mp_usbd_line_state_cb(uint8_t itf, bool dtr, bool rts); -#endif - #endif // MICROPY_INCLUDED_SHARED_TINYUSB_MP_USBD_CDC_H From 5ae622ef7b31881cb38b56baa66d8aec3d132cf9 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Thu, 23 May 2024 22:08:12 +1000 Subject: [PATCH 3/6] esp32: Add automatic bootloader handling for S2 and S3. Enables support for the ESP standard DTR/RTS based reboot to bootloader. Switches from OTG to Serial/Jtag mode to workaround issue discussed in: https://github.com/espressif/arduino-esp32/issues/6762 Signed-off-by: Andrew Leech --- .../boards/ESP32_GENERIC_S3/sdkconfig.board | 1 - .../esp32/boards/UM_FEATHERS2/sdkconfig.board | 1 - .../boards/UM_FEATHERS2NEO/sdkconfig.board | 1 - .../esp32/boards/UM_FEATHERS3/sdkconfig.board | 1 - ports/esp32/boards/UM_NANOS3/sdkconfig.board | 1 - ports/esp32/boards/UM_PROS3/sdkconfig.board | 1 - ports/esp32/boards/UM_TINYS2/sdkconfig.board | 1 - ports/esp32/boards/UM_TINYS3/sdkconfig.board | 1 - .../boards/UM_TINYWATCHS3/sdkconfig.board | 1 - ports/esp32/modmachine.c | 12 ++++++++++ ports/esp32/mpconfigport.h | 3 ++- ports/esp32/usb.c | 12 ++++++++++ ports/esp32/usb.h | 1 + shared/tinyusb/mp_usbd_cdc.c | 23 +++++++++++++++++-- shared/tinyusb/mp_usbd_cdc.h | 6 +++++ 15 files changed, 54 insertions(+), 12 deletions(-) diff --git a/ports/esp32/boards/ESP32_GENERIC_S3/sdkconfig.board b/ports/esp32/boards/ESP32_GENERIC_S3/sdkconfig.board index a36b971162850..9839b0d300510 100644 --- a/ports/esp32/boards/ESP32_GENERIC_S3/sdkconfig.board +++ b/ports/esp32/boards/ESP32_GENERIC_S3/sdkconfig.board @@ -1,6 +1,5 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_ESPTOOLPY_AFTER_NORESET=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB= CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y diff --git a/ports/esp32/boards/UM_FEATHERS2/sdkconfig.board b/ports/esp32/boards/UM_FEATHERS2/sdkconfig.board index c2e1c2b3d3b7c..9ab58f215f2e6 100644 --- a/ports/esp32/boards/UM_FEATHERS2/sdkconfig.board +++ b/ports/esp32/boards/UM_FEATHERS2/sdkconfig.board @@ -1,6 +1,5 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_ESPTOOLPY_AFTER_NORESET=y CONFIG_SPIRAM_MEMTEST= diff --git a/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board b/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board index a624f7fd97fb1..6ef737212f23a 100644 --- a/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board +++ b/ports/esp32/boards/UM_FEATHERS2NEO/sdkconfig.board @@ -1,6 +1,5 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_ESPTOOLPY_AFTER_NORESET=y # LWIP CONFIG_LWIP_LOCAL_HOSTNAME="UMFeatherS2Neo" diff --git a/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board b/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board index c557141ebfc9b..3ca0c4b243e28 100644 --- a/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board +++ b/ports/esp32/boards/UM_FEATHERS3/sdkconfig.board @@ -1,6 +1,5 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_ESPTOOLPY_AFTER_NORESET=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB= CONFIG_ESPTOOLPY_FLASHSIZE_8MB= diff --git a/ports/esp32/boards/UM_NANOS3/sdkconfig.board b/ports/esp32/boards/UM_NANOS3/sdkconfig.board index 31d7528317a1d..2a39c64337b20 100644 --- a/ports/esp32/boards/UM_NANOS3/sdkconfig.board +++ b/ports/esp32/boards/UM_NANOS3/sdkconfig.board @@ -1,6 +1,5 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_ESPTOOLPY_AFTER_NORESET=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB= CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y diff --git a/ports/esp32/boards/UM_PROS3/sdkconfig.board b/ports/esp32/boards/UM_PROS3/sdkconfig.board index 0de84d57d01d9..5752e03e60013 100644 --- a/ports/esp32/boards/UM_PROS3/sdkconfig.board +++ b/ports/esp32/boards/UM_PROS3/sdkconfig.board @@ -1,6 +1,5 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_ESPTOOLPY_AFTER_NORESET=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB= CONFIG_ESPTOOLPY_FLASHSIZE_8MB= diff --git a/ports/esp32/boards/UM_TINYS2/sdkconfig.board b/ports/esp32/boards/UM_TINYS2/sdkconfig.board index 0a2097e242141..c09731431b9e0 100644 --- a/ports/esp32/boards/UM_TINYS2/sdkconfig.board +++ b/ports/esp32/boards/UM_TINYS2/sdkconfig.board @@ -1,6 +1,5 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_ESPTOOLPY_AFTER_NORESET=y # LWIP CONFIG_LWIP_LOCAL_HOSTNAME="UMTinyS2" diff --git a/ports/esp32/boards/UM_TINYS3/sdkconfig.board b/ports/esp32/boards/UM_TINYS3/sdkconfig.board index d1689aaf394c8..d1d19761a0666 100644 --- a/ports/esp32/boards/UM_TINYS3/sdkconfig.board +++ b/ports/esp32/boards/UM_TINYS3/sdkconfig.board @@ -1,6 +1,5 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_ESPTOOLPY_AFTER_NORESET=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB= CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y diff --git a/ports/esp32/boards/UM_TINYWATCHS3/sdkconfig.board b/ports/esp32/boards/UM_TINYWATCHS3/sdkconfig.board index d73f4fe0bc012..1380e15ce8481 100644 --- a/ports/esp32/boards/UM_TINYWATCHS3/sdkconfig.board +++ b/ports/esp32/boards/UM_TINYWATCHS3/sdkconfig.board @@ -1,6 +1,5 @@ CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHFREQ_80M=y -CONFIG_ESPTOOLPY_AFTER_NORESET=y CONFIG_ESPTOOLPY_FLASHSIZE_4MB= CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index 759455a59a5d6..5e05a261b70c7 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -222,7 +222,19 @@ static mp_int_t mp_machine_reset_cause(void) { #if MICROPY_ESP32_USE_BOOTLOADER_RTC #include "soc/rtc_cntl_reg.h" +#include "usb.h" +#if CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rom/usb/usb_dc.h" +#include "esp32s3/rom/usb/usb_persist.h" +#include "esp32s3/rom/usb/chip_usb_dw_wrapper.h" +#endif + NORETURN static void machine_bootloader_rtc(void) { + #if CONFIG_IDF_TARGET_ESP32S3 + usb_usj_mode(); + usb_dc_prepare_persist(); + chip_usb_set_persist_flags(USBDC_BOOT_DFU); + #endif REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); esp_restart(); } diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index f1687cf168ff6..4c94fd16e2c58 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -199,7 +199,8 @@ #endif #if MICROPY_HW_ENABLE_USBDEV -#define MICROPY_SCHEDULER_STATIC_NODES (1) +#define MICROPY_SCHEDULER_STATIC_NODES (1) +#define MICROPY_HW_USB_CDC_DTR_RTS_BOOTLOADER (1) #ifndef MICROPY_HW_USB_VID #define USB_ESPRESSIF_VID 0x303A diff --git a/ports/esp32/usb.c b/ports/esp32/usb.c index d643a7bc77410..3ce3d045810af 100644 --- a/ports/esp32/usb.c +++ b/ports/esp32/usb.c @@ -57,6 +57,18 @@ void usb_init(void) { } +#if CONFIG_IDF_TARGET_ESP32S3 +void usb_usj_mode(void) { + // Switch the USB PHY back to Serial/Jtag mode, disabling OTG support + // This should be run before jumping to bootloader. + usb_del_phy(phy_hdl); + usb_phy_config_t phy_conf = { + .controller = USB_PHY_CTRL_SERIAL_JTAG, + }; + usb_new_phy(&phy_conf, &phy_hdl); +} +#endif + void mp_usbd_port_get_serial_number(char *serial_buf) { // use factory default MAC as serial ID uint8_t mac[8]; diff --git a/ports/esp32/usb.h b/ports/esp32/usb.h index 5e5eea34e5694..2bfa3d31aff8b 100644 --- a/ports/esp32/usb.h +++ b/ports/esp32/usb.h @@ -29,5 +29,6 @@ #define MICROPY_HW_USB_CDC_TX_TIMEOUT_MS (500) void usb_init(void); +void usb_usj_mode(void); #endif // MICROPY_INCLUDED_ESP32_USB_H diff --git a/shared/tinyusb/mp_usbd_cdc.c b/shared/tinyusb/mp_usbd_cdc.c index 0fbecb0a8657f..b4151f685c41e 100644 --- a/shared/tinyusb/mp_usbd_cdc.c +++ b/shared/tinyusb/mp_usbd_cdc.c @@ -138,9 +138,12 @@ void tud_sof_cb(uint32_t frame_count) { #endif -#if MICROPY_HW_ENABLE_USBDEV && (MICROPY_HW_USB_CDC_1200BPS_TOUCH || MICROPY_HW_USB_CDC) +#if MICROPY_HW_ENABLE_USBDEV && ( \ + MICROPY_HW_USB_CDC_1200BPS_TOUCH || \ + MICROPY_HW_USB_CDC || \ + MICROPY_HW_USB_CDC_DTR_RTS_BOOTLOADER) -#if MICROPY_HW_USB_CDC_1200BPS_TOUCH +#if MICROPY_HW_USB_CDC_1200BPS_TOUCH || MICROPY_HW_USB_CDC_DTR_RTS_BOOTLOADER static mp_sched_node_t mp_bootloader_sched_node; static void usbd_cdc_run_bootloader_task(mp_sched_node_t *node) { @@ -149,6 +152,13 @@ static void usbd_cdc_run_bootloader_task(mp_sched_node_t *node) { } #endif +#if MICROPY_HW_USB_CDC_DTR_RTS_BOOTLOADER +static struct { + bool dtr : 1; + bool rts : 1; +} prev_line_state = {0}; +#endif + void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { #if MICROPY_HW_USB_CDC && !MICROPY_EXCLUDE_SHARED_TINYUSB_USBD_CDC if (dtr) { @@ -159,6 +169,15 @@ void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { tud_sof_cb_enable(true); } #endif + #if MICROPY_HW_USB_CDC_DTR_RTS_BOOTLOADER + if (dtr && !rts) { + if (prev_line_state.rts && !prev_line_state.dtr) { + mp_sched_schedule_node(&mp_bootloader_sched_node, usbd_cdc_run_bootloader_task); + } + } + prev_line_state.rts = rts; + prev_line_state.dtr = dtr; + #endif #if MICROPY_HW_USB_CDC_1200BPS_TOUCH if (dtr == false && rts == false) { // Device is disconnected. diff --git a/shared/tinyusb/mp_usbd_cdc.h b/shared/tinyusb/mp_usbd_cdc.h index 648cf12881e31..8d37a77315dcc 100644 --- a/shared/tinyusb/mp_usbd_cdc.h +++ b/shared/tinyusb/mp_usbd_cdc.h @@ -31,6 +31,12 @@ #define MICROPY_HW_USB_CDC_TX_TIMEOUT (500) #endif +// This is typically only enabled on esp32 +// parts which have an internal usb peripheral. +#ifndef MICROPY_HW_USB_CDC_DTR_RTS_BOOTLOADER +#define MICROPY_HW_USB_CDC_DTR_RTS_BOOTLOADER (0) +#endif + uintptr_t mp_usbd_cdc_poll_interfaces(uintptr_t poll_flags); void tud_cdc_rx_cb(uint8_t itf); mp_uint_t mp_usbd_cdc_tx_strn(const char *str, mp_uint_t len); From 386771e052cd0396031705f22bd2ecab5cc30ea5 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Tue, 4 Jun 2024 13:46:00 +1000 Subject: [PATCH 4/6] esp32/Makefile: Allow auto-port selection if not passed on cmdline. Signed-off-by: Andrew Leech --- ports/esp32/Makefile | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 3df2af4716fd9..62b1faa571931 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -29,8 +29,12 @@ BUILD ?= build-$(BOARD) endif # Device serial settings. -PORT ?= /dev/ttyUSB0 -BAUD ?= 460800 +ifneq ($(PORT),) +PORT_ARG := -p $(PORT) +endif +ifneq ($(BAUD),) +BAUD_ARG := -b $(BAUD) +endif PYTHON ?= python3 @@ -59,7 +63,7 @@ endif HELP_BUILD_ERROR ?= "See \033[1;31mhttps://github.com/micropython/micropython/wiki/Build-Troubleshooting\033[0m" define RUN_IDF_PY - idf.py $(IDFPY_FLAGS) -B $(BUILD) -p $(PORT) -b $(BAUD) $(1) + idf.py $(IDFPY_FLAGS) -B $(BUILD) $(PORT_ARG) $(BAUD_ARG) $(1) endef all: From 11bc7d0fc1074b01aaddc325209a281ee9acbba4 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Tue, 24 Sep 2024 11:35:53 +1000 Subject: [PATCH 5/6] esp32/boards: Update ARDUINO_NANO_ESP32 USB configuration. The custom line state handling is no longer needed as MicroPython runs it directly now. Signed-off-by: Andrew Leech --- ports/esp32/boards/ARDUINO_NANO_ESP32/board_init.c | 8 -------- ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h | 5 ----- 2 files changed, 13 deletions(-) diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/board_init.c b/ports/esp32/boards/ARDUINO_NANO_ESP32/board_init.c index 69a414cd5d9e3..3394bb1e2e219 100644 --- a/ports/esp32/boards/ARDUINO_NANO_ESP32/board_init.c +++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/board_init.c @@ -35,9 +35,6 @@ #include "double_tap.h" #include "usb.h" -#include "tinyusb.h" -#include "tusb_cdc_acm.h" - #define LED_RED GPIO_NUM_46 #define LED_GREEN GPIO_NUM_0 #define LED_BLUE GPIO_NUM_45 @@ -87,11 +84,6 @@ void NANO_ESP32_enter_bootloader(void) { esp_restart(); } -void NANO_ESP32_usb_callback_line_state_changed(int itf, void *event_in) { - cdcacm_event_t *event = event_in; - mp_usbd_line_state_cb(itf, event->line_state_changed_data.dtr, event->line_state_changed_data.rts); -} - void NANO_ESP32_board_startup(void) { boardctrl_startup(); diff --git a/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h b/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h index 8c2aa88e9f2ec..31b2a49bf8c31 100644 --- a/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h +++ b/ports/esp32/boards/ARDUINO_NANO_ESP32/mpconfigboard.h @@ -19,14 +19,9 @@ #define MICROPY_HW_SPI2_SCK (18) #define MICROPY_HW_ENABLE_USBDEV (1) -#define MICROPY_EXCLUDE_SHARED_TINYUSB_USBD_CDC (1) -#define MICROPY_HW_USB_EXTERNAL_TINYUSB (1) #define MICROPY_HW_USB_CDC_1200BPS_TOUCH (1) #define MICROPY_SCHEDULER_STATIC_NODES (1) -#define MICROPY_HW_USB_CUSTOM_LINE_STATE_CB NANO_ESP32_usb_callback_line_state_changed -void NANO_ESP32_usb_callback_line_state_changed(int itf, void *event); - #define MICROPY_BOARD_STARTUP NANO_ESP32_board_startup void NANO_ESP32_board_startup(void); From 548f88d2bd254f1328014a303f8bf602a0646421 Mon Sep 17 00:00:00 2001 From: Andrew Leech Date: Wed, 31 Jul 2024 21:40:05 +1000 Subject: [PATCH 6/6] shared/tinyusb: Wake main task if needed at end of USB ISR. Signed-off-by: Andrew Leech --- ports/mimxrt/mphalport.h | 4 ++++ ports/nrf/mphalport.h | 4 ++++ ports/renesas-ra/mphalport.h | 4 ++++ ports/rp2/mphalport.h | 4 ++++ ports/samd/mphalport.h | 4 ++++ shared/tinyusb/mp_usbd.c | 3 ++- 6 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ports/mimxrt/mphalport.h b/ports/mimxrt/mphalport.h index c69ebf58106b2..a0e4575024420 100644 --- a/ports/mimxrt/mphalport.h +++ b/ports/mimxrt/mphalport.h @@ -109,6 +109,10 @@ __attribute__((always_inline)) static inline uint32_t disable_irq(void) { void mp_hal_set_interrupt_char(int c); +static inline void mp_hal_wake_main_task_from_isr(void) { + // Defined for tinyusb support, nothing needs to be done here. +} + static inline mp_uint_t mp_hal_ticks_ms(void) { return ticks_ms32(); } diff --git a/ports/nrf/mphalport.h b/ports/nrf/mphalport.h index 50c61aefcdd59..a0bca58a625ba 100644 --- a/ports/nrf/mphalport.h +++ b/ports/nrf/mphalport.h @@ -53,6 +53,10 @@ void mp_hal_set_interrupt_char(int c); // -1 to disable int mp_hal_stdin_rx_chr(void); void mp_hal_stdout_tx_str(const char *str); +static inline void mp_hal_wake_main_task_from_isr(void) { + // Defined for tinyusb support, nothing needs to be done here. +} + void mp_hal_delay_ms(mp_uint_t ms); void mp_hal_delay_us(mp_uint_t us); diff --git a/ports/renesas-ra/mphalport.h b/ports/renesas-ra/mphalport.h index 14e6ee0c3eea6..0819abeaf617e 100644 --- a/ports/renesas-ra/mphalport.h +++ b/ports/renesas-ra/mphalport.h @@ -52,6 +52,10 @@ static inline int mp_hal_status_to_neg_errno(HAL_StatusTypeDef status) { NORETURN void mp_hal_raise(HAL_StatusTypeDef status); void mp_hal_set_interrupt_char(int c); // -1 to disable +static inline void mp_hal_wake_main_task_from_isr(void) { + // Defined for tinyusb support, nothing needs to be done here. +} + // timing functions #include "irq.h" diff --git a/ports/rp2/mphalport.h b/ports/rp2/mphalport.h index 16ac4259a6feb..09ad54dd1eb78 100644 --- a/ports/rp2/mphalport.h +++ b/ports/rp2/mphalport.h @@ -77,6 +77,10 @@ void mp_thread_end_atomic_section(uint32_t); void mp_hal_set_interrupt_char(int c); void mp_hal_time_ns_set_from_rtc(void); +static inline void mp_hal_wake_main_task_from_isr(void) { + // Defined for tinyusb support, nothing needs to be done here. +} + static inline void mp_hal_delay_us_fast(mp_uint_t us) { busy_wait_us(us); } diff --git a/ports/samd/mphalport.h b/ports/samd/mphalport.h index ee1ebf7aea2b0..6c9e525bb9162 100644 --- a/ports/samd/mphalport.h +++ b/ports/samd/mphalport.h @@ -50,6 +50,10 @@ uint64_t mp_hal_ticks_us_64(void); void mp_hal_set_interrupt_char(int c); +static inline void mp_hal_wake_main_task_from_isr(void) { + // Defined for tinyusb support, nothing needs to be done here. +} + __attribute__((always_inline)) static inline void enable_irq(uint32_t state) { __set_PRIMASK(state); } diff --git a/shared/tinyusb/mp_usbd.c b/shared/tinyusb/mp_usbd.c index 436314dcde5c8..7ccfa7018d4bc 100644 --- a/shared/tinyusb/mp_usbd.c +++ b/shared/tinyusb/mp_usbd.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include "py/mpconfig.h" +#include "py/mphal.h" #if MICROPY_HW_ENABLE_USBDEV @@ -55,6 +55,7 @@ extern void __real_dcd_event_handler(dcd_event_t const *event, bool in_isr); TU_ATTR_FAST_FUNC void __wrap_dcd_event_handler(dcd_event_t const *event, bool in_isr) { __real_dcd_event_handler(event, in_isr); mp_usbd_schedule_task(); + mp_hal_wake_main_task_from_isr(); } TU_ATTR_FAST_FUNC void mp_usbd_schedule_task(void) {