Skip to content

Commit

Permalink
fix(read_flash): add flash size arg to enable reading past 2MB withou…
Browse files Browse the repository at this point in the history
…t stub
  • Loading branch information
peterdragun authored and radimkarnis committed Jan 16, 2024
1 parent 8ce5ed3 commit f1eb65f
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 42 deletions.
5 changes: 5 additions & 0 deletions docs/en/esptool/basic-commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ It is also possible to autodetect flash size by using ``ALL`` as size. The above
esptool.py -p PORT -b 460800 read_flash 0 ALL flash_contents.bin


.. note::

When using the ``read_flash`` command in combination with the ``--no-stub`` argument, it may be necessary to also set the ``--flash_size`` argument to ensure proper reading of the flash contents by the ROM.


.. note::

If ``write_flash`` updated the boot image's :ref:`flash mode and flash size <flash-modes>` during flashing then these bytes may be different when read back.
Expand Down
67 changes: 38 additions & 29 deletions esptool/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,12 @@ def add_spi_connection_arg(parent):
default="0xFFFFFFFF",
)

def add_spi_flash_subparsers(parent, allow_keep, auto_detect):
def add_spi_flash_subparsers(
parent: argparse.ArgumentParser,
allow_keep: bool,
auto_detect: bool,
size_only: bool = False,
):
"""Add common parser arguments for SPI flash properties"""
extra_keep_args = ["keep"] if allow_keep else []

Expand All @@ -234,33 +239,35 @@ def add_spi_flash_subparsers(parent, allow_keep, auto_detect):
extra_fs_message = ""
flash_sizes = []

parent.add_argument(
"--flash_freq",
"-ff",
help="SPI Flash frequency",
choices=extra_keep_args
+ [
"80m",
"60m",
"48m",
"40m",
"30m",
"26m",
"24m",
"20m",
"16m",
"15m",
"12m",
],
default=os.environ.get("ESPTOOL_FF", "keep" if allow_keep else None),
)
parent.add_argument(
"--flash_mode",
"-fm",
help="SPI Flash mode",
choices=extra_keep_args + ["qio", "qout", "dio", "dout"],
default=os.environ.get("ESPTOOL_FM", "keep" if allow_keep else "qio"),
)
if not size_only:
parent.add_argument(
"--flash_freq",
"-ff",
help="SPI Flash frequency",
choices=extra_keep_args
+ [
"80m",
"60m",
"48m",
"40m",
"30m",
"26m",
"24m",
"20m",
"16m",
"15m",
"12m",
],
default=os.environ.get("ESPTOOL_FF", "keep" if allow_keep else None),
)
parent.add_argument(
"--flash_mode",
"-fm",
help="SPI Flash mode",
choices=extra_keep_args + ["qio", "qout", "dio", "dout"],
default=os.environ.get("ESPTOOL_FM", "keep" if allow_keep else "qio"),
)

parent.add_argument(
"--flash_size",
"-fs",
Expand Down Expand Up @@ -540,7 +547,9 @@ def add_spi_flash_subparsers(parent, allow_keep, auto_detect):
parser_read_flash = subparsers.add_parser(
"read_flash", help="Read SPI flash content"
)
add_spi_connection_arg(parser_read_flash)
add_spi_flash_subparsers(
parser_read_flash, allow_keep=True, auto_detect=True, size_only=True
)
parser_read_flash.add_argument("address", help="Start address", type=arg_auto_int)
parser_read_flash.add_argument(
"size",
Expand Down
16 changes: 11 additions & 5 deletions esptool/targets/esp32.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,11 +329,17 @@ def read_flash_slow(self, offset, length, progress_fn):
data = b""
while len(data) < length:
block_len = min(BLOCK_LEN, length - len(data))
r = self.check_command(
"read flash block",
self.ESP_READ_FLASH_SLOW,
struct.pack("<II", offset + len(data), block_len),
)
try:
r = self.check_command(
"read flash block",
self.ESP_READ_FLASH_SLOW,
struct.pack("<II", offset + len(data), block_len),
)
except FatalError:
print(
"Hint: Consider specifying flash size using '--flash_size' argument"
)
raise
if len(r) < block_len:
raise FatalError(
"Expected %d byte block, got %d bytes. Serial errors?"
Expand Down
42 changes: 34 additions & 8 deletions test/test_esptool.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,12 @@ def readback(self, offset, length, spi_connection=None):
dump_file.close()
os.unlink(dump_file.name)

def diff(self, readback, compare_to):
for rb_b, ct_b, offs in zip(readback, compare_to, range(len(readback))):
assert (
rb_b == ct_b
), f"First difference at offset {offs:#x} Expected {ct_b} got {rb_b}"

def verify_readback(
self, offset, length, compare_to, is_bootloader=False, spi_connection=None
):
Expand All @@ -268,10 +274,7 @@ def verify_readback(
assert ct[0] == rb[0], "First bytes should be identical"
rb = rb[8:]
ct = ct[8:]
for rb_b, ct_b, offs in zip(rb, ct, range(len(rb))):
assert (
rb_b == ct_b
), f"First difference at offset {offs:#x} Expected {ct_b} got {rb_b}"
self.diff(rb, ct)


@pytest.mark.skipif(arg_chip != "esp32", reason="ESP32 only")
Expand Down Expand Up @@ -735,6 +738,32 @@ def test_flash_size_keep(self):
# header should be the same as in the .bin file
self.verify_readback(offset, image_len, image)

@pytest.mark.skipif(
arg_chip == "esp8266", reason="ESP8266 does not support read_flash_slow"
)
def test_read_nostub_high_offset(self):
offset = 0x300000
length = 1024
self.run_esptool(f"write_flash -fs detect {offset} images/one_kb.bin")
dump_file = tempfile.NamedTemporaryFile(delete=False)
# readback with no-stub and flash-size set
try:
self.run_esptool(
f"--no-stub read_flash -fs detect {offset} 1024 {dump_file.name}"
)
with open(dump_file.name, "rb") as f:
rb = f.read()
assert length == len(
rb
), f"read_flash length {length} offset {offset:#x} yielded {len(rb)} bytes!"
finally:
dump_file.close()
os.unlink(dump_file.name)
# compare files
with open("images/one_kb.bin", "rb") as f:
ct = f.read()
self.diff(rb, ct)


class TestFlashDetection(EsptoolTestCase):
@pytest.mark.quick_test
Expand Down Expand Up @@ -1337,10 +1366,7 @@ def verify_image(self, offset, length, image, compare_to):
f"WARNING: Expected length {len(ct)} doesn't match comparison {len(rb)}"
)
print(f"Readback {len(rb)} bytes")
for rb_b, ct_b, offs in zip(rb, ct, range(len(rb))):
assert (
rb_b == ct_b
), f"First difference at offset {offs:#x} Expected {ct_b} got {rb_b}"
self.diff(rb, ct)

def test_make_image(self):
output = self.run_esptool(
Expand Down

0 comments on commit f1eb65f

Please sign in to comment.