mirror of
https://github.com/espressif/esptool.git
synced 2025-10-16 23:06:31 +08:00
feat(esptool): add new command SFDP read
This commit is contained in:
@@ -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:
|
||||||
|
@@ -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`
|
||||||
|
@@ -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",
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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"
|
||||||
|
Reference in New Issue
Block a user