memory-25q¶
CLI reference¶
glasgow run memory-25q¶
Identify, read, erase, or program memories compatible with 25-series SPI/dual-SPI/quad-SPI
NOR Flash memory, such as Microchip 25C320, Winbond W25Q32JV, Micron MT25QU256ABA,
Macronix MX25L6445E, ISSI IS25LP128, or hundreds of other memories that typically have 25x
(where “x” is a letter, usually C, F, or Q) in their part number. Note that 25N
typically designates (Q)SPI NAND Flash memory, which is completely incompatible.
The pinout of a typical 25-series IC is as follows:
16-pin 8-pin
IO3/HOLD# @ * SCK CS# @ * VCC
VCC * * IO0/COPI IO1/CIPO * * IO3/HOLD#
N/C * * N/C IO2/WP# * * SCK
N/C * * N/C GND * * IO0/COPI
N/C * * N/C
N/C * * N/C
CS# * * GND
IO1/CIPO * * IO2/WP#
This applet supports ordinary SPI mode, as well as dual-SPI and quad-SPI. When quad-SPI mode
is not in use, the WP# and HOLD# pins are pulled high; these must not be left floating
as the memories do not typically include internal pull-ups. These faster modes are not enabled
by default because of the potential for bus contention and higher severity of crosstalk; use
the options --dual-spi and --quad-spi to enable their use (when described in SFDP).
It is also possible to flash 25-series flash chips using the spi-flashrom applet, which requires a third-party tool flashrom. The advantage of using the flashrom applet is that flashrom offers compatibility with a wider variety of devices, some of which may not be supported by the memory-25q applet.
usage: glasgow run memory-25q [-h] [-V SPEC] [--cs PIN] [--sck PIN]
[--io PINS] [-f FREQ] [--dual-spi] [--quad-spi]
[-A WIDTH] [-P SIZE] [--opcode-erase-4k OPCODE]
[--opcode-erase-32k OPCODE]
[--opcode-erase-64k OPCODE]
OPERATION ...
- -h, --help¶
show this help message and exit
- -V <spec>, --voltage <spec>¶
configure I/O port voltage to SPEC (e.g.: ‘3.3’, ‘A=5.0,B=3.3’, ‘A=SA’)
- --cs <pin>¶
bind the applet I/O line ‘cs’ to PIN (default: ‘A0’, required)
- --sck <pin>¶
bind the applet I/O line ‘sck’ to PIN (default: ‘A1’, required)
- --io <pins>¶
bind the applet I/O lines ‘copi’, ‘cipo’, ‘wp’, ‘hold’ to PINS (default: ‘A2,A3,A4,A5’, required)
- -f <freq>, --frequency <freq>¶
set SCK frequency to FREQ kHz (default: 12000)
- --dual-spi¶
use dual-SPI modes if present in SFDP
- --quad-spi¶
use quad-SPI modes if present in SFDP
- -A {3,4}, --address-bytes {3,4}¶
use WIDTH address bytes for data region (choices: 3, 4, default: 3)
- -P <size>, --page-size <size>¶
do not cross multiple-of-SIZE boundaries when programming
- --opcode-erase-4k <opcode>¶
opcode for erasing a 4 KiB region
- --opcode-erase-32k <opcode>¶
opcode for erasing a 32 KiB region
- --opcode-erase-64k <opcode>¶
opcode for erasing a 64 KiB region
glasgow run memory-25q erase¶
Erase memory range. Start and end of specified range must be aligned on erase size boundaries.
usage: glasgow run memory-25q erase [-h] ADDRESS LENGTH
- address¶
start with byte at ADDRESS
- length¶
continue for LENGTH bytes
- -h, --help¶
show this help message and exit
glasgow run memory-25q erase-all¶
Erase memory range covering the entire chip.
usage: glasgow run memory-25q erase-all [-h]
- -h, --help¶
show this help message and exit
glasgow run memory-25q identify¶
Identify memory by its JEDEC ID and (if available) Serial Flash Discoverable Parameters.
usage: glasgow run memory-25q identify [-h] [--annotate-raw-sfdp]
- -h, --help¶
show this help message and exit
- --annotate-raw-sfdp¶
annotate known raw SFDP DWORDs with fields
glasgow run memory-25q protect¶
Read or write Block Protection (BP) bits. The exact size and location of the protected area for a specific bit combination can only be determined from the device datasheet.
Setting all BP bits to zero may be necessary to execute the erase-all command or to resolve erase/program failures.
usage: glasgow run memory-25q protect [-h] [BITMASK]
- bitmask¶
write BITMASK to BP bits (e.g. 0000 to allow all, 1111 to protect all)
- -h, --help¶
show this help message and exit
glasgow run memory-25q read¶
Read memory range using the fastest available read command.
usage: glasgow run memory-25q read [-h] [-f FILENAME] ADDRESS LENGTH
- address¶
start with byte at ADDRESS
- length¶
continue for LENGTH bytes
- -h, --help¶
show this help message and exit
- -f <filename>, --file <filename>¶
write memory contents to FILENAME
glasgow run memory-25q verify¶
Read memory range using the fastest available read command, and compare with given data.
usage: glasgow run memory-25q verify [-h] (-d DATA | -f FILENAME) ADDRESS
- address¶
start with byte at ADDRESS
- -h, --help¶
show this help message and exit
- -d <data>, --data <data>¶
use hex bytes DATA as memory contents
- -f <filename>, --file <filename>¶
use data from FILENAME as memory contents
glasgow run memory-25q write¶
Write memory range using a read-modify-write sequence. Start and end of specified range do not need to be aligned on erase size boundaries.
usage: glasgow run memory-25q write [-h] (-d DATA | -f FILENAME) ADDRESS
- address¶
start with byte at ADDRESS
- -h, --help¶
show this help message and exit
- -d <data>, --data <data>¶
use hex bytes DATA as memory contents
- -f <filename>, --file <filename>¶
use data from FILENAME as memory contents
glasgow tool memory-25q¶
Dissect captured SPI/QSPI transactions and extract data into linear memory image files.
The expected capture file format is the same as ones used by spi-analyzer and qspi-analyzer applets. Specifically, one of the following Comma-Separated Value line formats is expected:
<COPI>,<CIPO>, where <COPI> and <CIPO> are hexadecimal byte sequences with each eight bits corresponding to samples of COPI and CIPO, respectively (from MSB to LSB).<DATA>, where <DATA> is a hexadecimal nibble sequence with each four bits corresponding to samples of HOLD#, WP#, CIPO, COPI (from MSB to LSB).
The extracted data can be saved as pairs of data files and mask files, where the mask file contains a 1 bit for every bit in the data file that has been observed in a transaction, and a 0 bit otherwise.
The list below details every command that is recognized by this tool. If your capture includes commands not currently recognized, please open an issue with a capture file attached.
03h (Read Data)
04h (Write Disable)
05h (Read Status Register)
06h (Write Enable)
0Bh (Fast Read)
4Bh (Read Unique ID)
5Ah (Read SFDP)
9Fh (Read JEDEC ID)
B7h (Enter 4-Byte Address Mode)
E9h (Exit 4-Byte Address Mode)
3Bh (Dual Output Fast Read)
6Bh (Quad Output Fast Read)
BBh (Dual I/O Fast Read)
EBh (Quad I/O Fast Read)
usage: glasgow tool memory-25q [-h] [--data DATA-FILE] [--data-mask MASK-FILE]
[--sfdp DATA-FILE] [--sfdp-mask MASK-FILE]
[--uid DATA-FILE] [--uid-mask MASK-FILE]
CAPTURE-FILE
- capture-file¶
read captured SPI transactions from CAPTURE-FILE
- -h, --help¶
show this help message and exit
- --data <data-file>¶
write extracted data to DATA-FILE
- --data-mask <mask-file>¶
write data presence mask to MASK-FILE
- --sfdp <data-file>¶
write extracted SFDP data to DATA-FILE
- --sfdp-mask <mask-file>¶
write SFDP data presence mask to MASK-FILE
- --uid <data-file>¶
write extracted UID data to DATA-FILE
- --uid-mask <mask-file>¶
write UID data presence mask to MASK-FILE
API reference¶
- exception glasgow.applet.memory._25q.Memory25QError¶
- exception glasgow.applet.memory._25q.Memory25QVerifyError¶
- class glasgow.applet.memory._25q.Memory25QInterface(logger: Logger, assembly, *, cs: GlasgowPin, sck: GlasgowPin, io: GlasgowPin)¶
Make sure to call
initialize()first.- qspi: QSPIControllerInterface¶
Underlying QSPI interface.
- cmds: CommandSet¶
Active NOR command set.
The command set may be modified or extended after the interface is created to better represent actual capabilities of the memory device.
- sfdp: SFDPCollection | None¶
SFDP table collection.
Populated only if the tables were parsed successfully.
- sfdp_used: bool¶
Whether SFDP tables are usable.
Will be
Trueif SFDP information was used to successfully configure data transfer parameters,Falseotherwise.
- property memory_size: int | None¶
Memory size.
Size of the data region in bytes, or
Noneif SFDP data is not populated.
- async power_up()¶
Power up the device.
Implemented using
Opcode.ReleasePowerDown.Important
A memory may not accept any commands besides this one if it is in a deep power-down state.
- async power_down()¶
Power down the device.
Implemented using
Opcode.PowerDown.See
power_up().
- async jedec_id() tuple[int, int]¶
Read JEDEC IDs.
Implemented using
Opcode.ReadJEDEC.Returns
(jedec_mfg_id, device_id).
- async read_sfdp(address: int, length: int) memoryview¶
Read SFDP information.
Implemented using
Opcode.ReadSFDP.Returns
lengthSFDP bytes starting ataddress, wrapping when reading past the end of the SFDP region.
- async initialize(*, enable_dual: bool = False, enable_quad: bool = False)¶
Prepare device for data transfer.
Powers up the device and populates
sfdp(if possible).
- async read_data(address: int, length: int) bytes¶
Read data.
Implemented using the
Command.ReadData, which is typically but not necessarily mapped to one of:Returns
lengthdata bytes starting ataddress, wrapping when reading past the end of the data region.- Raises:
Memory25QError – If no read commands are configured.
- async read_status_reg_1() StatusReg1¶
Read Status Register 1.
Implemented using
Opcode.ReadStatusReg1.
- async write_status_reg_1(value: StatusReg1)¶
Write Status Register 1.
Implemented using
Opcode.WriteStatusReg1.
- async write_enable()¶
Prefix for write operations.
All methods of this interface that perform write operations internally enable writes; only call this method explicitly when implementing new operations.
- Raises:
Memory25QError – If the
BUSYbit is set in Status Register 1.Memory25QError – If the operation fails to set the
WRENbit in Status Register 1.
- async poll_busy()¶
Wait until operation is done.
Polls Status Register 1 until the
BUSYbit is clear.All methods of this interfaces that perform write operations internally wait for completion; only call this method explicitly when implementing new operations.
- Raises:
Memory25QError – If the
WRENbit in Status Register 1 is still set after theBUSYbit clears. This usually means that the preceding operation failed.
- async set_quad_enabled(enabled: bool = True)¶
Enable or disable quad-SPI instructions.
Most devices power on and/or arrive from the factory configured with IO2/IO3 pins having the WP#/HOLD# function. Using quad-SPI instructions requires switching them to data I/O first. Since this can cause bus contention and disables hardware write protection (if any), this action must be taken explicitly.
- Raises:
Memory25QError – If SFDP tables are not available.
NotImplementedError – If the device-specific enablement algorithm has not been implemented.
- async erase_data_all()¶
Erase all data.
Implemented using
Opcode.EraseChip.Warning
This command can take a very long time (on the order of minutes) and does not read back data to verify success.
Tip
If the memory size is known (see
memory_size), prefer usingerase_data()with a range that covers the entire data region, which will report progress and verify that the data was successfully erased.
- async erase_data(address: int, length: int)¶
Erase data and verify success.
Implemented using one of:
Erases memory range specified by
addressandlength.- Raises:
ValueError – If either
addressorlengthis not divisible by the erase size of one of the available erase commands.Memory25QError – If no erase commands are configured.
Memory25QVerifyError – If readback of erased data fails verification.
- async program_data(address: int, data: bytes | bytearray | memoryview)¶
Program data and verify success.
Implemented using
Command.ProgramData.Programs
datato memory range starting ataddress. The memory range must have been erased (usingerase_data()or otherwise), otherwise the resulting contents will become a logical AND of existing data and written data, and will fail verification.- Raises:
Memory25QError – If no program commands are available, or page size is not configured.
Memory25QVerifyError – If readback of programmed data fails verification.
- async write_data(address: int, data: bytes | bytearray | memoryview)¶
Write data and verify success.
Implemented using
erase_data()andprogram_data().Writes
dataataddresswithout any alignment constraints. If the written region is not already appropriately aligned, performs a read-modify-write cycle; in any case, data is first erased and then programmed.- Raises:
Memory25QError – If no erase or program commands are configured, or page size is not configured.
Memory25QVerifyError – If readback of erased or programmed data fails verification.
NOR command set reference¶
- enum glasgow.arch.qspi.nor.Opcode(value)¶
Common (Q)SPI NOR Flash memory opcodes.
- Member Type:
Valid values are as follows:
- ResetDevice = Opcode.ResetDevice(FFh)¶
- EnableReset = Opcode.EnableReset(66h)¶
- PerformReset = Opcode.PerformReset(99h)¶
- ReleasePowerDown = Opcode.ReleasePowerDown(ABh)¶
- PowerDown = Opcode.PowerDown(B9h)¶
- ReadSFDP = Opcode.ReadSFDP(5Ah)¶
- ReadID = Opcode.ReadID(90h)¶
- ReadJEDEC = Opcode.ReadJEDEC(9Fh)¶
- Read = Opcode.Read(03h)¶
- FastRead = Opcode.FastRead(0Bh)¶
- FastReadDualOutput = Opcode.FastReadDualOutput(3Bh)¶
- FastReadQuadOutput = Opcode.FastReadQuadOutput(6Bh)¶
- FastReadDualInOut = Opcode.FastReadDualInOut(BBh)¶
- FastReadQuadInOut = Opcode.FastReadQuadInOut(EBh)¶
- PageProgram = Opcode.PageProgram(02h)¶
- QuadInputPageProgram = Opcode.QuadInputPageProgram(32h)¶
- EraseChip = Opcode.EraseChip(60h)¶
- ReadStatusReg1 = Opcode.ReadStatusReg1(05h)¶
- WriteStatusReg1 = Opcode.WriteStatusReg1(01h)¶
- ReadStatusReg2 = Opcode.ReadStatusReg2(35h)¶
- WriteStatusReg2 = Opcode.WriteStatusReg2(31h)¶
- ReadStatusReg3 = Opcode.ReadStatusReg3(15h)¶
- WriteStatusReg3 = Opcode.WriteStatusReg3(11h)¶
- WriteDisable = Opcode.WriteDisable(04h)¶
- WriteEnable = Opcode.WriteEnable(06h)¶
- StatusRegWriteEnable = Opcode.StatusRegWriteEnable(50h)¶
- Enter4ByteMode = Opcode.Enter4ByteMode(B7h)¶
- Leave4ByteMode = Opcode.Leave4ByteMode(E9h)¶
- enum glasgow.arch.qspi.nor.StatusReg1(value)¶
Status Register 1 flags.
Only includes six universally agreed upon LSBs. The two remaining MSBs have wildly varying function.
- Member Type:
Valid values are as follows:
- BUSY = StatusReg1.BUSY(00000001)¶
Operation in Progress bit
- WREN = StatusReg1.WREN(00000010)¶
Write Enable Latch bit
- BP0 = StatusReg1.BP0(00000100)¶
Block Protection bit 0
- BP1 = StatusReg1.BP1(00001000)¶
Block Protection bit 1
- BP2 = StatusReg1.BP2(00010000)¶
Block Protection bit 2
- BP3 = StatusReg1.BP3(00100000)¶
Block Protection bit 3 or Top/Bottom Block Protection bit
- enum glasgow.arch.qspi.nor.Command(value)¶
Abstract (Q)SPI NOR Flash memory commands.
While some commands directly correspond to a specific
Opcode, other commands have multiple functionally equivalent opcodes with different throughput, or in some cases there is no globally uniform opcode assignment at all.The mapping of
Commands toInstructions (and thereforeOpcodes) is maintained within aCommandSet.Valid values are as follows:
- PowerUp = Command.PowerUp¶
- PowerDown = Command.PowerDown¶
- ReadJEDEC = Command.ReadJEDEC¶
- ReadSFDP = Command.ReadSFDP¶
- ReadData = Command.ReadData¶
- ProgramData = Command.ProgramData¶
- EraseData4K = Command.EraseData4K¶
- EraseData32K = Command.EraseData32K¶
- EraseData64K = Command.EraseData64K¶
- EraseDataAll = Command.EraseDataAll¶
- WriteEnable = Command.WriteEnable¶
- WriteDisable = Command.WriteDisable¶
- ReadStatusReg1 = Command.ReadStatusReg1¶
- ReadStatusReg2 = Command.ReadStatusReg2¶
- ReadStatusReg3 = Command.ReadStatusReg3¶
- WriteStatusRegs = Command.WriteStatusRegs¶
- Enter4ByteMode = Command.Enter4ByteMode¶
- Leave4ByteMode = Command.Leave4ByteMode¶
The
Enumand its members also have the following methods:- classmethod erase_for_size(erase_size: int) Command¶
Select erase command for an
erase_size-long region.- Raises:
ValueError – If
erase_sizeis not inerase_erase_sizes().
- class glasgow.arch.qspi.nor.CommandSet¶
Bases:
BaseCommandSet[Command]SPI NOR Flash command set.
When created, the command set only contains the opcodes that are implemented by every JESD216 compliant device. This makes identification and configuration possible, but data transfer cannot occur until the corresponding command set is configured via
use_explicit()oruse_jesd216().Created with the following mappings:
Command.PowerUp:Opcode.ReleasePowerDown, (1-0-0) modeCommand.PowerDown:Opcode.PowerDown, (1-0-0) modeCommand.ReadSFDP:Opcode.ReadSFDP, (1-1-1) modeCommand.ReadJEDEC:Opcode.ReadJEDEC, (1-0-1) modeCommand.ReadStatusReg1:Opcode.ReadStatusReg1, (1-0-1) modeCommand.ReadStatusReg2:Opcode.ReadStatusReg2, (1-0-1) modeCommand.ReadStatusReg3:Opcode.ReadStatusReg3, (1-0-1) modeCommand.WriteStatusRegs:Opcode.WriteStatusReg1, (1-0-1) modeCommand.WriteEnable:Opcode.WriteEnable, (1-0-0) modeCommand.WriteDisable:Opcode.WriteDisable, (1-0-0) modeCommand.EraseDataAll:Opcode.EraseChip, (1-0-0) mode
- use_explicit(*, address_bytes: int, page_size: int | None = None, opcode_erase_4k: Opcode | int | None = None, opcode_erase_32k: Opcode | int | None = None, opcode_erase_64k: Opcode | int | None = None, data_operation_prologue: Callable[[int], InstructionSequence] = lambda address: ...)¶
Use explicitly specified instructions.
Adds up to five mappings:
Command.ReadData:Opcode.Read, (1-1-1) modeCommand.EraseData4K:opcode_erase_4k, (1-1-0) mode (if specified)Command.EraseData32K:opcode_erase_32k, (1-1-0) mode (if specified)Command.EraseData64K:opcode_erase_64k, (1-1-0) mode (if specified)Command.ProgramData:Opcode.PageProgram, (1-1-1) mode (ifpage_sizeis specified)
Configures the
data_operation_prologue()method to executedata_operation_prologue.This function is intended for “lowest common denominator” configuration in absence of SFDP data. If you need to configure a different or more complex command set, you should add the necessary mappings directly.
- use_jesd216(sfdp: SFDPCollection, enable_dual: bool = False, enable_quad: bool = False)¶
Use instructions specified by
sfdp.To determine the highest throughput instruction, all the possible (1-x-y) modes are ordered first by y and then x.
Adds the following mappings:
Command.ReadData(fastest available, consideringenable_dualandenable_quad)Command.EraseData4K(if available)Command.EraseData32K(if available)Command.EraseData64K(if available)Command.ProgramData:Opcode.PageProgram, (1-1-1) modeCommand.Enter4ByteMode:Opcode.Enter4ByteMode(if relevant)Command.Leave4ByteMode:Opcode.Leave4ByteMode(if relevant)
Configures the
data_operation_prologue()method to execute any appropriate mode switch or register access sequence for 4-byte addressing.- Raises:
ValueError – If JEDEC flash parameters table is not present.
ValueError – If JEDEC flash parameters table contains unsupported parameters for required features.
- data_operation_prologue(address: int) InstructionSequence¶
Compute prologue sequence for a data operation starting at
address.Returns an (address-specific) sequence of commands or write instructions that must be executed to prepare for any operation (reading, erasing, or programming) addressing the data region. A preceding call to
use_explicit()oruse_jesd216()may affect the specific sequence returned by this method.Danger
If the steps above are not followed exactly, the outcome of any read, erase, or program operations may be completely unpredictable.