qspi-controller¶
CLI reference¶
glasgow run qspi-controller¶
Initiate transactions on the extended variant of the SPI bus with four I/O channels.
This applet can control a wide range of devices, primarily memories, that use multi-bit variants of the SPI bus. Electrically, they are all compatible, with the names indicating differences in protocol logic:
“SPI” uses COPI/CIPO for both commands and data;
“dual-SPI” uses COPI/CIPO for commands and IO0/IO1 for data;
“quad-SPI” uses COPI/CIPO for commands and IO0/IO1/IO2/IO3 for data;
“QPI” uses IO0/IO1/IO2/IO3 for both commands and data.
In this list, COPI and CIPO refer to IO0 and IO1 respectively used as fixed direction I/O. Note that vendors often make further distinction between modes, e.g. between “dual output SPI” and “dual I/O SPI”; refer to the vendor documentation for details.
The command line interface only initiates SPI mode transfers. Use the REPL for other modes.
usage: glasgow run qspi-controller [-h] [-V SPEC] [--sck PIN] [--io PINS]
[--cs PIN] [-f FREQ]
DATA [DATA ...]
- data¶
hex bytes to exchange with the device in SPI mode
- -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’)
- --sck <pin>¶
bind the applet I/O line ‘sck’ to PIN (default: ‘A0’, required)
- --io <pins>¶
bind the applet I/O lines ‘copi’, ‘cipo’, ‘io2’, ‘io3’ to PINS (default: ‘A1,A2,A3,A4’, required)
- --cs <pin>¶
bind the applet I/O line ‘cs’ to PIN (default: ‘A5’, required)
- -f <freq>, --frequency <freq>¶
set SCK frequency to FREQ kHz (default: 1000)
API reference¶
- exception glasgow.applet.interface.qspi_controller.QSPIControllerError¶
- class glasgow.applet.interface.qspi_controller.QSPIControllerInterface(logger: Logger, assembly: AbstractAssembly, *, cs: GlasgowPin, sck: GlasgowPin, io: GlasgowPin)¶
Pull-ups are enabled on all
iopins.- property clock: ClockDivisor¶
SCK clock divisor.
- select(index=0)¶
Perform a transaction.
Starting a transaction configures the first transfer within the transaction to assert the
index-th chip select signal; ending a transaction deasserts the chip select signal. Methodswrite(),read(),exchange(), anddummy()may be called only while a transaction is active to transfer data on the bus.For example, to read 16 bytes from an SPI NOR flash at address
0x001234using the Fast Read (0Bh) command, use the following code:async with iface.select(): await iface.write([0x0B]) await iface.write((0x001234).to_bytes(3, byteorder="big")) await iface.dummy(8) data = await iface.read(16)
An empty transaction (where the body does not call
write(),read(),exchange(), ordummy()) is allowed and does not cause any chip select activity.- Raises:
QSPIControllerError – If recursively called inside a transaction.
QSPIControllerError – If
indexis greater than 7.
- async exchange(octets: bytes | bytearray | memoryview) memoryview¶
Exchange bytes.
Clock
octetsout via the IO0 (COPI) pin while clocking return value in via the IO1 (CIPO) pin. Unlikewrite()andread(), this method always uses x1 transfer rate.- Raises:
QSPIControllerError – If called outside of a transaction.
- async write(octets: bytes | bytearray | memoryview, *, x: Literal[1, 2, 4] = 1)¶
Write bytes.
Clock
octetsout viaxIOn pins, corresponding to single, dual, or quad SPI.- Raises:
QSPIControllerError – If called outside of a transaction.
- async read(count: int, *, x: Literal[1, 2, 4] = 1) memoryview¶
Read bytes.
Clock
countoctets in viaxIOn pins, corresponding to single, dual, or quad SPI.- Raises:
QSPIControllerError – If called outside of a transaction.
- async dummy(count: int)¶
Clock dummy cycles.
Clock
countdummy cycles. One octet corresponds to 8 dummy cycles in single SPI mode, 4 dummy cycles in dual SPI mode, and 2 dummy cycles in quad SPI mode. Some devices may require a non-multipleWarning
The state of IOn pins is undefined during this operation.
- Raises:
QSPIControllerError – If called outside of a transaction.
- async delay_us(duration: int)¶
Delay operations.
Delays the following QSPI bus operations by
durationmicroseconds.
- async delay_ms(duration: int)¶
Delay operations.
Delays the following QSPI bus operations by
durationmilliseconds. Equivalent todelay_us(duration * 1000).
- async synchronize()¶
Synchronization barrier.
Ensures that once this method returns, all previously submitted operations have completed.
- async execute_cmd(instr: Instruction[int], *, address: int | None = None)¶
Execute a memory technology instruction without data transfer.
This is a low-level operation; in most cases, a memory technology specific interface should be used instead.
- async execute_read(instr: Instruction, *, address: int | None = None, length: int | None = None) memoryview¶
Execute a memory technology instruction that reads data.
This is a low-level operation; in most cases, a memory technology specific interface should be used instead.
- async execute_write(instr: Instruction, *, address: int | None = None, data: bytes | bytearray | memoryview)¶
Execute a memory technology instruction that writes data.
This is a low-level operation; in most cases, a memory technology specific interface should be used instead.
Memory command set reference¶
The building blocks below are used for implementing memory technology interfaces, such as memory-25q. They are typically not used on their own.
- enum glasgow.arch.qspi.Direction(value)¶
Transfer direction.
Specified relative to the controller.
Valid values are as follows:
- Read = Direction.Read¶
- Write = Direction.Write¶
- class glasgow.arch.qspi.CommandMode(opcode: Literal[0, 1, 2, 4], address: Literal[0, 1, 2, 4], data: Literal[0, 1, 2, 4])¶
Command mode.
Specifies gearing for the opcode, address, and data phase.
- class glasgow.arch.qspi.Instruction(*, opcode: OpcodeT, x_opcode: Literal[0, 1, 2, 4] = 1, x_address: Literal[0, 1, 2, 4] = 1, x_data: Literal[0, 1, 2, 4] = 1, address_octets: int = 0, mode_cycles: int = 0, dummy_cycles: int = 0, direction: Direction | None = None, data_octets: int | None = 0, data_repeats: bool = False)¶
Instruction format.
The
Instructiondescribes the framing of each part (opcode, address, dummy, and data) of an abstract (Q)SPI instruction. The(x_opcode, x_address, x_data)tuple corresponds to the SFDPx-y-zterminology (e.g.1-1-4for quad output hasx_opcode, x_address, x_data = 1, 1, 4). These “gearing” parameters indicate how many bits are transmitted per cycle, e.g. it takes8 // x_opcodecycles to transmit the instruction opcode.- opcode: OpcodeT¶
Instruction opcode (one octet).
- x_address: Literal[0, 1, 2, 4] = 1¶
Gearing of the address phase.
If
0, there is no address phase, andaddress_octetsmust also be0.
- x_data: Literal[0, 1, 2, 4] = 1¶
Gearing of the data phase.
If
0, there is no data phase, anddata_octetsmust also be0.
- address_octets: int = 0¶
Length of the address phase, in octets.
Typically, between 0 and 4 inclusive, but this is not a hard requirement.
- mode_cycles: int = 0¶
Length of the mode phase, in cycles.
Typically, between 0 and 4 inclusive, and an integer multiple of the number of cycles needed to exchange a byte in the address phase, but this is not a hard requirement.
- dummy_cycles: int = 0¶
Length of the dummy phase, in cycles.
Typically, either
0or8 // x_address, but this is not guaranteed: certain devices require dummy phase of a length that is not an integer multiple of the number of cycles needed to exchange a byte in the address or data phase.
- direction: Direction | None = None¶
Direction of the data phase.
Must be
Noneif and only ifx_data == 0.
- data_octets: int | None = 0¶
Length of the data phase, in octets.
Typically, variable (indicated as
None), but certain commands return a fixed amount of data. See alsodata_repeats.
- data_repeats: bool = False¶
Whether the data output repeats.
If true, then the output repeats after transferring more than
data_octets. For status registers, each repeat indicates up-to-date state at the moment of the transfer.If false, data output might return all-zeroes, all-ones, or be undriven after transferring
data_octets, and this condition should be avoided.
- classmethod spi_1_0_0(opcode: OpcodeT)¶
SPI instruction with 1-0-0 gearing.
- classmethod spi_1_1_0(opcode: OpcodeT, *, address_octets: int = 0)¶
SPI instruction with 1-1-0 gearing.
- classmethod spi_1_0_1(opcode: OpcodeT, *, dummy_cycles: int = 0, direction: Direction | Literal['read', 'write'], data_octets: int | None = None, data_repeats: bool = False)¶
SPI instruction with 1-0-1 gearing.
- classmethod spi_1_1_1(opcode: OpcodeT, *, address_octets: int = 0, dummy_cycles: int = 0, direction: Direction | Literal['read', 'write'], data_octets: int | None = None, data_repeats: bool = False)¶
SPI instruction with 1-1-1 gearing.
- classmethod dspi_1_1_2(opcode: OpcodeT, *, address_octets: int = 0, mode_cycles: int = 0, dummy_cycles: int = 0, direction: Direction | Literal['read', 'write'], data_octets: int | None = None, data_repeats: bool = False)¶
Dual SPI instruction with 1-1-2 gearing.
- classmethod dspi_1_2_2(opcode: OpcodeT, *, address_octets: int = 0, mode_cycles: int = 0, dummy_cycles: int = 0, direction: Direction | Literal['read', 'write'], data_octets: int | None = None, data_repeats: bool = False)¶
Dual SPI instruction with 1-2-2 gearing.
- classmethod qspi_1_1_4(opcode: OpcodeT, *, address_octets: int = 0, mode_cycles: int = 0, dummy_cycles: int = 0, direction: Direction | Literal['read', 'write'], data_octets: int | None = None, data_repeats: bool = False)¶
Quad SPI instruction with 1-1-4 gearing.
- classmethod qspi_1_4_4(opcode: OpcodeT, *, address_octets: int = 0, mode_cycles: int = 0, dummy_cycles: int = 0, direction: Direction | Literal['read', 'write'], data_octets: int | None = None, data_repeats: bool = False)¶
Quad SPI instruction with 1-4-4 gearing.
- property mode: CommandMode¶
Command mode of this instruction.
- class glasgow.arch.qspi.BaseCommandSet¶
Base class for command sets.
A command set is a mapping from an abstract command (e.g. “Erase 4K Sector”) to a specific concrete instruction (e.g. “20h, 1-0-0, 3 address bytes”). Maintaining this mapping is necessary because similar devices from different vendors, different variants of the same device from the same vendor, or the exact same device with different volatile configuration, may have the same abstract commands represented by different concrete opcodes.
Technology-specific command sets should inherit from this class and include methods that parse memory architecture self-description data (if available) or assist in manually configuring the instruction set; for example, see
glasgow.arch.qspi.nor.CommandSet.- update(updates: dict[CommandT, Instruction])¶
Add multiple
CommandT-Instructionmappings.Overwrites mappings that already exist.
- __setitem__(command: CommandT, instruction: Instruction)¶
Add a single
CommandT-Instructionmapping.Overwrites mappings that already exist.
- __getitem__(command: CommandT) Instruction¶
Map a
CommandTto a specificInstruction.- Raises:
KeyError – If the mapping does not exist.