espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.67k stars 7.29k forks source link

ESP32-S3 can not exit from USB Serial/JTAG bootloader (IDFGH-12237) #13287

Open xyzzy42 opened 8 months ago

xyzzy42 commented 8 months ago

Answers checklist.

IDF version.

v5.3-dev-0-g8171b22c40

Espressif SoC revision.

ESP32-S3 version 0.2

Operating System used.

Linux

How did you build your project?

Command line with idf.py

If you are using Windows, please specify command line type.

None

Development Kit.

Custom Board

Power Supply used.

Battery

What is the expected behavior?

Reset from Bootloader DOWNLOAD(USB/UART0) mode into normal SPI boot mode.

What is the actual behavior?

Reset always returns to DOWNLOAD(USB/UART0) mode.

Steps to reproduce.

  1. Pull GPIO0 and pulse CHIP_PU pin to enter bootloader.
  2. Use esptool.py to use RTS/DTR sequence on Espressif USB JTAG/serial debug unit to reset.

Alternatively, replace step 1 with software triggered bootloader reset:

REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
esp_restart();

Debug Logs.

ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0xc (RTC_SW_CPU_RST),boot:0x21 (DOWNLOAD(USB/UART0))
Saved PC:0x4038367a
waiting for download
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x15 (USB_UART_CHIP_RESET),boot:0x21 (DOWNLOAD(USB/UART0))
Saved PC:0x40041a76
waiting for download

First reboot is triggered via software using REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);esp_restart();. Second reboot is triggered via esptool. GPIO0 is not held low. But boot flags still do not have 0x08 bit set.

More Information.

If a device has no external reset button and permanently attached battery, it is impossible to exit bootloader!

igrr commented 8 months ago

As you found, the hardware behavior is that the boot mode set by the strapping pins can't be overridden by USB_SERIAL_JTAG. This is because the strapping pins are only latched on power-on reset, RTC WDT reset, as well as brownout/SWD reset (i think). They are not latched again on the reset triggered by the USB_SERIAL_JTAG.

It's probably not something that ESP-IDF project can do anything about, as the reset behavior is determined at the hardware level.

However, I am not sure I understand the exact usage scenario:

If you have already used GPIO0 and CHIP_PU, it seems like you have a connection to those pins in the factory. Can you toggle CHIP_PU again after flashing is done? Seems like that is the simplest solution.

Alternatively, don't use CHIP_PU and GPIO0 to enter the download mode in the first place, and use USB_SERIAL_JTAG instead. In this case, it should be possible to get back to the flash boot mode once flashing is complete.

xyzzy42 commented 8 months ago

This behavior is also observed when entering bootloader via software control, with:

    REG_WRITE(RTC_CNTL_OPTION1_REG, RTC_CNTL_FORCE_DOWNLOAD_BOOT);
    esp_restart();

In this case bootloader is entered without access to CHIP_PU and GPIO0.

It is also possible to enter bootloader by holding GPIO0 low and applying power to a dead battery. But once the battery is charged, there is no way to exit the bootloader other than to wait for the battery to fully discharge again. This make take hours or days!

We have built a sealed, wearable, device with no access to CHIP_PU nor ability to disconnect the battery. But we are also still doing software development, and might need to use the bootloader to flash new code. While the bootloader can be entered to reflash the software, it is not possible to exit the bootloader.

Documentation states that it is possible for JTAG/Serial device to reset into normal boot. ESP32-S3 Technical Reference Manual, §33.3.2:

Aside from general-purpose communication, the CDC-ACM interface also can be used to reset the ESP32-S3 and optionally make it go into download mode in order to flash new firmware. Note that if the download mode flag is set when the ESP32-S3 is reset, the ESP32-S3 will reboot into download mode. When this flag is cleared and the chip is reset, the ESP32-S3 will boot from flash.

I have also observed that if the ESP32-S3 ROM bootloader is configured to use USB-OTG instead of USB Serial/JTAG, then it can exit bootloader when a reset is trigger via the USB-OTG CDC interface.

Jason2866 commented 8 months ago

Tried this https://esp32.com/viewtopic.php?t=28967#p108694

xyzzy42 commented 8 months ago

It seems that only applies to entering bootloader via software. If it is entered via GPIO0 then there still is no way to exit without discharging the battery.

I did test that, but like the comments seem to indicate, it does not enter the bootloader. It reboots from user code into user code. I don't see how it's related to exiting the bootloader once the bootloader is entered.

That code is also interesting in other ways:

    // Maybe we need to consider tweaking these?
    chip_usb_set_persist_flags( 0 );  //NOT USBDC_PERSIST_ENA (1<<31)

    // We **must** unset this, otherwise we'll end up back in the bootloader.
    REG_WRITE(RTC_CNTL_OPTION1_REG, 0);
    void software_reset( uint32_t x );

But then if we look at ESP-IDF:

  * @brief Software Reset digital core.
  *
  * It is not recommended to use this function in esp-idf, use
  * esp_restart() instead.
  *
  * @param  None
  *
  * @return None
  */
void software_reset(void);

So should we use software_reset or not use software_reset? And does software_reset() have undocumented uint32_t argument? Because code in esp32 forum thinks it has one, but ESP-IDF header does not have one.

xyzzy42 commented 8 months ago

I have also observed that if the ESP32-S3 ROM bootloader is configured to use USB-OTG instead of USB Serial/JTAG, then it can exit bootloader when a reset is trigger via the USB-OTG CDC interface.

It turns out this isn't exactly correct. If the bootloader is entered via software setting RTC_CNTL_FORCE_DOWNLOAD_BOOT, and the bootloader uses USB-OTG mode, then it's possible to exit the bootloader via RTS/DTR on the USB-OTG device. But if the bootloader is entered via GPIO0 pull-down on reset, then RTS/DTR will not exit the bootloader, for both USB-OTG or USB-JTAG (selected via eFuse USB_PHY_SEL).

This is contrary to what esptool code does and what @radimkarnis said in https://github.com/espressif/esptool/pull/757#issuecomment-1186923741. Perhaps that statement, from 2022, was correct for ESP32-C3 but is no longer correct for ESP32-S3?

So the bugs here are:

xyzzy42 commented 8 months ago

only latched on power-on reset, RTC WDT reset, as well as brownout/SWD reset (i think).

This gave me an idea, maybe the bootloader can be escaped by triggering a WDT reset. The TRM §8.1 agrees, "During power-on-reset, RTC watchdog reset, brownout reset, analog super watchdog reset, and crystal clock glitch detection reset …"

However, this also appears to not work as documented. An RTC WDT system reset did not restrap the pins:

ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x9 (RTCWDT_SYS_RST),boot:0x21 (DOWNLOAD(USB/UART0))
Saved PC:0x40378cae
waiting for download

Nor a RTC WDT RTC reset:

ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x10 (RTCWDT_RTC_RST),boot:0x21 (DOWNLOAD(USB/UART0))
waiting for download

Nor does a Timer Group 0 WDT reset (wasn't in the list, but I tried anyway):

Build:Mar 27 2021
rst:0x7 (TG0WDT_SYS_RST),boot:0x21 (DOWNLOAD(USB/UART0))
Saved PC:0x40378cae
waiting for download

I can't see to figure out how to make the SWD trigger in the bootloader. I disabled the auto-feed and the SWD interrupt, but it still isn't triggering. If the SWD can trigger a chip reset and not just a system reset, then maybe it could do it.