Skip to content

Commit 2330e99

Browse files
committed
Fix reboot into download from TinyUSB on ESP32-S3
Requires manual reboot back into the new firmware after flashing has finished
1 parent 4866f93 commit 2330e99

File tree

1 file changed

+115
-67
lines changed

1 file changed

+115
-67
lines changed

Diff for: cores/esp32/esp32-hal-tinyusb.c

+115-67
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "hal/usb_hal.h"
2222
#include "hal/gpio_ll.h"
23+
#include "hal/usb_serial_jtag_ll.h"
2324

2425
#include "freertos/FreeRTOS.h"
2526
#include "freertos/task.h"
@@ -376,6 +377,120 @@ __attribute__ ((weak)) int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_
376377
static bool usb_persist_enabled = false;
377378
static restart_type_t usb_persist_mode = RESTART_NO_PERSIST;
378379

380+
#if CONFIG_IDF_TARGET_ESP32S3
381+
382+
static void hw_cdc_reset_handler(void *arg) {
383+
portBASE_TYPE xTaskWoken = 0;
384+
uint32_t usbjtag_intr_status = usb_serial_jtag_ll_get_intsts_mask();
385+
usb_serial_jtag_ll_clr_intsts_mask(usbjtag_intr_status);
386+
387+
if (usbjtag_intr_status & USB_SERIAL_JTAG_INTR_BUS_RESET) {
388+
xSemaphoreGiveFromISR((xSemaphoreHandle)arg, &xTaskWoken);
389+
}
390+
391+
if (xTaskWoken == pdTRUE) {
392+
portYIELD_FROM_ISR();
393+
}
394+
}
395+
396+
static void usb_switch_to_cdc_jtag(){
397+
// Disable USB-OTG
398+
periph_module_reset(PERIPH_USB_MODULE);
399+
//periph_module_enable(PERIPH_USB_MODULE);
400+
periph_module_disable(PERIPH_USB_MODULE);
401+
402+
// Switch to hardware CDC+JTAG
403+
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));
404+
405+
// Do not use external PHY
406+
CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PHY_SEL);
407+
408+
// Release GPIO pins from CDC+JTAG
409+
CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE);
410+
411+
// Force the host to re-enumerate (BUS_RESET)
412+
pinMode(USBPHY_DM_NUM, OUTPUT_OPEN_DRAIN);
413+
pinMode(USBPHY_DP_NUM, OUTPUT_OPEN_DRAIN);
414+
digitalWrite(USBPHY_DM_NUM, LOW);
415+
digitalWrite(USBPHY_DP_NUM, LOW);
416+
417+
// Initialize CDC+JTAG ISR to listen for BUS_RESET
418+
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK);
419+
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_LL_INTR_MASK);
420+
usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_BUS_RESET);
421+
intr_handle_t intr_handle = NULL;
422+
xSemaphoreHandle reset_sem = xSemaphoreCreateBinary();
423+
if(reset_sem){
424+
if(esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, 0, hw_cdc_reset_handler, reset_sem, &intr_handle) != ESP_OK){
425+
vSemaphoreDelete(reset_sem);
426+
reset_sem = NULL;
427+
log_e("HW USB CDC failed to init interrupts");
428+
}
429+
} else {
430+
log_e("reset_sem init failed");
431+
}
432+
433+
// Connect GPIOs to integrated CDC+JTAG
434+
SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE);
435+
436+
// Wait for BUS_RESET to give us back the semaphore
437+
if(reset_sem){
438+
if(xSemaphoreTake(reset_sem, 1000 / portTICK_PERIOD_MS) != pdPASS){
439+
log_e("reset_sem timeout");
440+
}
441+
usb_serial_jtag_ll_disable_intr_mask(USB_SERIAL_JTAG_LL_INTR_MASK);
442+
esp_intr_free(intr_handle);
443+
vSemaphoreDelete(reset_sem);
444+
}
445+
}
446+
#endif
447+
448+
static void IRAM_ATTR usb_persist_shutdown_handler(void)
449+
{
450+
if(usb_persist_mode != RESTART_NO_PERSIST){
451+
if (usb_persist_enabled) {
452+
usb_dc_prepare_persist();
453+
}
454+
if (usb_persist_mode == RESTART_BOOTLOADER) {
455+
//USB CDC Download
456+
if (usb_persist_enabled) {
457+
chip_usb_set_persist_flags(USBDC_PERSIST_ENA);
458+
#if CONFIG_IDF_TARGET_ESP32S2
459+
} else {
460+
periph_module_reset(PERIPH_USB_MODULE);
461+
periph_module_enable(PERIPH_USB_MODULE);
462+
#endif
463+
}
464+
REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
465+
} else if (usb_persist_mode == RESTART_BOOTLOADER_DFU) {
466+
//DFU Download
467+
#if CONFIG_IDF_TARGET_ESP32S2
468+
// Reset USB Core
469+
USB0.grstctl |= USB_CSFTRST;
470+
while ((USB0.grstctl & USB_CSFTRST) == USB_CSFTRST){}
471+
#endif
472+
chip_usb_set_persist_flags(USBDC_BOOT_DFU);
473+
REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
474+
} else if (usb_persist_enabled) {
475+
//USB Persist reboot
476+
chip_usb_set_persist_flags(USBDC_PERSIST_ENA);
477+
}
478+
}
479+
}
480+
481+
void usb_persist_restart(restart_type_t mode)
482+
{
483+
if (mode < RESTART_TYPE_MAX && esp_register_shutdown_handler(usb_persist_shutdown_handler) == ESP_OK) {
484+
usb_persist_mode = mode;
485+
#if CONFIG_IDF_TARGET_ESP32S3
486+
if (mode == RESTART_BOOTLOADER) {
487+
usb_switch_to_cdc_jtag();
488+
}
489+
#endif
490+
esp_restart();
491+
}
492+
}
493+
379494
static bool tinyusb_reserve_in_endpoint(uint8_t endpoint){
380495
if(endpoint > 6 || (tinyusb_endpoints.in & BIT(endpoint)) != 0){
381496
return false;
@@ -521,60 +636,6 @@ static void tinyusb_apply_device_config(tinyusb_device_config_t *config){
521636
tinyusb_device_descriptor.bDeviceProtocol = config->usb_protocol;
522637
}
523638

524-
static void IRAM_ATTR usb_persist_shutdown_handler(void)
525-
{
526-
if(usb_persist_mode != RESTART_NO_PERSIST){
527-
if (usb_persist_enabled) {
528-
usb_dc_prepare_persist();
529-
}
530-
if (usb_persist_mode == RESTART_BOOTLOADER) {
531-
//USB CDC Download
532-
if (usb_persist_enabled) {
533-
chip_usb_set_persist_flags(USBDC_PERSIST_ENA);
534-
} else {
535-
#if CONFIG_IDF_TARGET_ESP32S3
536-
/*
537-
* This currently does not work!
538-
* Integrated CDC+JTAG refuses to communicate, once into Download mode
539-
*/
540-
// Disable USB-OTG
541-
periph_module_reset(PERIPH_USB_MODULE);
542-
//periph_module_enable(PERIPH_USB_MODULE);
543-
periph_module_disable(PERIPH_USB_MODULE);
544-
// Switch to hardware CDC+JTAG
545-
REG_CLR_BIT(RTC_CNTL_USB_CONF_REG, (RTC_CNTL_SW_HW_USB_PHY_SEL|RTC_CNTL_SW_USB_PHY_SEL));
546-
// Release GPIO pins from CDC+JTAG
547-
CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE);
548-
// Force the host to re-enumerate (BUS_RESET)
549-
pinMode(USBPHY_DM_NUM, OUTPUT_OPEN_DRAIN);
550-
pinMode(USBPHY_DP_NUM, OUTPUT_OPEN_DRAIN);
551-
digitalWrite(USBPHY_DM_NUM, LOW);
552-
digitalWrite(USBPHY_DP_NUM, LOW);
553-
delay(20);
554-
// Connect GPIOs to integrated CDC+JTAG
555-
SET_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_USB_PAD_ENABLE);
556-
// Do not use external PHY
557-
CLEAR_PERI_REG_MASK(USB_SERIAL_JTAG_CONF0_REG, USB_SERIAL_JTAG_PHY_SEL);
558-
#else
559-
periph_module_reset(PERIPH_USB_MODULE);
560-
periph_module_enable(PERIPH_USB_MODULE);
561-
#endif
562-
}
563-
REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
564-
} else if (usb_persist_mode == RESTART_BOOTLOADER_DFU) {
565-
//DFU Download
566-
// Reset USB Core
567-
USB0.grstctl |= USB_CSFTRST;
568-
while ((USB0.grstctl & USB_CSFTRST) == USB_CSFTRST){}
569-
chip_usb_set_persist_flags(USBDC_BOOT_DFU);
570-
REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
571-
} else if (usb_persist_enabled) {
572-
//USB Persist reboot
573-
chip_usb_set_persist_flags(USBDC_PERSIST_ENA);
574-
}
575-
}
576-
}
577-
578639
// USB Device Driver task
579640
// This top level thread processes all usb events and invokes callbacks
580641
static void usb_device_task(void *param) {
@@ -638,11 +699,6 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
638699
periph_module_enable(PERIPH_USB_MODULE);
639700
}
640701

641-
if (esp_register_shutdown_handler(usb_persist_shutdown_handler) != ESP_OK) {
642-
tinyusb_is_initialized = false;
643-
return ESP_FAIL;
644-
}
645-
646702
tinyusb_config_t tusb_cfg = {
647703
.external_phy = false // In the most cases you need to use a `false` value
648704
};
@@ -655,14 +711,6 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
655711
return err;
656712
}
657713

658-
void usb_persist_restart(restart_type_t mode)
659-
{
660-
if (mode < RESTART_TYPE_MAX) {
661-
usb_persist_mode = mode;
662-
esp_restart();
663-
}
664-
}
665-
666714
uint8_t tinyusb_add_string_descriptor(const char * str){
667715
if(str == NULL || tinyusb_string_descriptor_len >= MAX_STRING_DESCRIPTORS){
668716
return 0;

0 commit comments

Comments
 (0)