From 6bbab78fc1b659c1c1277ee914df0c10b0998baa Mon Sep 17 00:00:00 2001 From: Li Bo Date: Thu, 20 Jun 2024 18:52:42 +0800 Subject: [PATCH] fix(esp_tinyuf2): usb mount && cpu dynimic frequency fixes https://github.com/espressif/esp-iot-solution/issues/353 --- components/usb/esp_tinyuf2/CHANGELOG.md | 6 ++ components/usb/esp_tinyuf2/CMakeLists.txt | 43 +++++--- components/usb/esp_tinyuf2/Kconfig | 2 + components/usb/esp_tinyuf2/cdc/tusb_cdc_acm.c | 18 ++++ components/usb/esp_tinyuf2/cdc/tusb_console.c | 4 +- components/usb/esp_tinyuf2/esp_tinyuf2.c | 102 ++++++++++++++++-- components/usb/esp_tinyuf2/esp_tinyuf2.h | 13 +++ components/usb/esp_tinyuf2/idf_component.yml | 4 +- components/usb/esp_tinyuf2/msc/msc.c | 27 ----- .../usb/esp_tinyuf2/{msc => }/tusb_config.h | 0 .../esp_tinyuf2/{msc => }/usb_descriptors.c | 0 .../device/usb_uf2_nvs/pytest_usb_uf2_nvs.py | 2 +- 12 files changed, 166 insertions(+), 55 deletions(-) rename components/usb/esp_tinyuf2/{msc => }/tusb_config.h (100%) rename components/usb/esp_tinyuf2/{msc => }/usb_descriptors.c (100%) diff --git a/components/usb/esp_tinyuf2/CHANGELOG.md b/components/usb/esp_tinyuf2/CHANGELOG.md index 0f18b4ba8..60834c547 100644 --- a/components/usb/esp_tinyuf2/CHANGELOG.md +++ b/components/usb/esp_tinyuf2/CHANGELOG.md @@ -1,5 +1,11 @@ # ChangeLog +## v0.2.2 - 2024-06-19 + +* Fix usb may not be enumerated after switch from usb-serial-jtag to usb-otg +* Fix tinyusb debug issue if usb console is enabled +* Fix power management when frequency dynamic scaling is enabled + ## v0.2.1 - 2024-04-22 * Fix build with latest ESP-IDF (USB Hal: Change name of usb_phy HAL files to usb_fsls_phy) diff --git a/components/usb/esp_tinyuf2/CMakeLists.txt b/components/usb/esp_tinyuf2/CMakeLists.txt index ccef33633..19d7a2c14 100644 --- a/components/usb/esp_tinyuf2/CMakeLists.txt +++ b/components/usb/esp_tinyuf2/CMakeLists.txt @@ -1,26 +1,45 @@ -set(src_cdc) -set(inc_cdc) +idf_component_get_property(TUSB_PATH leeebo__tinyusb_src COMPONENT_DIR) +idf_component_get_property(DCD_CORE_INCLUDES leeebo__tinyusb_src DCD_CORE_INCLUDES) +idf_component_get_property(DCD_CORE_SRCS leeebo__tinyusb_src DCD_CORE_SRCS) +idf_component_get_property(TUSB_COMPILE_OPTIONS leeebo__tinyusb_src TUSB_COMPILE_OPTIONS) + +message("TinyUSB path: ${TUSB_PATH}") +message("TinyUSB includes: ${DCD_CORE_INCLUDES}") +message("TinyUSB sources: ${DCD_CORE_SRCS}") +message("TinyUSB compile options: ${TUSB_COMPILE_OPTIONS}") + +set(src_tusb + "${DCD_CORE_SRCS}" + "msc/msc.c" + "usb_descriptors.c" + "${TUSB_PATH}/src/class/cdc/cdc_device.c" + "${TUSB_PATH}/src/class/msc/msc_device.c" + ) +set(inc_tusb "${DCD_CORE_INCLUDES}" "msc") + if(CONFIG_ENABLE_UF2_USB_CONSOLE) -set(src_cdc "cdc/cdc.c" "cdc/tusb_cdc_acm.c" "cdc/tusb_console.c" "cdc/vfs_tinyusb.c") -set(inc_cdc "cdc") +list(APPEND src_tusb "cdc/cdc.c" "cdc/tusb_cdc_acm.c" "cdc/tusb_console.c" "cdc/vfs_tinyusb.c") +list(APPEND inc_tusb "cdc") endif() idf_component_register( SRCS "uf2/board_flash.c" "uf2/ghostfat.c" - "msc/msc.c" - "msc/usb_descriptors.c" "esp_tinyuf2.c" - ${src_cdc} - INCLUDE_DIRS "." "msc" ${inc_cdc} + ${src_tusb} + INCLUDE_DIRS "." ${inc_tusb} PRIV_INCLUDE_DIRS "private_include" REQUIRES app_update - PRIV_REQUIRES usb nvs_flash vfs esp_ringbuf) + PRIV_REQUIRES usb nvs_flash vfs esp_ringbuf esp_pm) -idf_component_get_property(tusb_lib leeebo__tinyusb_src COMPONENT_LIB) -cmake_policy(SET CMP0079 NEW) -target_link_libraries(${tusb_lib} PRIVATE ${COMPONENT_LIB}) +if(NOT CONFIG_TINYUSB_SOURCE_CODE_ONLY) +message(FATAL_ERROR "Please disable 'Build tinyusb as a static library' in menuconfig 'TinyUSB soucre'") +endif() + +target_compile_options(${COMPONENT_LIB} PUBLIC + ${TUSB_COMPILE_OPTIONS} +) execute_process(COMMAND git -C ${IDF_PATH} describe --dirty --always --tags OUTPUT_VARIABLE MY_IDF_VERSION diff --git a/components/usb/esp_tinyuf2/Kconfig b/components/usb/esp_tinyuf2/Kconfig index 773039389..a6b0922c7 100644 --- a/components/usb/esp_tinyuf2/Kconfig +++ b/components/usb/esp_tinyuf2/Kconfig @@ -3,10 +3,12 @@ menu "TinyUF2 Config" config ENABLE_UF2_FLASHING bool default y if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + select TINYUSB_SOURCE_CODE_ONLY help Enable UF2, only support ESP SoC with USB-OTG config ENABLE_UF2_USB_CONSOLE bool "Enable USB Console For log" + depends on ENABLE_UF2_FLASHING default n config UF2_DISK_SIZE_MB int "USB Virtual Disk size(MB)" diff --git a/components/usb/esp_tinyuf2/cdc/tusb_cdc_acm.c b/components/usb/esp_tinyuf2/cdc/tusb_cdc_acm.c index 5673b0438..74820b115 100644 --- a/components/usb/esp_tinyuf2/cdc/tusb_cdc_acm.c +++ b/components/usb/esp_tinyuf2/cdc/tusb_cdc_acm.c @@ -15,6 +15,7 @@ #include "tusb_cdc_acm.h" #include "cdc.h" #include "sdkconfig.h" +#include "esp_tinyuf2.h" #define RX_UNREADBUF_SZ_DEFAULT 64 // buffer storing all unread RX data #define MIN(x, y) (((x) < (y)) ? (x) : (y)) @@ -272,6 +273,12 @@ size_t tinyusb_cdcacm_write_queue_char(tinyusb_cdcacm_itf_t itf, char ch) if (!get_acm(itf)) { // non-initialized return 0; } + + if (esp_tinyuf2_current_state() < TINYUF2_STATE_MOUNTED) { + ESP_LOGD(TAG, "USB is not connected"); + return 0; + } + return tud_cdc_n_write_char(itf, ch); } @@ -280,6 +287,12 @@ size_t tinyusb_cdcacm_write_queue(tinyusb_cdcacm_itf_t itf, const uint8_t *in_bu if (!get_acm(itf)) { // non-initialized return 0; } + + if (esp_tinyuf2_current_state() < TINYUF2_STATE_MOUNTED) { + ESP_LOGD(TAG, "USB is not connected"); + return 0; + } + const uint32_t size_available = tud_cdc_n_write_available(itf); return tud_cdc_n_write(itf, in_buf, MIN(in_size, size_available)); } @@ -295,6 +308,11 @@ esp_err_t tinyusb_cdcacm_write_flush(tinyusb_cdcacm_itf_t itf, uint32_t timeout_ return ESP_FAIL; } + if (esp_tinyuf2_current_state() < TINYUF2_STATE_MOUNTED) { + ESP_LOGD(TAG, "USB is not connected"); + return ESP_ERR_INVALID_STATE; + } + if (!timeout_ticks) { // if no timeout - nonblocking mode int res = tud_cdc_n_write_flush(itf); if (!res) { diff --git a/components/usb/esp_tinyuf2/cdc/tusb_console.c b/components/usb/esp_tinyuf2/cdc/tusb_console.c index f6b6da1e6..6204ee4d2 100644 --- a/components/usb/esp_tinyuf2/cdc/tusb_console.c +++ b/components/usb/esp_tinyuf2/cdc/tusb_console.c @@ -99,7 +99,7 @@ static esp_err_t restore_std_streams(FILE **f_in, FILE **f_out, FILE **f_err) esp_err_t esp_tusb_init_console(int cdc_intf) { /* Registering TUSB at VFS */ - ESP_RETURN_ON_ERROR(esp_vfs_tusb_cdc_register(cdc_intf, NULL), TAG, ""); + ESP_RETURN_ON_ERROR(esp_vfs_tusb_cdc_register(cdc_intf, VFS_TUSB_PATH_DEFAULT), TAG, ""); ESP_RETURN_ON_ERROR(redirect_std_streams_to(&con.in, &con.out, &con.err, VFS_TUSB_PATH_DEFAULT), TAG, "Failed to redirect STD streams"); return ESP_OK; } @@ -107,6 +107,6 @@ esp_err_t esp_tusb_init_console(int cdc_intf) esp_err_t esp_tusb_deinit_console(int cdc_intf) { ESP_RETURN_ON_ERROR(restore_std_streams(&con.in, &con.out, &con.err), TAG, "Failed to restore STD streams"); - esp_vfs_tusb_cdc_unregister(NULL); + esp_vfs_tusb_cdc_unregister(VFS_TUSB_PATH_DEFAULT); return ESP_OK; } diff --git a/components/usb/esp_tinyuf2/esp_tinyuf2.c b/components/usb/esp_tinyuf2/esp_tinyuf2.c index 5163667dc..55f042960 100644 --- a/components/usb/esp_tinyuf2/esp_tinyuf2.c +++ b/components/usb/esp_tinyuf2/esp_tinyuf2.c @@ -7,25 +7,77 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_log.h" +#include "esp_pm.h" #include "esp_rom_gpio.h" #include "soc/soc_caps.h" #include "soc/gpio_pins.h" #include "soc/gpio_sig_map.h" +#include "soc/rtc_cntl_struct.h" #include "tusb.h" #include "esp_tinyuf2.h" #include "esp_private/usb_phy.h" #include "board_flash.h" #include "uf2.h" +#if SOC_USB_SERIAL_JTAG_SUPPORTED +#include "soc/usb_serial_jtag_reg.h" +#endif + #ifdef CONFIG_ENABLE_UF2_USB_CONSOLE #include "tusb_cdc_acm.h" #include "tusb_console.h" #endif const static char* TAG = "TUF2"; -static bool _if_init = false; +static tinyuf2_state_t _uf2_state = TINYUF2_STATE_NOT_INSTALLED; static TaskHandle_t _task_handle = NULL; +#ifdef CONFIG_PM_ENABLE +static esp_pm_lock_handle_t pm_locks_cpu_max = NULL; +#endif + +// Invoked when device is mounted +void tud_mount_cb(void) +{ +#ifdef CONFIG_ENABLE_UF2_USB_CONSOLE + ESP_LOGI(TAG, "USB Mounted"); + ESP_LOGI(TAG, "Enable USB console, log will be output to USB"); + tinyusb_config_cdcacm_t acm_cfg = { 0 }; // the configuration uses default values + tusb_cdc_acm_init(&acm_cfg); + esp_tusb_init_console(TINYUSB_CDC_ACM_0); +#endif + _uf2_state = TINYUF2_STATE_MOUNTED; + ESP_LOGI(TAG, "USB Mounted"); +} + +// Invoked when device is unmounted +void tud_umount_cb(void) +{ +#ifdef CONFIG_ENABLE_UF2_USB_CONSOLE + ESP_LOGI(TAG, "USB Unmounted"); + esp_tusb_deinit_console(TINYUSB_CDC_ACM_0); + //todo: tusb_cdc_acm_deinit() is not implemented +#endif + _uf2_state = TINYUF2_STATE_INSTALLED; + ESP_LOGI(TAG, "USB Unmounted"); +} + +// Invoked when usb bus is suspended +// remote_wakeup_en : if host allows us to perform remote wakeup +// USB Specs: Within 7ms, device must draw an average current less than 2.5 mA from bus +void tud_suspend_cb(bool remote_wakeup_en) +{ + _uf2_state = TINYUF2_STATE_INSTALLED; + ESP_LOGI(TAG, "USB Suspended"); +} + +// Invoked when usb bus is resumed +void tud_resume_cb(void) +{ + _uf2_state = TINYUF2_STATE_MOUNTED; + ESP_LOGI(TAG, "USB Resumed"); +} + // USB Device Driver task static void _usb_otg_phy_init(bool enable) { @@ -40,6 +92,16 @@ static void _usb_otg_phy_init(bool enable) phy_hdl = NULL; } if (enable) { +#if SOC_USB_SERIAL_JTAG_SUPPORTED + // due to the default usb function is usb-serial-jtag + // quick switch may cause the host not re-enumerate the device + // pull down DP to make host treat it as disconnect event + SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PAD_PULL_OVERRIDE); + CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_DP_PULLUP); + SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_DP_PULLDOWN); + CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_DP_PULLDOWN); + vTaskDelay(pdMS_TO_TICKS(10)); +#endif // Configure USB OTG PHY phy_conf.controller = USB_PHY_CTRL_OTG; usb_new_phy(&phy_conf, &phy_hdl); @@ -57,6 +119,7 @@ static void _usb_otg_phy_init(bool enable) static void usb_device_task(void* param) { (void) param; + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // RTOS forever loop while (1) { // put this thread to waiting state until there is new events @@ -83,6 +146,10 @@ static void usbd_vbus_enable(bool enable) static esp_err_t tinyusb_init() { +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_create(ESP_PM_CPU_FREQ_MAX, 0, "usb_otg", &pm_locks_cpu_max); + esp_pm_lock_acquire(pm_locks_cpu_max); +#endif _usb_otg_phy_init(true); // init device stack on configured roothub port // This should be called after scheduler/kernel is started. @@ -115,16 +182,19 @@ static esp_err_t tinyusb_deinit() _task_handle = NULL; tusb_teardown(); _usb_otg_phy_init(false); +#ifdef CONFIG_PM_ENABLE + esp_pm_lock_release(pm_locks_cpu_max); + esp_pm_lock_delete(pm_locks_cpu_max); +#endif return ESP_OK; } esp_err_t esp_tinyuf2_install(tinyuf2_ota_config_t *ota_config, tinyuf2_nvs_config_t *nvs_config) { - if (_if_init) { + if (_uf2_state != TINYUF2_STATE_NOT_INSTALLED) { ESP_LOGE(TAG, "Tinyuf2 already installed"); return ESP_ERR_INVALID_STATE; } - _if_init = true; if (!(ota_config || nvs_config)) { ESP_LOGE(TAG, "Invalid Parameter, config can’t be NULL"); @@ -148,12 +218,9 @@ esp_err_t esp_tinyuf2_install(tinyuf2_ota_config_t *ota_config, tinyuf2_nvs_conf uf2_init(); tinyusb_init(); -#ifdef CONFIG_ENABLE_UF2_USB_CONSOLE - ESP_LOGI(TAG, "Enable USB console, log will be output to USB"); - tinyusb_config_cdcacm_t acm_cfg = { 0 }; // the configuration uses default values - tusb_cdc_acm_init(&acm_cfg); - esp_tusb_init_console(TINYUSB_CDC_ACM_0); -#endif + + _uf2_state = TINYUF2_STATE_INSTALLED; + xTaskNotifyGive(_task_handle); ESP_LOGI(TAG, "UF2 Updater install succeed, Version: %d.%d.%d", ESP_TINYUF2_VER_MAJOR, ESP_TINYUF2_VER_MINOR, ESP_TINYUF2_VER_PATCH); return ESP_OK; @@ -161,14 +228,27 @@ esp_err_t esp_tinyuf2_install(tinyuf2_ota_config_t *ota_config, tinyuf2_nvs_conf esp_err_t esp_tinyuf2_uninstall(void) { - if (!_if_init) { + if (_uf2_state == TINYUF2_STATE_NOT_INSTALLED) { ESP_LOGE(TAG, "Tinyuf2 not installed"); return ESP_ERR_INVALID_STATE; } + +#ifdef CONFIG_ENABLE_UF2_USB_CONSOLE + if (_uf2_state == TINYUF2_STATE_MOUNTED) { + esp_tusb_deinit_console(TINYUSB_CDC_ACM_0); + //todo: tusb_cdc_acm_deinit() is not implemented + } +#endif + tinyusb_deinit(); board_flash_deinit(); board_flash_nvs_deinit(); ESP_LOGI(TAG, "UF2 Updater uninstall succeed"); - _if_init = false; + _uf2_state = TINYUF2_STATE_NOT_INSTALLED; return ESP_OK; } + +tinyuf2_state_t esp_tinyuf2_current_state(void) +{ + return _uf2_state; +} diff --git a/components/usb/esp_tinyuf2/esp_tinyuf2.h b/components/usb/esp_tinyuf2/esp_tinyuf2.h index 4821a1145..be7d73d8e 100644 --- a/components/usb/esp_tinyuf2/esp_tinyuf2.h +++ b/components/usb/esp_tinyuf2/esp_tinyuf2.h @@ -57,6 +57,12 @@ typedef struct { nvs_modified_cb_t modified_cb; /*! user callback called after uf2 update complete */ } tinyuf2_nvs_config_t; +typedef enum { + TINYUF2_STATE_NOT_INSTALLED = 0, + TINYUF2_STATE_INSTALLED, + TINYUF2_STATE_MOUNTED, +} tinyuf2_state_t; + /** * @brief Flashing app to specified partition through USB UF2 (Virtual USB Disk), * and support operate NVS partition through USB UF2 CONFIG.ini file. @@ -79,6 +85,13 @@ esp_err_t esp_tinyuf2_install(tinyuf2_ota_config_t *ota_config, tinyuf2_nvs_conf */ esp_err_t esp_tinyuf2_uninstall(void); +/** + * @brief Get tinyuf2 current state + * + * @return tinyuf2_state_t + */ +tinyuf2_state_t esp_tinyuf2_current_state(void); + #ifdef __cplusplus } #endif diff --git a/components/usb/esp_tinyuf2/idf_component.yml b/components/usb/esp_tinyuf2/idf_component.yml index dcba7e4c6..cf8676c44 100644 --- a/components/usb/esp_tinyuf2/idf_component.yml +++ b/components/usb/esp_tinyuf2/idf_component.yml @@ -1,4 +1,4 @@ -version: "0.2.1" +version: "0.2.2" targets: - esp32s2 - esp32s3 @@ -13,7 +13,7 @@ dependencies: cmake_utilities: "0.*" leeebo/esp-inih: "0.*" leeebo/tinyusb_src: - version: "~0.0.3" + version: ">=0.16.0~5" examples: - path: ../../../examples/usb/device/usb_uf2_ota diff --git a/components/usb/esp_tinyuf2/msc/msc.c b/components/usb/esp_tinyuf2/msc/msc.c index 029df481b..ea3fc15ed 100644 --- a/components/usb/esp_tinyuf2/msc/msc.c +++ b/components/usb/esp_tinyuf2/msc/msc.c @@ -40,33 +40,6 @@ static char *TAG = "MSC"; //--------------------------------------------------------------------+ // tinyusb callbacks //--------------------------------------------------------------------+ - -// Invoked when device is mounted -void tud_mount_cb(void) -{ - ESP_LOGI(__func__, ""); -} - -// Invoked when device is unmounted -void tud_umount_cb(void) -{ - ESP_LOGI(__func__, ""); -} - -// Invoked when usb bus is suspended -// remote_wakeup_en : if host allows us to perform remote wakeup -// USB Specs: Within 7ms, device must draw an average current less than 2.5 mA from bus -void tud_suspend_cb(bool remote_wakeup_en) -{ - ESP_LOGD(__func__, ""); -} - -// Invoked when usb bus is resumed -void tud_resume_cb(void) -{ - ESP_LOGD(__func__, ""); -} - // Invoked when received SCSI_CMD_INQUIRY // Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) diff --git a/components/usb/esp_tinyuf2/msc/tusb_config.h b/components/usb/esp_tinyuf2/tusb_config.h similarity index 100% rename from components/usb/esp_tinyuf2/msc/tusb_config.h rename to components/usb/esp_tinyuf2/tusb_config.h diff --git a/components/usb/esp_tinyuf2/msc/usb_descriptors.c b/components/usb/esp_tinyuf2/usb_descriptors.c similarity index 100% rename from components/usb/esp_tinyuf2/msc/usb_descriptors.c rename to components/usb/esp_tinyuf2/usb_descriptors.c diff --git a/examples/usb/device/usb_uf2_nvs/pytest_usb_uf2_nvs.py b/examples/usb/device/usb_uf2_nvs/pytest_usb_uf2_nvs.py index 60700f3cd..900c1674f 100644 --- a/examples/usb/device/usb_uf2_nvs/pytest_usb_uf2_nvs.py +++ b/examples/usb/device/usb_uf2_nvs/pytest_usb_uf2_nvs.py @@ -20,4 +20,4 @@ @pytest.mark.env('usb-otg_camera') def test_usb_uf2_nvs(dut: Dut)-> None: dut.expect(r'TUF2: UF2 Updater install succeed, Version: (\d+).(\d+).(\d+)', timeout=5) - dut.expect(r'tud_mount_cb:', timeout=10) + dut.expect(r'TUF2: USB Mounted', timeout=10)