UDMA QSPI Master
The Standard Peripheral Interface bus (SPI) is a synchronous serial communication interface specification used for short distance communications. The interface has been developed first by Motorola and now has become a de facto standard. The lack of a formal standard is reflected in a wide variety of protocol options:
Different word sizes are common.
Every device defines its own protocol, including whether it supports commands at all.
Some devices are transmit-only; others are receive-only.
Chip selects are sometimes active-high rather than active-low.
Some protocols send the least significant bit first.
CORE-V-MCU QSPI Implementation
The CORE-V-MCU QSPI Master supports an implementation of the SPI and the QSPI (Quad SPI) mode enabling higher bandwidths required by modern embedded devices. Due to the lack of a formal standard it is impossible to make a claim of compliance to the protocol. However, CORE-V-MCU’s QSPI interface is known to work with the Micron N25Q256A Serial NOR Flash Memory and should work with a large set of QSPI and SPI devices. The QSPI master described here has some limitations to the supported variants of the SPI protocol. The major limitation is the lack of support for the full duplex transfers.
Example Transactions
Below are examples of typical writes and reads to external memories using the standard 4-wire SPI protocol.
Next we see an example transfer in QSPI mode. All 4 datalines are bidirectional and the communication is always half duplex.
UDMA QSPI Control Buffer
The actions of the QSPI controller are controlled using a sequence of commands that are written to the transmit buffer. Therefore, to use the QSPI driver software must assemble the appropriate sequence of commands in a buffer, and use the uDMA to send the buffer to the QSPI contoller. Note that the uDMA core manages both data buffers and interrupts on behalf of the QSPI controller.
Code |
Command/Field |
Bits |
Description |
---|---|---|---|
0x0 |
SPI_CMD_CFG |
Sets the configuration for the SPI Master IP |
|
CLKDIV |
7:0 |
Sets the clock divider value |
|
CPHA |
8:8 |
Sets the clock phase: |
|
0x0: |
|||
0x1: |
|||
CPOL |
9:9 |
Sets the clock polarity: |
|
0x0: |
|||
0x1: |
|||
SPI_CMD |
31:28 |
Command to execute (0x0) |
|
0x1 |
SPI_CMD_SOT |
Sets the Chip Select (CS) |
|
CS |
1:0 |
Sets the Chip Select (CS): |
|
0x0: select csn0 |
|||
0x1: select csn1 |
|||
0x2: select csn2 |
|||
0x3: select csn3 |
|||
SPI_CMD |
31:28 |
Command to execute (0x1) |
|
0x2 |
SPI_CMD_SEND_CMD |
Transmits up to 16bits of data sent in the command |
|
DATA_VALUE |
15:0 |
Sets the command to send. |
|
MSB must always be at bit 15 |
|||
if cmd size is less than 16 |
|||
DATA_SIZE |
19:16 |
N-1, where N is the size in bits of the command |
|
to send |
|||
LSB |
26:26 |
Sends the data starting from LSB |
|
QPI |
27:27 |
Sends the command using QuadSPI |
|
SPI_CMD |
31:28 |
Command to execute (0x2) |
|
0x4 |
SPI_CMD_DUMMY |
Receives a number of dummy bits |
|
which are not sent to the RX interface |
|||
DUMMY_CYCLE |
21:16 |
Number of dummy cycles to perform |
|
SPI_CMD |
31:28 |
Command to execute (0x4) |
|
0x5 |
SPI_CMD_WAIT |
Waits for an external event to move to the next |
|
instruction |
|||
EVENT_ID_CYCLE_COUNT |
6:0 |
External event id or Number of wait cycles |
|
WAIT_TYPE |
9:8 |
Type of wait: |
|
0x0: wait for and soc event selected by EVENT_ID |
|||
0x1: wait CYCLE_COUNT cycles |
|||
0x2: rfu |
|||
0x3: rfu |
|||
SPI_CMD |
31:28 |
Command to execute (0x5) |
|
0x6 |
SPI_CMD_TX_DATA |
Sends data (max 256Kbits) |
|
WORD_NUM |
15:0 |
N-1, where N is the number of words to send |
|
(max 64K) |
|||
WORD_SIZE |
20:16 |
N-1, where N is the number of bits in each word |
|
WORD_PER_TRANSF |
22:21 |
Number of words transferred from SRAM at |
|
each transfer |
|||
0x0: 1 word per transfer |
|||
0x1: 2 words per transfer |
|||
0x2: 4 words per transfer |
|||
LSB |
26:26 |
0x0: MSB first |
|
0x1: LSB first |
|||
QPI |
27:27 |
0x0: single bit data |
|
0x1: quad SPI mode |
|||
SPI_CMD |
31:28 |
Command to execute (0x6) |
|
0x7 |
SPI_CMD_RX_DATA |
Receives data (max 256Kbits) |
|
WORD_NUM |
15:0 |
N-1, where N is the number of words to send |
|
(max 64K) |
|||
WORD_SIZE |
20:16 |
N-1, where N is the number of bits in each word |
|
WORD_PER_TRANSF |
22:21 |
Number of words transferred from SRAM at |
|
each transfer |
|||
0x0: 1 word per transfer |
|||
0x1: 2 words per transfer |
|||
0x2: 4 words per transfer |
|||
LSB |
26:26 |
0x0: MSB first |
|
0x1: LSB first |
|||
QPI |
27:27 |
0x0: single bit data |
|
0x1: quad SPI mode |
|||
SPI_CMD |
31:28 |
Command to execute (0x7) |
|
0x8 |
SPI_CMD_RPT |
Repeat the commands until RTP_END for N |
|
times |
|||
RPT_CNT |
15:0 |
Number of repeat iterations (max 64K) |
|
SPI_CMD |
31:28 |
Command to execute (0x8) |
|
0x9 |
SPI_CMD_EOT |
Clears the Chip Select (CS) |
|
EVENT_GEN |
0:0 |
Enable EOT event: |
|
0x0: disable |
|||
0x1: enable |
|||
SPI_CMD |
31:28 |
Command to execute (0x9) |
|
0xA |
SPI_CMD_RPT_END |
End of the repeat loop command |
|
SPI_CMD |
31:28 |
Command to execute (0xA) |
|
0xB |
SPI_CMD_RX_CHECK |
Checks up to 16 bits of data against an expected |
|
value |
|||
COMP_DATA |
15:0 |
Data to compare |
|
STATUS_SIZE |
19:16 |
N-1, where N is the size in bits of the word |
|
to read |
|||
CHECK_TYPE |
25:24 |
How to compare: |
|
0x0: compare bit by bit |
|||
0x1: compare only ones |
|||
0x2: compare only zeros |
|||
LSB |
26:26 |
0x0: Receieved data is LSB first |
|
0x1: Received data is MSB first |
|||
QPI |
27:27 |
0x0: single bit data |
|
0x1: quad SPI mode |
|||
SPI_CMD |
31:28 |
Command to execute (0xB) |
|
0xC |
SPI_CMD_FULL_DUPL |
Activate full duplex mode |
|
DATA_SIZE |
15:0 |
N-1, where N is the number of bits to send |
|
(max 64K) |
|||
LSB |
26:26 |
0x0: Data is LSB first |
|
0x1: Data is MSB first |
|||
SPI_CMD |
31:28 |
Command to execute (0xC) |
|
0xD |
SPI_CMD_SETUP_UCA |
Sets address for uDMA tx/rx channel |
|
START_ADDR |
20:0 |
Address of start of buffer |
|
SPI_CMD |
31:28 |
Command to execute (0xD) |
|
0xE |
SPI_CMD_SETUP_UCS |
Sets size and starts uDMA tx/rx channel |
|
SIZE |
N-1, where N is the number of bytes to transfer |
||
(max size depends on the TRANS_SIZE parameter) |
|||
WORD_PER_TRANSF |
26:25 |
Number of words from SRAM for each transfer: |
|
0x0: 1 word per transfer |
|||
0x1: 2 words per transfer |
|||
0x2: 4 words per transfer |
|||
TX_RXN |
27:27 |
Selects TX or RX channel: |
|
0x0: RX channel |
|||
0x1: TX channel |
|||
SPI_CMD |
31:28 |
Command to execute (0xE) |
|
UDMA QSPI CSRs
RX_SADDR offset = 0x0
Field |
Bits |
Type |
Default |
Description |
---|---|---|---|---|
SADDR |
11:0 |
RW |
Address of receive buffer on write; current address on read |
RX_SIZE offset = 0x04
Field |
Bits |
Type |
Default |
Description |
---|---|---|---|---|
SIZE |
15:0 |
RW |
Size of receive buffer on write; bytes left on read |
RX_CFG offset = 0x08
Field |
Bits |
Type |
Default |
Description |
---|---|---|---|---|
CLR |
6:6 |
WO |
Clear the receive channel |
|
PENDING |
5:5 |
RO |
Receive transaction is pending |
|
EN |
4:4 |
RW |
Enable the receive channel |
|
DATASIZE |
2:1 |
RW |
0x02 |
Controls uDMA address increment |
0x00: increment address by 1 (data is 8 bits) |
||||
0x01: increment address by 2 (data is 16 bits) |
||||
0x02: increment address by 4 (data is 32 bits) |
||||
0x03: increment address by 0 |
||||
CONTINUOUS |
0:0 |
RW |
0x0: stop after last transfer for channel |
|
0x1: after last transfer for channel, |
||||
reload buffer size and start address and restart channel |
TX_SADDR offset = 0x10
Field |
Bits |
Type |
Default |
Description |
---|---|---|---|---|
SADDR |
11:0 |
RW |
Address of Tx buffer on write; current address on read |
TX_SIZE offset = 0x14
Field |
Bits |
Type |
Default |
Description |
---|---|---|---|---|
SIZE |
15:0 |
RW |
Size of receive buffer on write; bytes left on read |
TX_CFG offset = 0x18
Field |
Bits |
Type |
Default |
Description |
---|---|---|---|---|
CLR |
6:6 |
WO |
Clear the transmit channel |
|
PENDING |
5:5 |
RO |
Transmit transaction is pending |
|
EN |
4:4 |
RW |
Enable the transmit channel |
|
DATASIZE |
2:1 |
WO |
0x02 |
Controls uDMA address increment (Reads as 0x00) |
0x00: increment address by 1 (data is 8 bits) |
||||
0x01: increment address by 2 (data is 16 bits) |
||||
0x02: increment address by 4 (data is 32 bits) |
||||
0x03: increment address by 0 |
||||
CONTINUOUS |
0:0 |
RW |
0x0: stop after last transfer for channel |
|
0x1: after last transfer for channel, |
||||
reload buffer size and start address and restart channel |
CMD_SADDR offset = 0x20
Field |
Bits |
Type |
Default |
Description |
---|---|---|---|---|
SADDR |
31:0 |
RW |
0x00 |
Address of command memory buffer: |
Read: current address until transfer is complete, then 0x00 |
||||
Write: start addrress of command buffer |
CMD_SIZE offset = 0x24
Field |
Bits |
Type |
Default |
Description |
---|---|---|---|---|
SIZE |
20:0 |
RW |
Buffer size in bytes (1MByte maximum) |
|
Read: bytes remaining to be transferred |
||||
Write: number of bytes to transmit |
CMD_CFG offset = 0x28
Field |
Bits |
Type |
Default |
Description |
---|---|---|---|---|
CLR |
6:6 |
WO |
Clear the transmit channel |
|
PENDING |
5:5 |
RO |
Transmit transaction is pending |
|
EN |
4:4 |
RW |
Enable the transmit channel |
|
DATASIZE |
2:1 |
WO |
0x02 |
Controls uDMA address increment (Reads as 0x02) |
0x00: increment address by 1 (data is 8 bits) |
||||
0x01: increment address by 2 (data is 16 bits) |
||||
0x02: increment address by 4 (data is 32 bits) |
||||
0x03: increment address by 0 |
||||
CONTINUOUS |
0:0 |
RW |
0x0: stop after last transfer for channel |
|
0x1: after last transfer for channel, |
||||
reload buffer size and start address and restart channel |
STATUS offset = 0x30
Field |
Bits |
Type |
Default |
Description |
---|---|---|---|---|
BUSY |
1:0 |
RO |
Status: |
|
0x00: STAT_NONE |
||||
0x01: STAT_CHECK (matched) |
||||
0x02: STAT_EOL (end of loop) |