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_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
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``).
- 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
time.sleep(0.05)
_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:
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):
"""

View File

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

View File

@@ -1525,9 +1525,13 @@ class ESPLoader(object):
)
return norm_xtal
def hard_reset(self):
def hard_reset(self, uses_usb=False):
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):
if not self.IS_STUB:

View File

@@ -205,5 +205,5 @@ class CustomReset(ResetStrategy):
cmds = seq_str.split("|")
fn_calls_list = [self.format_dict[cmd[0]].format(cmd[1:]) for cmd in cmds]
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)

View File

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

View File

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

View File

@@ -9,7 +9,6 @@ from typing import Dict
from .esp32 import ESP32ROM
from ..loader import ESPLoader
from ..reset import HardReset
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
pass
print("Hard resetting via RTS pin...")
HardReset(self._port, uses_usb_otg)()
ESPLoader.hard_reset(self, uses_usb_otg)
def 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):
output = self.run_esptool_error("flash_id")
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):
# Test that the open_port_attempts option is loaded correctly