mirror of
https://github.com/espressif/esptool.git
synced 2025-10-22 07:51:36 +08:00
fix(usb_resets): Fix resetting in USB-OTG and USB-Serial/JTAG modes
Closes https://github.com/espressif/esptool/issues/970
This commit is contained in:
@@ -297,6 +297,8 @@ target_esp32s2_usbcdc:
|
|||||||
extends: .target_esptool_test
|
extends: .target_esptool_test
|
||||||
tags:
|
tags:
|
||||||
- esptool_esp32s2_cdc_target
|
- esptool_esp32s2_cdc_target
|
||||||
|
variables:
|
||||||
|
ESPTOOL_TEST_USB_OTG: "1"
|
||||||
script:
|
script:
|
||||||
- coverage run --parallel-mode -m pytest ${CI_PROJECT_DIR}/test/test_esptool.py --port /dev/serial_ports/ESP32S2_USBCDC --chip esp32s2 --baud 115200
|
- coverage run --parallel-mode -m pytest ${CI_PROJECT_DIR}/test/test_esptool.py --port /dev/serial_ports/ESP32S2_USBCDC --chip esp32s2 --baud 115200
|
||||||
|
|
||||||
@@ -347,6 +349,8 @@ target_esp32s3_usbcdc:
|
|||||||
extends: .target_esptool_test
|
extends: .target_esptool_test
|
||||||
tags:
|
tags:
|
||||||
- esptool_esp32s3_cdc_target
|
- esptool_esp32s3_cdc_target
|
||||||
|
variables:
|
||||||
|
ESPTOOL_TEST_USB_OTG: "1"
|
||||||
script:
|
script:
|
||||||
- coverage run --parallel-mode -m pytest ${CI_PROJECT_DIR}/test/test_esptool.py --port /dev/serial_ports/ESP32S3_USBCDC --chip esp32s3 --baud 115200
|
- coverage run --parallel-mode -m pytest ${CI_PROJECT_DIR}/test/test_esptool.py --port /dev/serial_ports/ESP32S3_USBCDC --chip esp32s3 --baud 115200
|
||||||
|
|
||||||
|
@@ -31,8 +31,8 @@ The ``--after`` argument allows you to specify whether the chip should be reset
|
|||||||
|
|
||||||
.. list::
|
.. list::
|
||||||
|
|
||||||
* ``--after hard_reset`` is the default. The DTR serial control line is used to reset the chip into a normal boot sequence.
|
* ``--after hard_reset`` is the default. The RTS serial control line is used to reset the chip into a normal boot sequence.
|
||||||
:esp8266:* ``--after soft_reset`` This runs the user firmware, but any subsequent reset will return to the serial bootloader. This was the reset behaviour in esptool v1.x.
|
:esp8266: * ``--after soft_reset`` runs the user firmware, but any subsequent reset will return to the serial bootloader. This was the reset behaviour in esptool v1.x.
|
||||||
* ``--after no_reset`` leaves the chip in the serial bootloader, no reset is performed.
|
* ``--after no_reset`` leaves the chip in the serial bootloader, no reset is performed.
|
||||||
* ``--after no_reset_stub`` leaves the chip in the stub bootloader, no reset is performed.
|
* ``--after no_reset_stub`` leaves the chip in the stub bootloader, no reset is performed.
|
||||||
|
|
||||||
|
@@ -18,6 +18,7 @@ __all__ = [
|
|||||||
"merge_bin",
|
"merge_bin",
|
||||||
"read_flash",
|
"read_flash",
|
||||||
"read_flash_status",
|
"read_flash_status",
|
||||||
|
"read_flash_sfdp",
|
||||||
"read_mac",
|
"read_mac",
|
||||||
"read_mem",
|
"read_mem",
|
||||||
"run",
|
"run",
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
|
# SPDX-FileCopyrightText: 2014-2024 Fredrik Ahlberg, Angus Gratton,
|
||||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
@@ -63,6 +63,12 @@ class ESP32C2ROM(ESP32C3ROM):
|
|||||||
[0x4037C000, 0x403C0000, "IRAM"],
|
[0x4037C000, 0x403C0000, "IRAM"],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
RTCCNTL_BASE_REG = 0x60008000
|
||||||
|
RTC_CNTL_WDTCONFIG0_REG = RTCCNTL_BASE_REG + 0x0084
|
||||||
|
RTC_CNTL_WDTCONFIG1_REG = RTCCNTL_BASE_REG + 0x0088
|
||||||
|
RTC_CNTL_WDTWPROTECT_REG = RTCCNTL_BASE_REG + 0x009C
|
||||||
|
RTC_CNTL_WDT_WKEY = 0x50D83AA1
|
||||||
|
|
||||||
UF2_FAMILY_ID = 0x2B88D29C
|
UF2_FAMILY_ID = 0x2B88D29C
|
||||||
|
|
||||||
KEY_PURPOSES: Dict[int, str] = {}
|
KEY_PURPOSES: Dict[int, str] = {}
|
||||||
@@ -130,6 +136,9 @@ class ESP32C2ROM(ESP32C3ROM):
|
|||||||
self.stub_is_disabled = True
|
self.stub_is_disabled = True
|
||||||
self.IS_STUB = False
|
self.IS_STUB = False
|
||||||
|
|
||||||
|
def hard_reset(self):
|
||||||
|
ESPLoader.hard_reset(self)
|
||||||
|
|
||||||
""" Try to read (encryption key) and check if it is valid """
|
""" Try to read (encryption key) and check if it is valid """
|
||||||
|
|
||||||
def is_flash_encryption_key_valid(self):
|
def is_flash_encryption_key_valid(self):
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
|
# SPDX-FileCopyrightText: 2014-2024 Fredrik Ahlberg, Angus Gratton,
|
||||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
@@ -83,6 +83,7 @@ class ESP32C3ROM(ESP32ROM):
|
|||||||
RTC_CNTL_SWD_WKEY = 0x8F1D312A
|
RTC_CNTL_SWD_WKEY = 0x8F1D312A
|
||||||
|
|
||||||
RTC_CNTL_WDTCONFIG0_REG = RTCCNTL_BASE_REG + 0x0090
|
RTC_CNTL_WDTCONFIG0_REG = RTCCNTL_BASE_REG + 0x0090
|
||||||
|
RTC_CNTL_WDTCONFIG1_REG = RTCCNTL_BASE_REG + 0x0094
|
||||||
RTC_CNTL_WDTWPROTECT_REG = RTCCNTL_BASE_REG + 0x00A8
|
RTC_CNTL_WDTWPROTECT_REG = RTCCNTL_BASE_REG + 0x00A8
|
||||||
RTC_CNTL_WDT_WKEY = 0x50D83AA1
|
RTC_CNTL_WDT_WKEY = 0x50D83AA1
|
||||||
|
|
||||||
@@ -252,6 +253,21 @@ class ESP32C3ROM(ESP32ROM):
|
|||||||
if not self.sync_stub_detected: # Don't run if stub is reused
|
if not self.sync_stub_detected: # Don't run if stub is reused
|
||||||
self.disable_watchdogs()
|
self.disable_watchdogs()
|
||||||
|
|
||||||
|
def hard_reset(self):
|
||||||
|
if self.uses_usb_jtag_serial():
|
||||||
|
self.rtc_wdt_reset()
|
||||||
|
else:
|
||||||
|
ESPLoader.hard_reset(self)
|
||||||
|
|
||||||
|
def rtc_wdt_reset(self):
|
||||||
|
print("Hard resetting with RTC WDT...")
|
||||||
|
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, self.RTC_CNTL_WDT_WKEY) # unlock
|
||||||
|
self.write_reg(self.RTC_CNTL_WDTCONFIG1_REG, 5000) # set WDT timeout
|
||||||
|
self.write_reg(
|
||||||
|
self.RTC_CNTL_WDTCONFIG0_REG, (1 << 31) | (5 << 28) | (1 << 8) | 2
|
||||||
|
) # enable WDT
|
||||||
|
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, 0) # lock
|
||||||
|
|
||||||
def check_spi_connection(self, spi_connection):
|
def check_spi_connection(self, spi_connection):
|
||||||
if not set(spi_connection).issubset(set(range(0, 22))):
|
if not set(spi_connection).issubset(set(range(0, 22))):
|
||||||
raise FatalError("SPI Pin numbers must be in the range 0-21.")
|
raise FatalError("SPI Pin numbers must be in the range 0-21.")
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# SPDX-FileCopyrightText: 2022 Fredrik Ahlberg, Angus Gratton,
|
# SPDX-FileCopyrightText: 2024 Fredrik Ahlberg, Angus Gratton,
|
||||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
@@ -72,6 +72,7 @@ class ESP32C6ROM(ESP32C3ROM):
|
|||||||
|
|
||||||
DR_REG_LP_WDT_BASE = 0x600B1C00
|
DR_REG_LP_WDT_BASE = 0x600B1C00
|
||||||
RTC_CNTL_WDTCONFIG0_REG = DR_REG_LP_WDT_BASE + 0x0 # LP_WDT_RWDT_CONFIG0_REG
|
RTC_CNTL_WDTCONFIG0_REG = DR_REG_LP_WDT_BASE + 0x0 # LP_WDT_RWDT_CONFIG0_REG
|
||||||
|
RTC_CNTL_WDTCONFIG1_REG = DR_REG_LP_WDT_BASE + 0x0004 # LP_WDT_RWDT_CONFIG1_REG
|
||||||
RTC_CNTL_WDTWPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0018 # LP_WDT_RWDT_WPROTECT_REG
|
RTC_CNTL_WDTWPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0018 # LP_WDT_RWDT_WPROTECT_REG
|
||||||
|
|
||||||
RTC_CNTL_SWD_CONF_REG = DR_REG_LP_WDT_BASE + 0x001C # LP_WDT_SWD_CONFIG_REG
|
RTC_CNTL_SWD_CONF_REG = DR_REG_LP_WDT_BASE + 0x001C # LP_WDT_SWD_CONFIG_REG
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# SPDX-FileCopyrightText: 2022 Fredrik Ahlberg, Angus Gratton,
|
# SPDX-FileCopyrightText: 2024 Fredrik Ahlberg, Angus Gratton,
|
||||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
from .esp32c6 import ESP32C6ROM
|
from .esp32c6 import ESP32C6ROM
|
||||||
|
from ..loader import ESPLoader
|
||||||
from ..util import FatalError
|
from ..util import FatalError
|
||||||
|
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ class ESP32H2ROM(ESP32C6ROM):
|
|||||||
|
|
||||||
DR_REG_LP_WDT_BASE = 0x600B1C00
|
DR_REG_LP_WDT_BASE = 0x600B1C00
|
||||||
RTC_CNTL_WDTCONFIG0_REG = DR_REG_LP_WDT_BASE + 0x0 # LP_WDT_RWDT_CONFIG0_REG
|
RTC_CNTL_WDTCONFIG0_REG = DR_REG_LP_WDT_BASE + 0x0 # LP_WDT_RWDT_CONFIG0_REG
|
||||||
|
RTC_CNTL_WDTCONFIG1_REG = DR_REG_LP_WDT_BASE + 0x0004 # LP_WDT_RWDT_CONFIG1_REG
|
||||||
RTC_CNTL_WDTWPROTECT_REG = DR_REG_LP_WDT_BASE + 0x001C # LP_WDT_RWDT_WPROTECT_REG
|
RTC_CNTL_WDTWPROTECT_REG = DR_REG_LP_WDT_BASE + 0x001C # LP_WDT_RWDT_WPROTECT_REG
|
||||||
|
|
||||||
RTC_CNTL_SWD_CONF_REG = DR_REG_LP_WDT_BASE + 0x0020 # LP_WDT_SWD_CONFIG_REG
|
RTC_CNTL_SWD_CONF_REG = DR_REG_LP_WDT_BASE + 0x0020 # LP_WDT_SWD_CONFIG_REG
|
||||||
@@ -77,6 +79,9 @@ class ESP32H2ROM(ESP32C6ROM):
|
|||||||
# ESP32H2 XTAL is fixed to 32MHz
|
# ESP32H2 XTAL is fixed to 32MHz
|
||||||
return 32
|
return 32
|
||||||
|
|
||||||
|
def hard_reset(self):
|
||||||
|
ESPLoader.hard_reset(self)
|
||||||
|
|
||||||
def check_spi_connection(self, spi_connection):
|
def check_spi_connection(self, spi_connection):
|
||||||
if not set(spi_connection).issubset(set(range(0, 28))):
|
if not set(spi_connection).issubset(set(range(0, 28))):
|
||||||
raise FatalError("SPI Pin numbers must be in the range 0-27.")
|
raise FatalError("SPI Pin numbers must be in the range 0-27.")
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# SPDX-FileCopyrightText: 2023 Fredrik Ahlberg, Angus Gratton,
|
# SPDX-FileCopyrightText: 2024 Fredrik Ahlberg, Angus Gratton,
|
||||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
@@ -72,6 +72,10 @@ class ESP32P4ROM(ESP32ROM):
|
|||||||
|
|
||||||
FLASH_ENCRYPTED_WRITE_ALIGN = 16
|
FLASH_ENCRYPTED_WRITE_ALIGN = 16
|
||||||
|
|
||||||
|
UARTDEV_BUF_NO = 0x4FF3FEC8 # Variable in ROM .bss which indicates the port in use
|
||||||
|
UARTDEV_BUF_NO_USB_OTG = 5 # The above var when USB-OTG is used
|
||||||
|
UARTDEV_BUF_NO_USB_JTAG_SERIAL = 6 # The above var when USB-JTAG/Serial is used
|
||||||
|
|
||||||
MEMORY_MAP = [
|
MEMORY_MAP = [
|
||||||
[0x00000000, 0x00010000, "PADDING"],
|
[0x00000000, 0x00010000, "PADDING"],
|
||||||
[0x40000000, 0x4C000000, "DROM"],
|
[0x40000000, 0x4C000000, "DROM"],
|
||||||
@@ -105,6 +109,17 @@ class ESP32P4ROM(ESP32ROM):
|
|||||||
12: "KM_INIT_KEY",
|
12: "KM_INIT_KEY",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DR_REG_LP_WDT_BASE = 0x50116000
|
||||||
|
RTC_CNTL_WDTCONFIG0_REG = DR_REG_LP_WDT_BASE + 0x0 # LP_WDT_CONFIG0_REG
|
||||||
|
RTC_CNTL_WDTCONFIG1_REG = DR_REG_LP_WDT_BASE + 0x0004 # LP_WDT_CONFIG1_REG
|
||||||
|
RTC_CNTL_WDTWPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0018 # LP_WDT_WPROTECT_REG
|
||||||
|
RTC_CNTL_WDT_WKEY = 0x50D83AA1
|
||||||
|
|
||||||
|
RTC_CNTL_SWD_CONF_REG = DR_REG_LP_WDT_BASE + 0x001C # RTC_WDT_SWD_CONFIG_REG
|
||||||
|
RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 18
|
||||||
|
RTC_CNTL_SWD_WPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0020 # RTC_WDT_SWD_WPROTECT_REG
|
||||||
|
RTC_CNTL_SWD_WKEY = 0x50D83AA1 # RTC_WDT_SWD_WKEY, same as WDT key in this case
|
||||||
|
|
||||||
def get_pkg_version(self):
|
def get_pkg_version(self):
|
||||||
num_word = 2
|
num_word = 2
|
||||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 20) & 0x07
|
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 20) & 0x07
|
||||||
@@ -191,10 +206,42 @@ class ESP32P4ROM(ESP32ROM):
|
|||||||
ESPLoader.change_baud(self, baud)
|
ESPLoader.change_baud(self, baud)
|
||||||
|
|
||||||
def _post_connect(self):
|
def _post_connect(self):
|
||||||
pass
|
if not self.sync_stub_detected: # Don't run if stub is reused
|
||||||
# TODO: Disable watchdogs when USB modes are supported in the stub
|
self.disable_watchdogs()
|
||||||
# if not self.sync_stub_detected: # Don't run if stub is reused
|
|
||||||
# self.disable_watchdogs()
|
def uses_usb_otg(self):
|
||||||
|
"""
|
||||||
|
Check the UARTDEV_BUF_NO register to see if USB-OTG console is being used
|
||||||
|
"""
|
||||||
|
if self.secure_download_mode:
|
||||||
|
return False # can't detect native USB in secure download mode
|
||||||
|
return self.get_uart_no() == self.UARTDEV_BUF_NO_USB_OTG
|
||||||
|
|
||||||
|
def uses_usb_jtag_serial(self):
|
||||||
|
"""
|
||||||
|
Check the UARTDEV_BUF_NO register to see if USB-JTAG/Serial is being used
|
||||||
|
"""
|
||||||
|
if self.secure_download_mode:
|
||||||
|
return False # can't detect USB-JTAG/Serial in secure download mode
|
||||||
|
return self.get_uart_no() == self.UARTDEV_BUF_NO_USB_JTAG_SERIAL
|
||||||
|
|
||||||
|
def disable_watchdogs(self):
|
||||||
|
# When USB-JTAG/Serial is used, the RTC WDT and SWD watchdog are not reset
|
||||||
|
# and can then reset the board during flashing. Disable them.
|
||||||
|
if self.uses_usb_jtag_serial():
|
||||||
|
# Disable RTC WDT
|
||||||
|
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, self.RTC_CNTL_SWD_WKEY)
|
||||||
|
self.write_reg(self.RTC_CNTL_WDTCONFIG0_REG, 0)
|
||||||
|
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, 0)
|
||||||
|
|
||||||
|
# Automatically feed SWD
|
||||||
|
self.write_reg(self.RTC_CNTL_SWD_WPROTECT_REG, self.RTC_CNTL_SWD_WKEY)
|
||||||
|
self.write_reg(
|
||||||
|
self.RTC_CNTL_SWD_CONF_REG,
|
||||||
|
self.read_reg(self.RTC_CNTL_SWD_CONF_REG)
|
||||||
|
| self.RTC_CNTL_SWD_AUTO_FEED_EN,
|
||||||
|
)
|
||||||
|
self.write_reg(self.RTC_CNTL_SWD_WPROTECT_REG, 0)
|
||||||
|
|
||||||
def check_spi_connection(self, spi_connection):
|
def check_spi_connection(self, spi_connection):
|
||||||
if not set(spi_connection).issubset(set(range(0, 55))):
|
if not set(spi_connection).issubset(set(range(0, 55))):
|
||||||
@@ -205,6 +252,21 @@ class ESP32P4ROM(ESP32ROM):
|
|||||||
"consider using other pins for SPI flash connection."
|
"consider using other pins for SPI flash connection."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def rtc_wdt_reset(self):
|
||||||
|
print("Hard resetting with RTC WDT...")
|
||||||
|
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, self.RTC_CNTL_WDT_WKEY) # unlock
|
||||||
|
self.write_reg(self.RTC_CNTL_WDTCONFIG1_REG, 5000) # set WDT timeout
|
||||||
|
self.write_reg(
|
||||||
|
self.RTC_CNTL_WDTCONFIG0_REG, (1 << 31) | (5 << 28) | (1 << 8) | 2
|
||||||
|
) # enable WDT
|
||||||
|
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, 0) # lock
|
||||||
|
|
||||||
|
def hard_reset(self):
|
||||||
|
if self.uses_usb_jtag_serial():
|
||||||
|
self.rtc_wdt_reset()
|
||||||
|
else:
|
||||||
|
ESPLoader.hard_reset(self)
|
||||||
|
|
||||||
|
|
||||||
class ESP32P4StubLoader(ESP32P4ROM):
|
class ESP32P4StubLoader(ESP32P4ROM):
|
||||||
"""Access class for ESP32P4 stub loader, runs on top of ROM.
|
"""Access class for ESP32P4 stub loader, runs on top of ROM.
|
||||||
|
@@ -1,9 +1,8 @@
|
|||||||
# SPDX-FileCopyrightText: 2014-2023 Fredrik Ahlberg, Angus Gratton,
|
# SPDX-FileCopyrightText: 2014-2024 Fredrik Ahlberg, Angus Gratton,
|
||||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
import os
|
|
||||||
import struct
|
import struct
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
@@ -82,11 +81,17 @@ class ESP32S2ROM(ESP32ROM):
|
|||||||
USB_RAM_BLOCK = 0x800 # Max block size USB-OTG is used
|
USB_RAM_BLOCK = 0x800 # Max block size USB-OTG is used
|
||||||
|
|
||||||
GPIO_STRAP_REG = 0x3F404038
|
GPIO_STRAP_REG = 0x3F404038
|
||||||
GPIO_STRAP_SPI_BOOT_MASK = 0x8 # Not download mode
|
GPIO_STRAP_SPI_BOOT_MASK = 1 << 3 # Not download mode
|
||||||
GPIO_STRAP_VDDSPI_MASK = 1 << 4
|
GPIO_STRAP_VDDSPI_MASK = 1 << 4
|
||||||
RTC_CNTL_OPTION1_REG = 0x3F408128
|
RTC_CNTL_OPTION1_REG = 0x3F408128
|
||||||
RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x1 # Is download mode forced over USB?
|
RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x1 # Is download mode forced over USB?
|
||||||
|
|
||||||
|
RTCCNTL_BASE_REG = 0x3F408000
|
||||||
|
RTC_CNTL_WDTCONFIG0_REG = RTCCNTL_BASE_REG + 0x0094
|
||||||
|
RTC_CNTL_WDTCONFIG1_REG = RTCCNTL_BASE_REG + 0x0098
|
||||||
|
RTC_CNTL_WDTWPROTECT_REG = RTCCNTL_BASE_REG + 0x00AC
|
||||||
|
RTC_CNTL_WDT_WKEY = 0x50D83AA1
|
||||||
|
|
||||||
MEMORY_MAP = [
|
MEMORY_MAP = [
|
||||||
[0x00000000, 0x00010000, "PADDING"],
|
[0x00000000, 0x00010000, "PADDING"],
|
||||||
[0x3F000000, 0x3FF80000, "DROM"],
|
[0x3F000000, 0x3FF80000, "DROM"],
|
||||||
@@ -282,32 +287,27 @@ class ESP32S2ROM(ESP32ROM):
|
|||||||
if self.uses_usb_otg():
|
if self.uses_usb_otg():
|
||||||
self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK
|
self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK
|
||||||
|
|
||||||
def _check_if_can_reset(self):
|
def rtc_wdt_reset(self):
|
||||||
"""
|
print("Hard resetting with RTC WDT...")
|
||||||
Check the strapping register to see if we can reset out of download mode.
|
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, self.RTC_CNTL_WDT_WKEY) # unlock
|
||||||
"""
|
self.write_reg(self.RTC_CNTL_WDTCONFIG1_REG, 5000) # set WDT timeout
|
||||||
if os.getenv("ESPTOOL_TESTING") is not None:
|
self.write_reg(
|
||||||
print("ESPTOOL_TESTING is set, ignoring strapping mode check")
|
self.RTC_CNTL_WDTCONFIG0_REG, (1 << 31) | (5 << 28) | (1 << 8) | 2
|
||||||
# Esptool tests over USB-OTG run with GPIO0 strapped low,
|
) # enable WDT
|
||||||
# don't complain in this case.
|
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, 0) # lock
|
||||||
return
|
|
||||||
strap_reg = self.read_reg(self.GPIO_STRAP_REG)
|
|
||||||
force_dl_reg = self.read_reg(self.RTC_CNTL_OPTION1_REG)
|
|
||||||
if (
|
|
||||||
strap_reg & self.GPIO_STRAP_SPI_BOOT_MASK == 0
|
|
||||||
and force_dl_reg & self.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK == 0
|
|
||||||
):
|
|
||||||
raise SystemExit(
|
|
||||||
f"Error: {self.get_chip_description()} chip was placed into download "
|
|
||||||
"mode using GPIO0.\nesptool.py can not exit the download mode over "
|
|
||||||
"USB. To run the app, reset the chip manually.\n"
|
|
||||||
"To suppress this note, set --after option to 'no_reset'."
|
|
||||||
)
|
|
||||||
|
|
||||||
def hard_reset(self):
|
def hard_reset(self):
|
||||||
uses_usb_otg = self.uses_usb_otg()
|
uses_usb_otg = self.uses_usb_otg()
|
||||||
if uses_usb_otg:
|
if uses_usb_otg:
|
||||||
self._check_if_can_reset()
|
# Check the strapping register to see if we can perform RTC WDT reset
|
||||||
|
strap_reg = self.read_reg(self.GPIO_STRAP_REG)
|
||||||
|
force_dl_reg = self.read_reg(self.RTC_CNTL_OPTION1_REG)
|
||||||
|
if (
|
||||||
|
strap_reg & self.GPIO_STRAP_SPI_BOOT_MASK == 0 # GPIO0 low
|
||||||
|
and force_dl_reg & self.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK == 0
|
||||||
|
):
|
||||||
|
self.rtc_wdt_reset()
|
||||||
|
return
|
||||||
|
|
||||||
ESPLoader.hard_reset(self, uses_usb_otg)
|
ESPLoader.hard_reset(self, uses_usb_otg)
|
||||||
|
|
||||||
|
@@ -1,9 +1,8 @@
|
|||||||
# SPDX-FileCopyrightText: 2014-2023 Fredrik Ahlberg, Angus Gratton,
|
# SPDX-FileCopyrightText: 2014-2024 Fredrik Ahlberg, Angus Gratton,
|
||||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
import os
|
|
||||||
import struct
|
import struct
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
@@ -90,13 +89,14 @@ class ESP32S3ROM(ESP32ROM):
|
|||||||
RTC_CNTL_SWD_WKEY = 0x8F1D312A
|
RTC_CNTL_SWD_WKEY = 0x8F1D312A
|
||||||
|
|
||||||
RTC_CNTL_WDTCONFIG0_REG = RTCCNTL_BASE_REG + 0x0098
|
RTC_CNTL_WDTCONFIG0_REG = RTCCNTL_BASE_REG + 0x0098
|
||||||
|
RTC_CNTL_WDTCONFIG1_REG = RTCCNTL_BASE_REG + 0x009C
|
||||||
RTC_CNTL_WDTWPROTECT_REG = RTCCNTL_BASE_REG + 0x00B0
|
RTC_CNTL_WDTWPROTECT_REG = RTCCNTL_BASE_REG + 0x00B0
|
||||||
RTC_CNTL_WDT_WKEY = 0x50D83AA1
|
RTC_CNTL_WDT_WKEY = 0x50D83AA1
|
||||||
|
|
||||||
USB_RAM_BLOCK = 0x800 # Max block size USB-OTG is used
|
USB_RAM_BLOCK = 0x800 # Max block size USB-OTG is used
|
||||||
|
|
||||||
GPIO_STRAP_REG = 0x60004038
|
GPIO_STRAP_REG = 0x60004038
|
||||||
GPIO_STRAP_SPI_BOOT_MASK = 0x8 # Not download mode
|
GPIO_STRAP_SPI_BOOT_MASK = 1 << 3 # Not download mode
|
||||||
GPIO_STRAP_VDDSPI_MASK = 1 << 4
|
GPIO_STRAP_VDDSPI_MASK = 1 << 4
|
||||||
RTC_CNTL_OPTION1_REG = 0x6000812C
|
RTC_CNTL_OPTION1_REG = 0x6000812C
|
||||||
RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x1 # Is download mode forced over USB?
|
RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x1 # Is download mode forced over USB?
|
||||||
@@ -344,33 +344,16 @@ class ESP32S3ROM(ESP32ROM):
|
|||||||
if not self.sync_stub_detected: # Don't run if stub is reused
|
if not self.sync_stub_detected: # Don't run if stub is reused
|
||||||
self.disable_watchdogs()
|
self.disable_watchdogs()
|
||||||
|
|
||||||
def _check_if_can_reset(self):
|
def rtc_wdt_reset(self):
|
||||||
"""
|
print("Hard resetting with RTC WDT...")
|
||||||
Check the strapping register to see if we can reset out of download mode.
|
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, self.RTC_CNTL_WDT_WKEY) # unlock
|
||||||
"""
|
self.write_reg(self.RTC_CNTL_WDTCONFIG1_REG, 5000) # set WDT timeout
|
||||||
if os.getenv("ESPTOOL_TESTING") is not None:
|
self.write_reg(
|
||||||
print("ESPTOOL_TESTING is set, ignoring strapping mode check")
|
self.RTC_CNTL_WDTCONFIG0_REG, (1 << 31) | (5 << 28) | (1 << 8) | 2
|
||||||
# Esptool tests over USB-OTG run with GPIO0 strapped low,
|
) # enable WDT
|
||||||
# don't complain in this case.
|
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, 0) # lock
|
||||||
return
|
|
||||||
strap_reg = self.read_reg(self.GPIO_STRAP_REG)
|
|
||||||
force_dl_reg = self.read_reg(self.RTC_CNTL_OPTION1_REG)
|
|
||||||
if (
|
|
||||||
strap_reg & self.GPIO_STRAP_SPI_BOOT_MASK == 0
|
|
||||||
and force_dl_reg & self.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK == 0
|
|
||||||
):
|
|
||||||
raise SystemExit(
|
|
||||||
f"Error: {self.get_chip_description()} chip was placed into download "
|
|
||||||
"mode using GPIO0.\nesptool.py can not exit the download mode over "
|
|
||||||
"USB. To run the app, reset the chip manually.\n"
|
|
||||||
"To suppress this note, set --after option to 'no_reset'."
|
|
||||||
)
|
|
||||||
|
|
||||||
def hard_reset(self):
|
def hard_reset(self):
|
||||||
uses_usb_otg = self.uses_usb_otg()
|
|
||||||
if uses_usb_otg:
|
|
||||||
self._check_if_can_reset()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Clear force download boot mode to avoid the chip being stuck in download mode after reset
|
# Clear force download boot mode to avoid the chip being stuck in download mode after reset
|
||||||
# workaround for issue: https://github.com/espressif/arduino-esp32/issues/6762
|
# workaround for issue: https://github.com/espressif/arduino-esp32/issues/6762
|
||||||
@@ -380,6 +363,17 @@ class ESP32S3ROM(ESP32ROM):
|
|||||||
except Exception:
|
except Exception:
|
||||||
# Skip if response was not valid and proceed to reset; e.g. when monitoring while resetting
|
# Skip if response was not valid and proceed to reset; e.g. when monitoring while resetting
|
||||||
pass
|
pass
|
||||||
|
uses_usb_otg = self.uses_usb_otg()
|
||||||
|
if uses_usb_otg or self.uses_usb_jtag_serial():
|
||||||
|
# Check the strapping register to see if we can perform RTC WDT reset
|
||||||
|
strap_reg = self.read_reg(self.GPIO_STRAP_REG)
|
||||||
|
force_dl_reg = self.read_reg(self.RTC_CNTL_OPTION1_REG)
|
||||||
|
if (
|
||||||
|
strap_reg & self.GPIO_STRAP_SPI_BOOT_MASK == 0 # GPIO0 low
|
||||||
|
and force_dl_reg & self.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK == 0
|
||||||
|
):
|
||||||
|
self.rtc_wdt_reset()
|
||||||
|
return
|
||||||
|
|
||||||
ESPLoader.hard_reset(self, uses_usb_otg)
|
ESPLoader.hard_reset(self, uses_usb_otg)
|
||||||
|
|
||||||
|
@@ -12,6 +12,13 @@
|
|||||||
# - --chip - ESP chip name
|
# - --chip - ESP chip name
|
||||||
# - --baud - baud rate
|
# - --baud - baud rate
|
||||||
# - --with-trace - trace all interactions (True or False)
|
# - --with-trace - trace all interactions (True or False)
|
||||||
|
#
|
||||||
|
# To run the tests in USB-OTG mode, ground the boot mode straping pin
|
||||||
|
# and set ESPTOOL_TEST_USB_OTG environment variable to any value.
|
||||||
|
#
|
||||||
|
# To run the tests in USB-Serial/JTAG mode, set both --port and --preload-port
|
||||||
|
# options. The --preload-port needs to be connected to a USB-to-UART bridge,
|
||||||
|
# while --port needs to be connected to the USB-Serial/JTAG peripheral.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
@@ -21,7 +28,6 @@ import struct
|
|||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
|
||||||
from socket import AF_INET, SOCK_STREAM, socket
|
from socket import AF_INET, SOCK_STREAM, socket
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from typing import List
|
from typing import List
|
||||||
@@ -51,9 +57,6 @@ import serial
|
|||||||
|
|
||||||
TEST_DIR = os.path.abspath(os.path.dirname(__file__))
|
TEST_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
# esptool.py skips strapping mode check in USB-CDC case if this is set
|
|
||||||
os.environ["ESPTOOL_TESTING"] = "1"
|
|
||||||
|
|
||||||
print("Running esptool.py tests...")
|
print("Running esptool.py tests...")
|
||||||
|
|
||||||
|
|
||||||
@@ -177,7 +180,12 @@ class EsptoolTestCase:
|
|||||||
if baud or arg_baud is not None:
|
if baud or arg_baud is not None:
|
||||||
base_cmd += ["--baud", str(baud or arg_baud)]
|
base_cmd += ["--baud", str(baud or arg_baud)]
|
||||||
usb_jtag_serial_reset = ["--before", "usb_reset"] if arg_preload_port else []
|
usb_jtag_serial_reset = ["--before", "usb_reset"] if arg_preload_port else []
|
||||||
full_cmd = base_cmd + usb_jtag_serial_reset + args.split(" ")
|
usb_otg_dont_reset = (
|
||||||
|
["--after", "no_reset_stub"] if "ESPTOOL_TEST_USB_OTG" in os.environ else []
|
||||||
|
)
|
||||||
|
full_cmd = (
|
||||||
|
base_cmd + usb_jtag_serial_reset + usb_otg_dont_reset + args.split(" ")
|
||||||
|
)
|
||||||
|
|
||||||
# Preload a dummy binary to disable the RTC watchdog, needed in USB-JTAG/Serial
|
# Preload a dummy binary to disable the RTC watchdog, needed in USB-JTAG/Serial
|
||||||
if (
|
if (
|
||||||
@@ -204,12 +212,16 @@ class EsptoolTestCase:
|
|||||||
print("\nPreloading dummy binary to disable RTC watchdog...")
|
print("\nPreloading dummy binary to disable RTC watchdog...")
|
||||||
run_esptool_process(preload_cmd)
|
run_esptool_process(preload_cmd)
|
||||||
print("Dummy binary preloaded successfully.")
|
print("Dummy binary preloaded successfully.")
|
||||||
time.sleep(0.3) # Wait for the app to run and port to appear
|
sleep(0.3) # Wait for the app to run and port to appear
|
||||||
|
|
||||||
# Run the command
|
# Run the command
|
||||||
print(f'\nRunning the "{args}" command...')
|
print(f'\nRunning the "{args}" command...')
|
||||||
output = run_esptool_process(full_cmd)
|
output = run_esptool_process(full_cmd)
|
||||||
print(output) # for more complete stdout logs on failure
|
print(output) # for more complete stdout logs on failure
|
||||||
|
|
||||||
|
if "ESPTOOL_TEST_USB_OTG" in os.environ:
|
||||||
|
sleep(0.5) # Wait for the port to enumerate between tests
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def run_esptool_error(self, args, baud=None, chip=None):
|
def run_esptool_error(self, args, baud=None, chip=None):
|
||||||
@@ -284,6 +296,20 @@ class EsptoolTestCase:
|
|||||||
ct = ct[8:]
|
ct = ct[8:]
|
||||||
self.diff(rb, ct)
|
self.diff(rb, ct)
|
||||||
|
|
||||||
|
def verify_output(self, expected_out: List[bytes]):
|
||||||
|
"""Verify that at least one element of expected_out is in serial output"""
|
||||||
|
# Setting rtscts to true enables hardware flow control.
|
||||||
|
# This removes unwanted RTS logic level changes for some machines
|
||||||
|
# (and, therefore, chip resets)
|
||||||
|
# when the port is opened by the following function.
|
||||||
|
# As a result, if an app loaded to RAM, it has a chance to run and send
|
||||||
|
# "Hello world" data without unwanted chip reset.
|
||||||
|
with serial.serial_for_url(arg_port, arg_baud, rtscts=True) as p:
|
||||||
|
p.timeout = 5
|
||||||
|
output = p.read(100)
|
||||||
|
print(f"Output: {output}")
|
||||||
|
assert any(item in output for item in expected_out)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(arg_chip != "esp32", reason="ESP32 only")
|
@pytest.mark.skipif(arg_chip != "esp32", reason="ESP32 only")
|
||||||
class TestFlashEncryption(EsptoolTestCase):
|
class TestFlashEncryption(EsptoolTestCase):
|
||||||
@@ -486,7 +512,7 @@ class TestFlashing(EsptoolTestCase):
|
|||||||
def test_correct_offset(self):
|
def test_correct_offset(self):
|
||||||
"""Verify writing at an offset actually writes to that offset."""
|
"""Verify writing at an offset actually writes to that offset."""
|
||||||
self.run_esptool("write_flash 0x2000 images/sector.bin")
|
self.run_esptool("write_flash 0x2000 images/sector.bin")
|
||||||
time.sleep(0.1)
|
sleep(0.1)
|
||||||
three_sectors = self.readback(0, 0x3000)
|
three_sectors = self.readback(0, 0x3000)
|
||||||
last_sector = three_sectors[0x2000:]
|
last_sector = three_sectors[0x2000:]
|
||||||
with open("images/sector.bin", "rb") as f:
|
with open("images/sector.bin", "rb") as f:
|
||||||
@@ -675,7 +701,8 @@ class TestFlashing(EsptoolTestCase):
|
|||||||
"WARNING: Flash address 0x00000001 is not aligned to a 0x1000 byte flash sector. 0x1 bytes before this address will be erased."
|
"WARNING: Flash address 0x00000001 is not aligned to a 0x1000 byte flash sector. 0x1 bytes before this address will be erased."
|
||||||
in output
|
in output
|
||||||
)
|
)
|
||||||
assert "Hard resetting via RTS pin..." in output
|
if "ESPTOOL_TEST_USB_OTG" not in os.environ:
|
||||||
|
assert "Hard resetting" in output
|
||||||
|
|
||||||
@pytest.mark.skipif(arg_preload_port is False, reason="USB-JTAG/Serial only")
|
@pytest.mark.skipif(arg_preload_port is False, reason="USB-JTAG/Serial only")
|
||||||
@pytest.mark.skipif(arg_chip != "esp32c3", reason="ESP32-C3 only")
|
@pytest.mark.skipif(arg_chip != "esp32c3", reason="ESP32-C3 only")
|
||||||
@@ -749,7 +776,7 @@ class TestFlashing(EsptoolTestCase):
|
|||||||
)
|
)
|
||||||
assert "Stub is already running. No upload is necessary." in output
|
assert "Stub is already running. No upload is necessary." in output
|
||||||
|
|
||||||
time.sleep(10) # Wait if RTC WDT triggers
|
sleep(10) # Wait if RTC WDT triggers
|
||||||
|
|
||||||
with esptool.cmds.detect_chip(
|
with esptool.cmds.detect_chip(
|
||||||
port=arg_port, connect_mode="no_reset"
|
port=arg_port, connect_mode="no_reset"
|
||||||
@@ -979,6 +1006,10 @@ class TestExternalFlash(EsptoolTestCase):
|
|||||||
self.verify_readback(0, 1024, "images/one_kb.bin", spi_connection=self.conn)
|
self.verify_readback(0, 1024, "images/one_kb.bin", spi_connection=self.conn)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
"ESPTOOL_TEST_USB_OTG" in os.environ,
|
||||||
|
reason="USB-OTG tests require --after no_reset for stability.",
|
||||||
|
)
|
||||||
class TestStubReuse(EsptoolTestCase):
|
class TestStubReuse(EsptoolTestCase):
|
||||||
def test_stub_reuse_with_synchronization(self):
|
def test_stub_reuse_with_synchronization(self):
|
||||||
"""Keep the flasher stub running and reuse it the next time."""
|
"""Keep the flasher stub running and reuse it the next time."""
|
||||||
@@ -1257,7 +1288,7 @@ class TestDeepSleepFlash(EsptoolTestCase):
|
|||||||
# (so GPIO16, etc, config is not important for this test)
|
# (so GPIO16, etc, config is not important for this test)
|
||||||
self.run_esptool("write_flash 0x0 images/esp8266_deepsleep.bin", baud=230400)
|
self.run_esptool("write_flash 0x0 images/esp8266_deepsleep.bin", baud=230400)
|
||||||
|
|
||||||
time.sleep(0.25) # give ESP8266 time to enter deep sleep
|
sleep(0.25) # give ESP8266 time to enter deep sleep
|
||||||
|
|
||||||
self.run_esptool("write_flash 0x0 images/fifty_kb.bin", baud=230400)
|
self.run_esptool("write_flash 0x0 images/fifty_kb.bin", baud=230400)
|
||||||
self.verify_readback(0, 50 * 1024, "images/fifty_kb.bin")
|
self.verify_readback(0, 50 * 1024, "images/fifty_kb.bin")
|
||||||
@@ -1491,6 +1522,31 @@ class TestMakeImage(EsptoolTestCase):
|
|||||||
os.remove("test0x00000.bin")
|
os.remove("test0x00000.bin")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
arg_chip in ["esp8266", "esp32", "esp32h2"], reason="Not supported on this chip"
|
||||||
|
)
|
||||||
|
@pytest.mark.skipif(
|
||||||
|
"ESPTOOL_TEST_USB_OTG" in os.environ or arg_preload_port is not False,
|
||||||
|
reason="Boot mode strapping pin pulled constantly low, can't reset out of bootloader",
|
||||||
|
)
|
||||||
|
class TestReset(EsptoolTestCase):
|
||||||
|
def test_rtc_wdt_reset(self):
|
||||||
|
# Erase the bootloader to get "invalid header" output + test RTC WDT reset
|
||||||
|
res = self.run_esptool("--after no_reset erase_region 0x0 0x4000")
|
||||||
|
assert "Erase completed" in res
|
||||||
|
try:
|
||||||
|
esp = esptool.get_default_connected_device(
|
||||||
|
[arg_port], arg_port, 10, 115200, arg_chip
|
||||||
|
)
|
||||||
|
esp.rtc_wdt_reset()
|
||||||
|
finally:
|
||||||
|
esp._port.close()
|
||||||
|
sleep(0.2) # Give the chip time to reset
|
||||||
|
# If there is no output, the chip did not reset
|
||||||
|
# Mangled bytes are for C2 26 MHz when the baudrate doesn't match
|
||||||
|
self.verify_output([b"invalid header", b"\x02b\xe2n\x9e\xe0p\x12n\x9c\x0cn"])
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(arg_chip != "esp32", reason="Don't need to test multiple times")
|
@pytest.mark.skipif(arg_chip != "esp32", reason="Don't need to test multiple times")
|
||||||
@pytest.mark.quick_test
|
@pytest.mark.quick_test
|
||||||
class TestConfigFile(EsptoolTestCase):
|
class TestConfigFile(EsptoolTestCase):
|
||||||
|
Reference in New Issue
Block a user