feat(hard_reset): Support custom hard reset sequence configuration

Closes https://github.com/espressif/esptool/issues/1004
This commit is contained in:
Radim Karniš
2024-09-17 15:08:24 +02:00
committed by Roland Dobai
parent 6abd05d5c9
commit 1b157384bc
9 changed files with 33 additions and 17 deletions

View File

@@ -111,14 +111,19 @@ Complete list of configurable options:
+------------------------------+-----------------------------------------------------------+----------+ +------------------------------+-----------------------------------------------------------+----------+
| custom_reset_sequence | Custom reset sequence for resetting into the bootloader | | | custom_reset_sequence | Custom reset sequence for resetting into the bootloader | |
+------------------------------+-----------------------------------------------------------+----------+ +------------------------------+-----------------------------------------------------------+----------+
| custom_hard_reset_sequence | Custom reset sequence for hard resetting the chip | |
+------------------------------+-----------------------------------------------------------+----------+
Custom Reset Sequence Custom Reset Sequences
--------------------- ----------------------
The ``custom_reset_sequence`` configuration option allows you to define a reset sequence which will get The ``custom_reset_sequence`` configuration option allows you to define a reset sequence which will get
used when an :ref:`automatic reset into the serial bootloader <automatic-bootloader>` is performed. used when an :ref:`automatic reset into the serial bootloader <automatic-bootloader>` is performed.
The sequence is defined with a string in the following format: The ``custom_hard_reset_sequence`` option allows you to define a reset sequence which will get
used when a hard reset (a reset out of the bootloader) is performed.
A sequence is defined with a string in the following format:
- Consists of individual commands divided by ``|`` (e.g. ``R0|D1|W0.5``). - Consists of individual commands divided by ``|`` (e.g. ``R0|D1|W0.5``).
- Commands (e.g. ``R0``) are defined by a code (``R``) and an argument (``0``). - Commands (e.g. ``R0``) are defined by a code (``R``) and an argument (``0``).
@@ -148,3 +153,11 @@ For example: ``D0|R1|W0.1|D1|R0|W0.5|D0`` represents the following classic reset
_setRTS(False) # EN=HIGH, chip out of reset _setRTS(False) # EN=HIGH, chip out of reset
time.sleep(0.05) time.sleep(0.05)
_setDTR(False) # IO0=HIGH, done _setDTR(False) # IO0=HIGH, done
Similarly, ``R1|W0.1|R0`` represents the classic hard reset sequence:
.. code-block:: python
_setRTS(True) # EN=LOW, chip in reset
time.sleep(0.1)
_setRTS(False) # EN=HIGH, chip out of reset

View File

@@ -74,7 +74,11 @@ class EspPortManager(serial.rfc2217.PortManager):
""" """
if self.logger: if self.logger:
self.logger.info("Activating hard reset in thread") self.logger.info("Activating hard reset in thread")
HardReset(self.serial)() cfg_custom_hard_reset_sequence = cfg.get("custom_hard_reset_sequence")
if cfg_custom_hard_reset_sequence is not None:
CustomReset(self.serial, cfg_custom_hard_reset_sequence)()
else:
HardReset(self.serial)()
def _reset_thread(self): def _reset_thread(self):
""" """

View File

@@ -21,6 +21,7 @@ CONFIG_OPTIONS = [
"reset_delay", "reset_delay",
"open_port_attempts", "open_port_attempts",
"custom_reset_sequence", "custom_reset_sequence",
"custom_hard_reset_sequence",
] ]

View File

@@ -1525,9 +1525,13 @@ class ESPLoader(object):
) )
return norm_xtal return norm_xtal
def hard_reset(self): def hard_reset(self, uses_usb=False):
print("Hard resetting via RTS pin...") print("Hard resetting via RTS pin...")
HardReset(self._port)() cfg_custom_hard_reset_sequence = cfg.get("custom_hard_reset_sequence")
if cfg_custom_hard_reset_sequence is not None:
CustomReset(self._port, cfg_custom_hard_reset_sequence)()
else:
HardReset(self._port, uses_usb)()
def soft_reset(self, stay_in_bootloader): def soft_reset(self, stay_in_bootloader):
if not self.IS_STUB: if not self.IS_STUB:

