From 2330e9992f46e265a34afafd1b14858d993e9621 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Thu, 17 Mar 2022 04:27:27 +0200 Subject: [PATCH] Fix reboot into download from TinyUSB on ESP32-S3 Requires manual reboot back into the new firmware after flashing has finished --- cores/esp32/esp32-hal-tinyusb.c | 182 ++++++++++++++++++++------------ 1 file changed, 115 insertions(+), 67 deletions(-) diff --git a/cores/esp32/esp32-hal-tinyusb.c b/cores/esp32/esp32-hal-tinyusb.c index 04edd77fa19..ab66e3d8e28 100644 --- a/cores/esp32/esp32-hal-tinyusb.c +++ b/cores/esp32/esp32-hal-tinyusb.c @@ -20,6 +20,7 @@ #include "hal/usb_hal.h" #include "hal/gpio_ll.h" +#include "hal/usb_serial_jtag_ll.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -376,6 +377,120 @@ __attribute__ ((weak)) int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_ static bool usb_persist_enabled = false; static restart_type_t usb_persist_mode = RESTART_NO_PERSIST; +#if CONFIG_IDF_TARGET_ESP32S3 + +static void hw_cdc_reset_handler(void *arg) { + portBASE_TYPE xTaskWoken = 0; + uint32_t usbjtag_intr_status = usb_serial_jtag_ll_get_intsts_mask(); + usb_serial_jtag_ll_clr_intsts_mask(usbjtag_intr_status); + + if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_BUS_RESET) { + xSemaphoreGiveFromISR((xSemaphoreHandle)arg, &xTaskWoken); + } + + if (xTaskWoken == pdTRUE) { + portYIELD_FROM_ISR(); + } +} + +static void usb_switch_to_cdc_jtag(){ + // Disable USB-OTG + periph_module_reset(PERIPH_USB_MODULE); + //periph_module_enable(PERIPH_USB_MODULE); + periph_module_disable(PERIPH_USB_MODULE); + + // Switch to hardware CDC+JTAG + CLEAR_PERI_REG_MASK(RTC_CNTL_USB_CONF_REG, (RTC_CNTL_SW_HW_USB_PHY_SEL|RTC_CNTL_SW_USB_PHY_SEL|RTC_CNTL_USB_PAD_ENABLE)); + + // Do not use external PHY + CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PHY_SEL); + + // Release GPIO pins from CDC+JTAG + CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE); + + // Force the host to re-enumerate (BUS_RESET) + pinMode(USBPHY_DM_NUM, OUTPUT_OPEN_DRAIN); + pinMode(USBPHY_DP_NUM, OUTPUT_OPEN_DRAIN); + digitalWrite(USBPHY_DM_NUM, LOW); + digitalWrite(USBPHY_DP_NUM, LOW); + + // Initialize CDC+JTAG ISR to listen for BUS_RESET + usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK); + usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_LL_INTR_MASK); + usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_BUS_RESET); + intr_handle_t intr_handle = NULL; + xSemaphoreHandle reset_sem = xSemaphoreCreateBinary(); + if(reset_sem){ + if(esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, 0, hw_cdc_reset_handler, reset_sem, &intr_handle) != ESP_OK){ + vSemaphoreDelete(reset_sem); + reset_sem = NULL; + log_e("HW USB CDC failed to init interrupts"); + } + } else { + log_e("reset_sem init failed"); + } + + // Connect GPIOs to integrated CDC+JTAG + SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE); + + // Wait for BUS_RESET to give us back the semaphore + if(reset_sem){ + if(xSemaphoreTake(reset_sem, 1000 / portTICK_PERIOD_MS) != pdPASS){ + log_e("reset_sem timeout"); + } + usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK); + esp_intr_free(intr_handle); + vSemaphoreDelete(reset_sem); + } +} +#endif + +static void IRAM_ATTR usb_persist_shutdown_handler(void) +{ + if(usb_persist_mode != RESTART_NO_PERSIST){ + if (usb_persist_enabled) { + usb_dc_prepare_persist(); + } + if (usb_persist_mode == RESTART_BOOTLOADER) { + //USB CDC Download + if (usb_persist_enabled) { + chip_usb_set_persist_flags(USBDC_PERSIST_ENA); +#if CONFIG_IDF_TARGET_ESP32S2 + } else { + periph_module_reset(PERIPH_USB_MODULE); + periph_module_enable(PERIPH_USB_MODULE); +#endif + } + REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); + } else if (usb_persist_mode == RESTART_BOOTLOADER_DFU) { + //DFU Download +#if CONFIG_IDF_TARGET_ESP32S2 + // Reset USB Core + USB0.grstctl |= USB_CSFTRST; + while ((USB0.grstctl & USB_CSFTRST) == USB_CSFTRST){} +#endif + chip_usb_set_persist_flags(USBDC_BOOT_DFU); + REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); + } else if (usb_persist_enabled) { + //USB Persist reboot + chip_usb_set_persist_flags(USBDC_PERSIST_ENA); + } + } +} + +void usb_persist_restart(restart_type_t mode) +{ + if (mode < RESTART_TYPE_MAX && esp_register_shutdown_handler(usb_persist_shutdown_handler) == ESP_OK) { + usb_persist_mode = mode; +#if CONFIG_IDF_TARGET_ESP32S3 + if (mode == RESTART_BOOTLOADER) { + usb_switch_to_cdc_jtag(); + } +#endif + esp_restart(); + } +} + static bool tinyusb_reserve_in_endpoint(uint8_t endpoint){ if(endpoint > 6 || (tinyusb_endpoints.in & BIT(endpoint)) != 0){ return false; @@ -521,60 +636,6 @@ static void tinyusb_apply_device_config(tinyusb_device_config_t *config){ tinyusb_device_descriptor.bDeviceProtocol = config->usb_protocol; } -static void IRAM_ATTR usb_persist_shutdown_handler(void) -{ - if(usb_persist_mode != RESTART_NO_PERSIST){ - if (usb_persist_enabled) { - usb_dc_prepare_persist(); - } - if (usb_persist_mode == RESTART_BOOTLOADER) { - //USB CDC Download - if (usb_persist_enabled) { - chip_usb_set_persist_flags(USBDC_PERSIST_ENA); - } else { -#if CONFIG_IDF_TARGET_ESP32S3 - /* - * This currently does not work! - * Integrated CDC+JTAG refuses to communicate, once into Download mode - */ - // Disable USB-OTG - periph_module_reset(PERIPH_USB_MODULE); - //periph_module_enable(PERIPH_USB_MODULE); - periph_module_disable(PERIPH_USB_MODULE); - // Switch to hardware CDC+JTAG - REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, (RTC_CNTL_SW_HW_USB_PHY_SEL|RTC_CNTL_SW_USB_PHY_SEL)); - // Release GPIO pins from CDC+JTAG - CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE); - // Force the host to re-enumerate (BUS_RESET) - pinMode(USBPHY_DM_NUM, OUTPUT_OPEN_DRAIN); - pinMode(USBPHY_DP_NUM, OUTPUT_OPEN_DRAIN); - digitalWrite(USBPHY_DM_NUM, LOW); - digitalWrite(USBPHY_DP_NUM, LOW); - delay(20); - // Connect GPIOs to integrated CDC+JTAG - SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE); - // Do not use external PHY - CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PHY_SEL); -#else - periph_module_reset(PERIPH_USB_MODULE); - periph_module_enable(PERIPH_USB_MODULE); -#endif - } - REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); - } else if (usb_persist_mode == RESTART_BOOTLOADER_DFU) { - //DFU Download - // Reset USB Core - USB0.grstctl |= USB_CSFTRST; - while ((USB0.grstctl & USB_CSFTRST) == USB_CSFTRST){} - chip_usb_set_persist_flags(USBDC_BOOT_DFU); - REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT); - } else if (usb_persist_enabled) { - //USB Persist reboot - chip_usb_set_persist_flags(USBDC_PERSIST_ENA); - } - } -} - // USB Device Driver task // This top level thread processes all usb events and invokes callbacks static void usb_device_task(void *param) { @@ -638,11 +699,6 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) { periph_module_enable(PERIPH_USB_MODULE); } - if (esp_register_shutdown_handler(usb_persist_shutdown_handler) != ESP_OK) { - tinyusb_is_initialized = false; - return ESP_FAIL; - } - tinyusb_config_t tusb_cfg = { .external_phy = false // In the most cases you need to use a `false` value }; @@ -655,14 +711,6 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) { return err; } -void usb_persist_restart(restart_type_t mode) -{ - if (mode < RESTART_TYPE_MAX) { - usb_persist_mode = mode; - esp_restart(); - } -} - uint8_t tinyusb_add_string_descriptor(const char * str){ if(str == NULL || tinyusb_string_descriptor_len >= MAX_STRING_DESCRIPTORS){ return 0;