Serial peripheral interface (SPI) host

The SPI in Sonata only has the capability to be a host. This is a simple hardware IP block that can transmit and receive bytes over SPI.

In Sonata, there are multiple uses for SPI:

  • LCD screen
  • Ethernet
  • Flash
  • Raspberry Pi hat
  • Arduino shield
  • mikroBUS

The current Sonata system configuration has two SPI instantiations, one for the LCD screen and one for Flash. The Sonata top-level will need modification to add more SPI blocks for other uses.

The offset for each of the blocks is shown below, with each additional block having a 0x1000 offset from the previous.

SPI InstanceOffset (from SPI base)
Flash0x0
LCD Screen0x1000
Ethernet MAC0x2000
Raspberry Pi HAT SPI00x3000
Raspberry Pi HAT SPI10x4000
Arduino Shield0x5000
mikroBUS Click0x6000

Overview

Each SPI block has a two 64 entry FIFOs one for transmit and one for receive. To begin an SPI transaction write to the START register. Bytes do not need to be immediately available in the transmit FIFO nor space available in the receive FIFO to begin the transaction. The SPI block will only run the clock when its able to proceed. Note that the CS pin is not handled by the SPI block and must be dealt with via GPIO and controlled with software.

Note Interrupts are not yet implemented

Register Table

NameOffsetLengthDescription
spi.INTR_STATE0x04Interrupt State Register
spi.INTR_ENABLE0x44Interrupt Enable Register
spi.INTR_TEST0x84Interrupt Test Register
spi.CFG0xc4Configuration register. Controls how the SPI block transmits
spi.CONTROL0x104Controls the operation of the SPI block. This register can
spi.STATUS0x144Status information about the SPI block
spi.START0x184When written begins an SPI operation. Writes are ignored when the
spi.RX_FIFO0x1c4Data from the receive FIFO. When read the data is popped from the
spi.TX_FIFO0x204Bytes written here are pushed to the transmit FIFO. If the FIFO

INTR_STATE

Interrupt State Register

  • Offset: 0x0
  • Reset default: 0x0
  • Reset mask: 0x1f

Fields

[{"name": "rx_full", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "rx_watermark", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "tx_empty", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "tx_watermark", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "complete", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"bits": 27}]
BitsTypeResetNameDescription
31:5Reserved
4rw1c0x0completeOn-going SPI operation has completed and the block is now idle
3ro0x0tx_watermarkTransmit FIFO level is at or below watermark
2ro0x0tx_emptyTransmit FIFO is empty
1ro0x0rx_watermarkReceive FIFO level is at or above watermark
0ro0x0rx_fullReceive FIFO is full

INTR_ENABLE

Interrupt Enable Register

  • Offset: 0x4
  • Reset default: 0x0
  • Reset mask: 0x1f

Fields

[{"name": "rx_full", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "rx_watermark", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "tx_empty", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "tx_watermark", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "complete", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 27}]
BitsTypeResetNameDescription
31:5Reserved
4rw0x0completeEnable interrupt when INTR_STATE.complete is set.
3rw0x0tx_watermarkEnable interrupt when INTR_STATE.tx_watermark is set.
2rw0x0tx_emptyEnable interrupt when INTR_STATE.tx_empty is set.
1rw0x0rx_watermarkEnable interrupt when INTR_STATE.rx_watermark is set.
0rw0x0rx_fullEnable interrupt when INTR_STATE.rx_full is set.

INTR_TEST

Interrupt Test Register

  • Offset: 0x8
  • Reset default: 0x0
  • Reset mask: 0x1f

Fields

[{"name": "rx_full", "bits": 1, "attr": ["wo"], "rotate": -90}, {"name": "rx_watermark", "bits": 1, "attr": ["wo"], "rotate": -90}, {"name": "tx_empty", "bits": 1, "attr": ["wo"], "rotate": -90}, {"name": "tx_watermark", "bits": 1, "attr": ["wo"], "rotate": -90}, {"name": "complete", "bits": 1, "attr": ["wo"], "rotate": -90}, {"bits": 27}]
BitsTypeResetNameDescription
31:5Reserved
4wo0x0completeWrite 1 to force INTR_STATE.complete to 1.
3wo0x0tx_watermarkWrite 1 to force INTR_STATE.tx_watermark to 1.
2wo0x0tx_emptyWrite 1 to force INTR_STATE.tx_empty to 1.
1wo0x0rx_watermarkWrite 1 to force INTR_STATE.rx_watermark to 1.
0wo0x0rx_fullWrite 1 to force INTR_STATE.rx_full to 1.

CFG

Configuration register. Controls how the SPI block transmits and receives data. This register can only be modified whilst the SPI block is idle.

  • Offset: 0xc
  • Reset default: 0x20000000
  • Reset mask: 0xe000ffff

Fields

[{"name": "HALF_CLK_PERIOD", "bits": 16, "attr": ["rw"], "rotate": 0}, {"bits": 13}, {"name": "MSB_FIRST", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "CPHA", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "CPOL", "bits": 1, "attr": ["rw"], "rotate": -90}]
BitsTypeResetName
31rw0x0CPOL
30rw0x0CPHA
29rw0x1MSB_FIRST
28:16Reserved
15:0rw0x0HALF_CLK_PERIOD

CFG . CPOL

The polarity of the spi_clk signal. When CPOL is 0 clock is low when idle and the leading edge is positive. When CPOL is 1 clock is high when idle and the leading edge is negative