View File

@@ -205,5 +205,5 @@ class CustomReset(ResetStrategy):
cmds = seq_str.split("|") cmds = seq_str.split("|")
fn_calls_list = [self.format_dict[cmd[0]].format(cmd[1:]) for cmd in cmds] fn_calls_list = [self.format_dict[cmd[0]].format(cmd[1:]) for cmd in cmds]
except Exception as e: except Exception as e:
raise FatalError(f'Invalid "custom_reset_sequence" option format: {e}') raise FatalError(f"Invalid custom reset sequence option format: {e}")
return "\n".join(fn_calls_list) return "\n".join(fn_calls_list)

View File

@@ -8,7 +8,6 @@ from typing import Dict
from .esp32c6 import ESP32C6ROM from .esp32c6 import ESP32C6ROM
from ..loader import ESPLoader from ..loader import ESPLoader
from ..reset import HardReset
from ..util import FatalError from ..util import FatalError
@@ -128,8 +127,7 @@ class ESP32C5ROM(ESP32C6ROM):
) >> self.PCR_SYSCLK_XTAL_FREQ_S ) >> self.PCR_SYSCLK_XTAL_FREQ_S
def hard_reset(self): def hard_reset(self):
print("Hard resetting via RTS pin...") ESPLoader.hard_reset(self, self.uses_usb_jtag_serial())
HardReset(self._port, self.uses_usb_jtag_serial())()
def change_baud(self, baud): def change_baud(self, baud):
if not self.IS_STUB: if not self.IS_STUB:

View File

@@ -9,7 +9,6 @@ from typing import Dict
from .esp32 import ESP32ROM from .esp32 import ESP32ROM
from ..loader import ESPLoader from ..loader import ESPLoader
from ..reset import HardReset
from ..util import FatalError, NotImplementedInROMError from ..util import FatalError, NotImplementedInROMError
@@ -310,8 +309,7 @@ class ESP32S2ROM(ESP32ROM):
if uses_usb_otg: if uses_usb_otg:
self._check_if_can_reset() self._check_if_can_reset()
print("Hard resetting via RTS pin...") ESPLoader.hard_reset(self, uses_usb_otg)
HardReset(self._port, uses_usb_otg)()
def change_baud(self, baud): def change_baud(self, baud):
ESPLoader.change_baud(self, baud) ESPLoader.change_baud(self, baud)

View File

@@ -9,7 +9,6 @@ from typing import Dict
from .esp32 import ESP32ROM from .esp32 import ESP32ROM
from ..loader import ESPLoader from ..loader import ESPLoader
from ..reset import HardReset
from ..util import FatalError, NotImplementedInROMError from ..util import FatalError, NotImplementedInROMError
@@ -382,8 +381,7 @@ class ESP32S3ROM(ESP32ROM):
# 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
print("Hard resetting via RTS pin...") ESPLoader.hard_reset(self, uses_usb_otg)
HardReset(self._port, uses_usb_otg)()
def change_baud(self, baud): def change_baud(self, baud):
ESPLoader.change_baud(self, baud) ESPLoader.change_baud(self, baud)

View File

@@ -1604,7 +1604,7 @@ class TestConfigFile(EsptoolTestCase):
with self.ConfigFile(config_file_path, invalid_reset_seq_config): with self.ConfigFile(config_file_path, invalid_reset_seq_config):
output = self.run_esptool_error("flash_id") output = self.run_esptool_error("flash_id")
assert f"Loaded custom configuration from {config_file_path}" in output assert f"Loaded custom configuration from {config_file_path}" in output
assert 'Invalid "custom_reset_sequence" option format:' in output assert "Invalid custom reset sequence option format:" in output
def test_open_port_attempts(self): def test_open_port_attempts(self):
# Test that the open_port_attempts option is loaded correctly # Test that the open_port_attempts option is loaded correctly