feat(esptool): add new command SFDP read

This commit is contained in:
Xiao Xufeng
2024-07-27 02:02:20 +08:00
parent 4f7e22391c
commit 92143ed146
10 changed files with 60 additions and 2 deletions

View File

@@ -120,6 +120,18 @@ A second option ``--non-volatile`` can be used in order to send a ``WREN`` (06h)
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! 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!
.. _read-flash-sfdp:
Read Serial Flash Discoverable Parameters (SFDP)
------------------------------------------------
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:
::
esptool.py read_flash_sfdp 16 4
This will read 4 bytes from SFDP address 16.
.. only:: esp8266 .. only:: esp8266
.. _chip-id: .. _chip-id:

View File

@@ -338,6 +338,7 @@ The following commands are less commonly used, or only of interest to advanced u
* :ref:`read-mem-write-mem` * :ref:`read-mem-write-mem`
* :ref:`read-flash-status` * :ref:`read-flash-status`
* :ref:`write-flash-status` * :ref:`write-flash-status`
* :ref:`read-flash-sfdp`
:esp8266: * :ref:`chip-id` :esp8266: * :ref:`chip-id`
:esp8266: * :ref:`make-image` :esp8266: * :ref:`make-image`
:esp8266: * :ref:`run` :esp8266: * :ref:`run`

View File

