Skip to content

Commit 92143ed

Browse files
committed
feat(esptool): add new command SFDP read
1 parent 4f7e223 commit 92143ed

File tree

10 files changed

+60
-2
lines changed

10 files changed

+60
-2
lines changed

docs/en/esptool/advanced-commands.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,18 @@ A second option ``--non-volatile`` can be used in order to send a ``WREN`` (06h)
120120

121121
Setting status bits (particularly non-volatile ones) can have permanent side effects for some flash chips, so check carefully before using this command to set any bits!
122122

123+
.. _read-flash-sfdp:
124+
125+
Read Serial Flash Discoverable Parameters (SFDP)
126+
------------------------------------------------
127+
128+
The Serial Flash Discoverable Parameters (SFDP) store essential vendor-specific configuration data of the flash memory chip. These parameters help identify and interact with different flash devices. Usage:
129+
130+
::
131+
esptool.py read_flash_sfdp 16 4
132+
133+
This will read 4 bytes from SFDP address 16.
134+
123135
.. only:: esp8266
124136

125137
.. _chip-id:

docs/en/esptool/basic-commands.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ The following commands are less commonly used, or only of interest to advanced u
338338
* :ref:`read-mem-write-mem`
339339
* :ref:`read-flash-status`
340340
* :ref:`write-flash-status`
341+
* :ref:`read-flash-sfdp`
341342
:esp8266: * :ref:`chip-id`
342343
:esp8266: * :ref:`make-image`
343344
:esp8266: * :ref:`run`

esptool/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
erase_flash,
5050
erase_region,
5151
flash_id,
52+
read_flash_sfdp,
5253
get_security_info,
5354
image_info,
5455
load_ram,
@@ -627,6 +628,14 @@ def add_spi_flash_subparsers(
627628
type=arg_auto_size,
628629
)
629630

631+
parser_read_flash_sfdp = subparsers.add_parser(
632+
"read_flash_sfdp",
633+
help="Read SPI flash SFDP (Serial Flash Discoverable Parameters)",
634+
)
635+
add_spi_flash_subparsers(parser_read_flash_sfdp, allow_keep=True, auto_detect=True)
636+
parser_read_flash_sfdp.add_argument("addr", type=arg_auto_int)
637+
parser_read_flash_sfdp.add_argument("bytes", type=int)
638+
630639
parser_merge_bin = subparsers.add_parser(
631640
"merge_bin",
632641
help="Merge multiple raw binary files into a single file for later flashing",

esptool/cmds.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1164,14 +1164,18 @@ def run(esp, args):
11641164
esp.run()
11651165

11661166

1167-
def flash_id(esp, args):
1167+
def detect_flash_id(esp):
11681168
flash_id = esp.flash_id()
11691169
print("Manufacturer: %02x" % (flash_id & 0xFF))
11701170
flid_lowbyte = (flash_id >> 16) & 0xFF
11711171
print("Device: %02x%02x" % ((flash_id >> 8) & 0xFF, flid_lowbyte))
11721172
print(
11731173
"Detected flash size: %s" % (DETECTED_FLASH_SIZES.get(flid_lowbyte, "Unknown"))
11741174
)
1175+
1176+
1177+
def flash_id(esp, args):
1178+
detect_flash_id(esp)
11751179
flash_type = esp.flash_type()
11761180
flash_type_dict = {0: "quad (4 data lines)", 1: "octal (8 data lines)"}
11771181
flash_type_str = flash_type_dict.get(flash_type)
@@ -1180,6 +1184,17 @@ def flash_id(esp, args):
11801184
esp.get_flash_voltage()
11811185

11821186

1187+
def read_flash_sfdp(esp, args):
1188+
detect_flash_id(esp)
1189+
1190+
sfdp = esp.read_spiflash_sfdp(args.addr, args.bytes * 8)
1191+
print(f"SFDP[{args.addr}..{args.addr+args.bytes-1}]: ", end="")
1192+
for i in range(args.bytes):
1193+
print(f"{sfdp&0xff:02X} ", end="")
1194+
sfdp = sfdp >> 8
1195+
print()
1196+
1197+
11831198
def read_flash(esp, args):
11841199
if args.no_progress:
11851200
flash_progress = None

esptool/loader.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ class ESPLoader(object):
268268

269269
UART_DATE_REG_ADDR = 0x60000078
270270

271+
# Whether the SPI peripheral sends from MSB of 32-bit register, or the MSB of valid LSB bits.
272+
SPI_ADDR_REG_MSB = True
273+
271274
# This ROM address has a different value on each chip model
272275
CHIP_DETECT_MAGIC_REG_ADDR = 0x40001000
273276

@@ -1392,7 +1395,9 @@ def set_data_lengths(mosi_bits, miso_bits):
13921395
self.write_reg(
13931396
SPI_USR2_REG, (7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflash_command
13941397
)
1395-
if addr and addr_len > 0:
1398+
if addr_len > 0:
1399+
if self.SPI_ADDR_REG_MSB:
1400+
addr = addr << (32 - addr_len)
13961401
self.write_reg(SPI_ADDR_REG, addr)
13971402
if data_bits == 0:
13981403
self.write_reg(SPI_W0_REG, 0) # clear data register before we read it

esptool/targets/esp32c3.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class ESP32C3ROM(ESP32ROM):
2828
SPI_MISO_DLEN_OFFS = 0x28
2929
SPI_W0_OFFS = 0x58
3030

31+
SPI_ADDR_REG_MSB = False
32+
3133
BOOTLOADER_FLASH_OFFSET = 0x0
3234

3335
# Magic values for ESP32-C3 eco 1+2, eco 3, eco 6, and eco 7 respectively

esptool/targets/esp32p4.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ class ESP32P4ROM(ESP32ROM):
3838
SPI_MISO_DLEN_OFFS = 0x28
3939
SPI_W0_OFFS = 0x58
4040

41+
SPI_ADDR_REG_MSB = False
42+
4143
EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address
4244

4345
EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34

esptool/targets/esp32s2.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class ESP32S2ROM(ESP32ROM):
3232
SPI_MISO_DLEN_OFFS = 0x28
3333
SPI_W0_OFFS = 0x58
3434

35+
SPI_ADDR_REG_MSB = False
36+
3537
MAC_EFUSE_REG = 0x3F41A044 # ESP32-S2 has special block for MAC efuses
3638

3739
UART_CLKDIV_REG = 0x3F400014

esptool/targets/esp32s3.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ class ESP32S3ROM(ESP32ROM):
3535
SPI_MISO_DLEN_OFFS = 0x28
3636
SPI_W0_OFFS = 0x58
3737

38+
SPI_ADDR_REG_MSB = False
39+
3840
BOOTLOADER_FLASH_OFFSET = 0x0
3941

4042
SUPPORTS_ENCRYPTED_FLASH = True

test/test_esptool.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,14 @@ def test_flash_size(self):
841841
for line in lines:
842842
assert "embedded flash" not in line.lower()
843843

844+
@pytest.mark.quick_test
845+
def test_flash_sfdp(self):
846+
"""Test manufacturer and device response of flash detection."""
847+
res = self.run_esptool("read_flash_sfdp 0 4")
848+
assert "SFDP[0..3]: 53 46 44 50" in res
849+
res = self.run_esptool("read_flash_sfdp 1 3")
850+
assert "SFDP[1..3]: 46 44 50 " in res
851+
844852

845853
@pytest.mark.skipif(
846854
os.getenv("ESPTOOL_TEST_SPI_CONN") is None, reason="Needs external flash"

0 commit comments

Comments
 (0)