The spi(serial peripheral interface)
IP is a fully parameterised soft IP to implement the Motorola SPI standard protocol. The IP features an APB4 slave interface, fully compliant with the AMBA APB Protocol Specification v2.0.
- Compatible with Motorola SPI standard
- Half duplex serial data transmission
- SPI master mode only
- Standard, dual and quad SPI mode support
- Max 4 slave device select
- Programmable prescaler
- max division factor is up to 2^16
- MSB or LSB bit transmission order
- Hardware or Software NSS configuration
- 8, 16, 24 or 32 bits data transmission size
- 1~65536 transmission length with hardware NSS
- All CPOL and CPHA mode support
- Programmable dummay and delay cycles configuration
- Independent send and receive FIFO
- 16~64 data depth
- empty or no-emtpy status flag
- Maskable send or receive interrupt and programmable threshold
- Static synchronous design
- Full synthesizable
port name | type | description |
---|---|---|
apb4 | interface | apb4 slave interface |
spi -> | interface | spi slave interface |
spi.spi_sck_o |
output | spi serial clock output |
spi.spi_nss_o |
output | spi slave select output |
spi.spi_io_en_o |
output | spi output enable |
spi.spi_io_in_i |
input | spi data input |
spi.spi_io_out_o |
output | spi data output |
spi.irq_o |
output | interrupt output |
name | offset | length | description |
---|---|---|---|
CTRL1 | 0x0 | 4 | control 1 register |
CTRL2 | 0x4 | 4 | control 2 register |
DIV | 0x8 | 4 | divide register |
CAL | 0xC | 4 | command address length register |
TAL | 0x10 | 4 | transmit receive length reigster |
TXR | 0x14 | 4 | transmit register |
RXR | 0x18 | 4 | receive register |
STAT | 0x1C | 4 | state register |
bit | access | description |
---|---|---|
[31:22] |
none | reserved |
[21:20] |
RW | SPM |
[19:15] |
RW | RXTH |
[14:10] |
RW | TXTH |
[9:8] |
RW | RDTB |
[7:6] |
RW | TDTB |
[5:5] |
RW | SSTR |
[4:4] |
RW | RDM |
[3:3] |
RW | ASS |
[2:2] |
RW | LSB |
[1:1] |
RW | CPOL |
[0:0] |
RW | CPHA |
reset value: 0x0000_0000
-
SPM: spi mode
SPM = 2'b00
: std spi modeSPM = 2'b01
: dual spi modeSPM = 2'b10
: quad spi modeSPM = 2'b11
: qpi mode
-
RXTH: receive fifo interrupt threshold
-
TXTH: transmit fifo interrupt threshold
-
RDTB: size of single receive data
RDTB = 2'b00
: 8-bitRDTB = 2'b01
: 16-bitRDTB = 2'b10
: 24-bitRDTB = 2'b11
: 32-bit
-
TDTB: size of single transmit data
TDTB = 2'b00
: 8-bitTDTB = 2'b01
: 16-bitTDTB = 2'b10
: 24-bitTDTB = 2'b11
: 32-bit
-
SSTR: slave select transmit receive(no use)
SSTR = 1'b0
: spi master modeSSTR = 1'b1
: spi slave mode
-
RDM: reverse data mode
RDM = 1'b0
: normal read dataRDM = 1'b1
: byte-reverse of read data
-
ASS: automate slave select
ASS = 1'b0
: software slave selectASS = 1'b1
: hardware slave select
-
LSB: serial send the LSB first
LSB = 1'b0
: send MSB firstLSB = 1'b1
: send LSB first
-
CPOL: clock polarity
CPOL = 1'b0
: idle clock is highCPOL = 1'b1
: idle clock is low
-
CPHA: clock phase
CPHA = 1'b0
: sample along the first clock edgeCPHA = 1'b1
: sample along the second clock edge
bit | access | description |
---|---|---|
[31:17] |
none | reserved |
[16:13] |
RW | SNM |
[12:9] |
RW | CSV |
[8:5] |
RW | NSS |
[4:4] |
RW | RWM |
[3:3] |
RW | ST |
[2:2] |
RW | EN |
[1:1] |
RW | RXIE |
[0:0] |
RW | TXIE |
-
SNM: serial data numuber
-
CSV: 4-bit chip select reverse
-
NSS: 4-bit software slave select
-
RWM: read write mode
RWM = 1'b0
: write only modeRWM = 1'b1
: write/read mode
-
ST: start transmit
ST = 1'b0
: dont transmit dataST = 1'b1
: otherwise
-
EN: spi core enable
EN = 1'b0
: enable spi coreEN = 1'b1
: otherwise
-
RXIE: receive interrupt enable
RXIE = 1'b0
: disable receieve interruptRXIE = 1'b1
: otherwise
-
TXIE: transmit interrupt enable
TXIE = 1'b0
: disable transmit interruptTXIE = 1'b1
: otherwise
bit | access | description |
---|---|---|
[31:16] |
none | reserved |
[15:0] |
RW | DIV |
reset value: 0x000_0000
- DIV: 16-bit clock division value
bit | access | description |
---|---|---|
[31:16] |
none | reserved |
[15:0] |
WO | CAL |
reset value: 0x0000_0000
- CAL: command address transmit length
bit | access | description |
---|---|---|
[31:16] |
none | reserved |
[15:0] |
WO | TRL |
reset value: 0x0000_0000
- TRL: transmit receive length
bit | access | description |
---|---|---|
[31:0] |
WO | TXDATA |
reset value: none
- TXDATA: transmit data
bit | access | description |
---|---|---|
[31:0] |
RO | RXDATA |
reset value: 0x0000_0000
- RXDTA: receive data
bit | access | description |
---|---|---|
[31:5] |
none | reserved |
[4:4] |
RO | RETY |
[3:3] |
RO | TFUL |
[2:2] |
RO | BUSY |
[1:1] |
RO | RXIF |
[0:0] |
RO | TXIF |
reset value: 0x0000_0000
-
RETY: receive fifo empty
RETY = 1'b0
: receive fifo is not emptyRETY = 1'b1
: otherwise
-
TFUL: transmit fifo full
TFUL = 1'b0
: transmit fifo is not fullTFUL = 1'b1
: otherwise
-
BUSY: transmit busy
BUSY = 1'b0
: transmit in progressBUSY = 1'b1
: otherwise
-
RXIF: receive interrupt flag
RXIF = 1'b0
: dont trigger receive interruptRXIF = 1'b1
: otherwise
-
TXIF: transmit interrupt flag
RXIF = 1'b0
: dont trigger transmit interruptRXIF = 1'b1
: otherwise
These registers can be accessed by 4-byte aligned read and write. C-like pseudocode standard spi write operation to w25q128 nor flash:
// mode 0(CPOL = 0 CPHA = 0)
spi.DIV = DIV_32_bit // set clock division
spi.CTRL1.ASS = 1 // hardware slave select mode
spi.CTRL2.NSS[0] = 1 // use the one slave select bit
spi.CTRL2.EN = 0 // clear fifo
spi.CTRL2.EN = 1 // enter in normal mode
spi.TXR = 0x06 // set write enable command
spi.CTRL2.[NSS[0], ST, EN] = 1 // start transmit
...
spi.CTRL1.ASS = 1
spi.CTRL1.[RDTB, TDTB] = 3 // set transmit block size to 32-bit
spi.TXR = (0x02 << 24) | PAGE_24_bit // set page program + page addr
for (int i = 0; i < WRITE_DATA_NUM; ++i) {
while(spi.STAT.TFUL == 1); // wait trans fifo is no full
spi.TXR = WRITE_VALUE
}
spi.CAL = 0
spi.TRL = WRITE_DATA_NUM + 1
spi.CTRL2.[NSS[0], ST, EN] = 1 // start transmit
while(spi.STAT.busy == 1); // wait data transmit done
read operation:
spi.TXR = (0x03 << 24) | PAGE_24_bit // set read command + page addr
spi.CAL = WRITE_DATA_NUM
spi.TRL = WRITE_DATA_NUM + 1
spi.CTRL2.[NSS[0], RWM, ST, EN] = 1 // start read data
for (int i = 0; i < WRITE_DATA_NUM; ++i) {
while(spi.STAT.RETY == 1); // wait recv fifo is no empty
uint32_t recv_val = spi.RXR
}
complete driver and test codes in driver dir.