@@ -49,6 +49,7 @@ from esptool.cmds import (
erase_flash, erase_flash,
erase_region, erase_region,
flash_id, flash_id,
read_flash_sfdp,
get_security_info, get_security_info,
image_info, image_info,
load_ram, load_ram,
@@ -627,6 +628,14 @@ def main(argv=None, esp=None):
type=arg_auto_size, type=arg_auto_size,
) )
parser_read_flash_sfdp = subparsers.add_parser(
"read_flash_sfdp",
help="Read SPI flash SFDP (Serial Flash Discoverable Parameters)",
)
add_spi_flash_subparsers(parser_read_flash_sfdp, allow_keep=True, auto_detect=True)
parser_read_flash_sfdp.add_argument("addr", type=arg_auto_int)
parser_read_flash_sfdp.add_argument("bytes", type=int)
parser_merge_bin = subparsers.add_parser( parser_merge_bin = subparsers.add_parser(
"merge_bin", "merge_bin",
help="Merge multiple raw binary files into a single file for later flashing", help="Merge multiple raw binary files into a single file for later flashing",

View File

@@ -1164,7 +1164,7 @@ def run(esp, args):
esp.run() esp.run()
def flash_id(esp, args): def detect_flash_id(esp):
flash_id = esp.flash_id() flash_id = esp.flash_id()
print("Manufacturer: %02x" % (flash_id & 0xFF)) print("Manufacturer: %02x" % (flash_id & 0xFF))
flid_lowbyte = (flash_id >> 16) & 0xFF flid_lowbyte = (flash_id >> 16) & 0xFF
@@ -1172,6 +1172,10 @@ def flash_id(esp, args):
print( print(
"Detected flash size: %s" % (DETECTED_FLASH_SIZES.get(flid_lowbyte, "Unknown")) "Detected flash size: %s" % (DETECTED_FLASH_SIZES.get(flid_lowbyte, "Unknown"))
) )
def flash_id(esp, args):
detect_flash_id(esp)
flash_type = esp.flash_type() flash_type = esp.flash_type()
flash_type_dict = {0: "quad (4 data lines)", 1: "octal (8 data lines)"} flash_type_dict = {0: "quad (4 data lines)", 1: "octal (8 data lines)"}
flash_type_str = flash_type_dict.get(flash_type) flash_type_str = flash_type_dict.get(flash_type)
@@ -1180,6 +1184,17 @@ def flash_id(esp, args):
esp.get_flash_voltage() esp.get_flash_voltage()
def read_flash_sfdp(esp, args):
detect_flash_id(esp)
sfdp = esp.read_spiflash_sfdp(args.addr, args.bytes * 8)
print(f"SFDP[{args.addr}..{args.addr+args.bytes-1}]: ", end="")
for i in range(args.bytes):
print(f"{sfdp&0xff:02X} ", end="")
sfdp = sfdp >> 8
print()
def read_flash(esp, args): def read_flash(esp, args):
if args.no_progress: if args.no_progress:
flash_progress = None flash_progress = None

View File

@@ -268,6 +268,9 @@ class ESPLoader(object):
UART_DATE_REG_ADDR = 0x60000078 UART_DATE_REG_ADDR = 0x60000078
# Whether the SPI peripheral sends from MSB of 32-bit register, or the MSB of valid LSB bits.
SPI_ADDR_REG_MSB = True
# This ROM address has a different value on each chip model # This ROM address has a different value on each chip model
CHIP_DETECT_MAGIC_REG_ADDR = 0x40001000 CHIP_DETECT_MAGIC_REG_ADDR = 0x40001000
@@ -1392,7 +1395,9 @@ class ESPLoader(object):
self.write_reg( self.write_reg(
SPI_USR2_REG, (7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflash_command SPI_USR2_REG, (7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflash_command
) )
if addr and addr_len > 0: if addr_len > 0:
if self.SPI_ADDR_REG_MSB:
addr = addr << (32 - addr_len)
self.write_reg(SPI_ADDR_REG, addr) self.write_reg(SPI_ADDR_REG, addr)
if data_bits == 0: if data_bits == 0:
self.write_reg(SPI_W0_REG, 0) # clear data register before we read it self.write_reg(SPI_W0_REG, 0) # clear data register before we read it

View File

@@ -28,6 +28,8 @@ class ESP32C3ROM(ESP32ROM):
SPI_MISO_DLEN_OFFS = 0x28 SPI_MISO_DLEN_OFFS = 0x28
SPI_W0_OFFS = 0x58 SPI_W0_OFFS = 0x58
SPI_ADDR_REG_MSB = False
BOOTLOADER_FLASH_OFFSET = 0x0 BOOTLOADER_FLASH_OFFSET = 0x0
# Magic values for ESP32-C3 eco 1+2, eco 3, eco 6, and eco 7 respectively # Magic values for ESP32-C3 eco 1+2, eco 3, eco 6, and eco 7 respectively

View File

@@ -38,6 +38,8 @@ class ESP32P4ROM(ESP32ROM):
SPI_MISO_DLEN_OFFS = 0x28 SPI_MISO_DLEN_OFFS = 0x28
SPI_W0_OFFS = 0x58 SPI_W0_OFFS = 0x58
SPI_ADDR_REG_MSB = False
EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address
EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34 EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34

View File

@@ -32,6 +32,8 @@ class ESP32S2ROM(ESP32ROM):
SPI_MISO_DLEN_OFFS = 0x28 SPI_MISO_DLEN_OFFS = 0x28
SPI_W0_OFFS = 0x58 SPI_W0_OFFS = 0x58
SPI_ADDR_REG_MSB = False
MAC_EFUSE_REG = 0x3F41A044 # ESP32-S2 has special block for MAC efuses MAC_EFUSE_REG = 0x3F41A044 # ESP32-S2 has special block for MAC efuses
UART_CLKDIV_REG = 0x3F400014 UART_CLKDIV_REG = 0x3F400014

View File

@@ -35,6 +35,8 @@ class ESP32S3ROM(ESP32ROM):
SPI_MISO_DLEN_OFFS = 0x28 SPI_MISO_DLEN_OFFS = 0x28
SPI_W0_OFFS = 0x58 SPI_W0_OFFS = 0x58
SPI_ADDR_REG_MSB = False
BOOTLOADER_FLASH_OFFSET = 0x0 BOOTLOADER_FLASH_OFFSET = 0x0
SUPPORTS_ENCRYPTED_FLASH = True SUPPORTS_ENCRYPTED_FLASH = True

View File

@@ -841,6 +841,14 @@ class TestFlashDetection(EsptoolTestCase):
for line in lines: for line in lines:
assert "embedded flash" not in line.lower() assert "embedded flash" not in line.lower()
@pytest.mark.quick_test
def test_flash_sfdp(self):
"""Test manufacturer and device response of flash detection."""
res = self.run_esptool("read_flash_sfdp 0 4")
assert "SFDP[0..3]: 53 46 44 50" in res
res = self.run_esptool("read_flash_sfdp 1 3")
assert "SFDP[1..3]: 46 44 50 " in res
@pytest.mark.skipif( @pytest.mark.skipif(
os.getenv("ESPTOOL_TEST_SPI_CONN") is None, reason="Needs external flash" os.getenv("ESPTOOL_TEST_SPI_CONN") is None, reason="Needs external flash"