CFG . CPHA

The phase of the spi_clk signal. When CPHA is 0 data is sampled on the leading edge and changes on the trailing edge. The first data bit is immediately available before the first leading edge of the clock when transmission begins. When CPHA is 1 data is sampled on the trailing edge and change on the leading edge.

CFG . MSB_FIRST

When set the most significant bit (MSB) is the first bit sent and received with each byte

CFG . HALF_CLK_PERIOD

The length of a half period (i.e. positive edge to negative edge) of the SPI clock, measured in system clock cycles reduced by 1. At the standard Sonata 50 MHz system clock a value of 0 gives a 25 MHz SPI clock, a value of 1 gives a 12.5 MHz SPI clock, a value of 2 gives a 8.33 MHz SPI clock and so on.

CONTROL

Controls the operation of the SPI block. This register can only be modified whilst the SPI block is idle.

  • Offset: 0x10
  • Reset default: 0x0
  • Reset mask: 0xfff

Fields

[{"name": "TX_CLEAR", "bits": 1, "attr": ["wo"], "rotate": -90}, {"name": "RX_CLEAR", "bits": 1, "attr": ["wo"], "rotate": -90}, {"name": "TX_ENABLE", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "RX_ENABLE", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "TX_WATERMARK", "bits": 4, "attr": ["rw"], "rotate": -90}, {"name": "RX_WATERMARK", "bits": 4, "attr": ["rw"], "rotate": -90}, {"bits": 20}]
BitsTypeResetName
31:12Reserved
11:8rw0x0RX_WATERMARK
7:4rw0x0TX_WATERMARK
3rw0x0RX_ENABLE
2rw0x0TX_ENABLE
1wo0x0RX_CLEAR
0wo0x0TX_CLEAR

CONTROL . RX_WATERMARK

The watermark level for the receive FIFO, depending on the value the interrupt will trigger at different points:

  • 0: 1 or more items in the FIFO
  • 1: 2 or more items in the FIFO
  • 2: 4 or more items in the FIFO
  • 3: 8 or more items in the FIFO
  • 4: 16 or more items in the FIFO
  • 5: 32 or more items in the FIFO
  • 6: 56 or more items in the FIFO

CONTROL . TX_WATERMARK

The watermark level for the transmit FIFO, depending on the value the interrupt will trigger at different points:

  • 0: 1 or fewer items in the FIFO
  • 1: 2 or fewer items in the FIFO
  • 2: 4 or fewer items in the FIFO
  • 3: 8 or fewer items in the FIFO
  • 4: 16 or fewer items in the FIFO

CONTROL . RX_ENABLE

When set incoming bits are written to the receive FIFO. When clear incoming bits are ignored.

CONTROL . TX_ENABLE

When set bytes from the transmit FIFO are sent. When clear the state of the outgoing spi_cipo is undefined whilst the SPI clock is running.

CONTROL . RX_CLEAR

Write 1 to clear the receive FIFO.

CONTROL . TX_CLEAR

Write 1 to clear the transmit FIFO.

STATUS

Status information about the SPI block

  • Offset: 0x14
  • Reset default: 0x0
  • Reset mask: 0x7ffff

Fields

[{"name": "TX_FIFO_LEVEL", "bits": 8, "attr": ["ro"], "rotate": 0}, {"name": "RX_FIFO_LEVEL", "bits": 8, "attr": ["ro"], "rotate": 0}, {"name": "TX_FIFO_FULL", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "RX_FIFO_EMPTY", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "IDLE", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 13}]
BitsTypeResetNameDescription
31:19Reserved
18roxIDLEWhen set the SPI block is idle and can accept a new start command.
17roxRX_FIFO_EMPTYWhen set the receive FIFO is empty and any data read from it will be undefined.
16roxTX_FIFO_FULLWhen set the transmit FIFO is full and any data written to it will be ignored.
15:8roxRX_FIFO_LEVELNumber of items in the receive FIFO
7:0roxTX_FIFO_LEVELNumber of items in the transmit FIFO

START

When written begins an SPI operation. Writes are ignored when the SPI block is active.

  • Offset: 0x18
  • Reset default: 0x0
  • Reset mask: 0x7ff

Fields

[{"name": "BYTE_COUNT", "bits": 11, "attr": ["wo"], "rotate": 0}, {"bits": 21}]
BitsTypeResetNameDescription
31:11Reserved
10:0wo0x0BYTE_COUNTNumber of bytes to receive/transmit in the SPI operation

RX_FIFO

Data from the receive FIFO. When read the data is popped from the FIFO. If the FIFO is empty data read is undefined.

  • Offset: 0x1c
  • Reset default: 0x0
  • Reset mask: 0xff

Fields

[{"name": "DATA", "bits": 8, "attr": ["ro"], "rotate": 0}, {"bits": 24}]
BitsTypeResetNameDescription
31:8Reserved
7:0roxDATAByte popped from the FIFO

TX_FIFO

Bytes written here are pushed to the transmit FIFO. If the FIFO is full writes are ignored.

  • Offset: 0x20
  • Reset default: 0x0
  • Reset mask: 0xff

Fields

[{"name": "DATA", "bits": 8, "attr": ["wo"], "rotate": 0}, {"bits": 24}]
BitsTypeResetNameDescription
31:8Reserved
7:0wo0x0DATAByte to push to the FIFO