<<<
:sectnums:
==== Serial Peripheral Interface Controller (SPI)

[cols="<3,<3,<4"]
[grid="none"]
|=======================
| Hardware source files:  | neorv32_spi.vhd    |
| Software driver files:  | neorv32_spi.c      | link:https://stnolting.github.io/neorv32/sw/neorv32__spi_8c.html[Online software reference (Doxygen)]
|                         | neorv32_spi.h      | link:https://stnolting.github.io/neorv32/sw/neorv32__spi_8h.html[Online software reference (Doxygen)]
| Top entity ports:       | `spi_clk_o`        | 1-bit serial clock output
|                         | `spi_dat_o`        | 1-bit serial data output
|                         | `spi_dat_i`        | 1-bit serial data input
|                         | `spi_csn_o`        | 8-bit dedicated chip select output (low-active)
| Configuration generics: | `IO_SPI_EN`        | implement SPI controller when `true`
|                         | `IO_SPI_FIFO`      | FIFO depth, has to be a power of two, min 1
| CPU interrupts:         | fast IRQ channel 6 | configurable SPI interrupt (see <<_processor_interrupts>>)
|=======================

**Key Features**

* SPI-compatible host controller
* Programmable clock phase and polarity
* Fine-grained programmable clock
* 8 dedicated chip-select lines
* Optional data/command FIFO (ring-buffer)
* Interrupt if programmed transfer sequences have completed


**Overview**

The NEORV32 SPI module provides a **host-mode** serial peripheral interface. The module operates on byte-wide data,
supports all 4 standard SPI clock modes, provides a precise SPI clock generator and implements 8 dedicated chip select
signals via the top entity's `spi_csn_o` signal. An optional receive/transmit ring-buffer/FIFO can be configured
via the `IO_SPI_FIFO` generic to support programming of complete SPI transmissions without CPU interaction.

.Host-Mode Only
[NOTE]
The NEORV32 SPI module only supports _host mode_. Transmission are initiated only by the SPI
module itself. If you are looking for a _device-mode_ serial peripheral interface (transactions
initiated by an external host) check out the <<_serial_data_interface_controller_sdi>>.


**Theory of Operation**

The SPI module provides a single control register `CTRL` to configure the module and to check it's status and a single
data register `DATA` for receiving/transmitting data and for issuing chip-select commands.

The SPI module is enabled by setting the `SPI_CTRL_EN` bit in the `CTRL` control register. No transfer can be initiated
and no interrupt request will be triggered if this bit is cleared. Clearing this bit resets the entire module, clears
the RX/TX FIFO and terminates any transfer being in process.

The actual SPI transfer (receiving one byte while also sending one byte) as well as control of the chip-select lines is
handled by the module's `DATA` register. Note that this register will access the TX FIFO of the ring-buffer when writing
to it and will access the RX FIFO of the ring-buffer when reading from it.

The most significant bit of the `DATA` register (`SPI_DATA_CMD`) is used to select the purpose of the data being written.
When the `SPI_DATA_CMD` is cleared, the lowest 8-bit represent the actual SPI TX data that will be transmitted by the
SPI engine. After completion, the according receive data is pushed to the RX FIFO.

If `SPI_DATA_CMD` is set, the lowest 4-bit control the chip-select lines. In this case, bits `2:0` select one of the eight
chip-select lines. The selected line will become enabled when bit `3` is set. If bit `3` is cleared, all chip-select
lines will be disabled at once. Note that the bits of the `spi_csn_o` port are low-active. Only one chip-select can be
active at a time.

Since all SPI operations are controlled via the FIFOs, entire SPI sequences (chip-enable, data transmission(s), chip-disable)
can be _programmed_. Thus, SPI operations can be executed without any CPU interaction at all and can also be coordinated by
the system's DMA controller.


**SPI Clock Configuration**

The SPI module supports all standard SPI clock modes (0, 1, 2, 3), which are configured via the two control register bits
`SPI_CTRL_CPHA` and `SPI_CTRL_CPOL`. The `SPI_CTRL_CPHA` bit defines the _clock phase_ and the `SPI_CTRL_CPOL`
bit defines the _clock polarity_.

.SPI Clock Modes
[wavedrom, format="svg", align="center"]
----
{signal: [
  [
    "SCK",
    {name: 'CPOL=0', wave: 'l.hlhlhlhlhlhlhlhl.'},
    {name: 'CPOL=1', wave: 'h.lhlhlhlhlhlhlhlh.'},
  ],
  {},
  [
    "CPHA=0",
    {name: 'Host in',  wave: 'x2.3.4.5.6.7.8.9.x.', data: ['1', '2', '3', '4', '5', '6', '7', '8']},
    {name: 'Host out', wave: 'x2.3.4.5.6.7.8.9.x.', data: ['1', '2', '3', '4', '5', '6', '7', '8']},
  ],
  {},
  [
    "CPHA=1",
    {name: 'Host in',  wave: 'x.2.3.4.5.6.7.8.9.x', data: ['1', '2', '3', '4', '5', '6', '7', '8']},
    {name: 'Host out', wave: 'x.2.3.4.5.6.7.8.9.x', data: ['1', '2', '3', '4', '5', '6', '7', '8']},
  ]
],
 edge: ['ab', 'a~>c', 'c~>d', 'd~>e', 'fg', 'hi', 'h~>j', 'j~>k', 'k~>l', 'mn']
}
----

The SPI clock frequency (`spi_clk_o`) is programmed by the 3-bit `SPI_CTRL_PRSCx` clock prescaler for a coarse clock
selection and a 4-bit clock divider `SPI_CTRL_CDIVx` for a fine clock configuration. The following clock prescalers
(`SPI_CTRL_PRSCx`) are available:

.SPI prescaler configuration
[cols="<4,^1,^1,^1,^1,^1,^1,^1,^1"]
[options="header",grid="rows"]
|=======================
| **`SPI_CTRL_PRSC[2:0]`**    | `0b000` | `0b001` | `0b010` | `0b011` | `0b100` | `0b101` | `0b110` | `0b111`
| Resulting `clock_prescaler` |       2 |       4 |       8 |      64 |     128 |    1024 |    2048 |    4096
|=======================

Based on the programmed clock configuration, the actual SPI clock frequency f~SPI~ is derived
from the processor's main clock f~main~ according to the following equation:

_**f~SPI~**_ = _f~main~[Hz]_ / (2 * `clock_prescaler` * (1 + `SPI_CTRL_CDIVx`))

Hence, the maximum SPI clock is f~main~ / 4 and the lowest SPI clock is f~main~ / 131072.
The SPI clock is always symmetric having a duty cycle of exactly 50%.


**SPI Interrupt**

The SPI module provides a single interrupt that gets triggered when the programmed SPI sequence
has completed (i.e. the TX FIFO is empty and the SPI engine is idle).


**Register Map**

.SPI register map (`struct NEORV32_SPI`)
[cols="<2,<1,<4,^1,<7"]
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.14+<| `0xfff80000` .14+<| `CTRL` <|`0`     `SPI_CTRL_EN`                           ^| r/w <| SPI module enable
                                  <|`1`     `SPI_CTRL_CPHA`                         ^| r/w <| clock phase
                                  <|`2`     `SPI_CTRL_CPOL`                         ^| r/w <| clock polarity
                                  <|`5:3`   `SPI_CTRL_PRSC2 : SPI_CTRL_PRSC0`       ^| r/w <| 3-bit clock prescaler select
                                  <|`9:6`   `SPI_CTRL_CDIV3 : SPI_CTRL_CDIV0`       ^| r/w <| 4-bit clock divider for fine-tuning
                                  <|`15:10` -                                       ^| r/- <| _reserved_, read as zero
                                  <|`16`    `SPI_CTRL_RX_AVAIL`                     ^| r/- <| RX FIFO data available (RX FIFO not empty)
                                  <|`17`    `SPI_CTRL_TX_EMPTY`                     ^| r/- <| TX FIFO empty
                                  <|`18`    `SPI_CTRL_TX_FULL`                      ^| r/- <| TX FIFO full
                                  <|`23:19` -                                       ^| r/- <| _reserved_, read as zero
                                  <|`27:24` `SPI_CTRL_FIFO_MSB : SPI_CTRL_FIFO_LSB` ^| r/- <| FIFO depth; log2(`IO_SPI_FIFO`)
                                  <|`29:28` -                                       ^| r/- <| _reserved_, read as zero
                                  <|`30`    `SPI_CS_ACTIVE`                         ^| r/- <| Set if any chip-select line is active
                                  <|`31`    `SPI_CTRL_BUSY`                         ^| r/- <| SPI module busy when set (serial engine operation in progress and TX FIFO not empty yet)
.4+<| `0xfff80004` .4+<| `DATA` <|`7:0`  `SPI_DATA_MSB : SPI_DATA_LSB` ^| r/w <| receive/transmit data (FIFO), only for data mode (`SPI_DATA_CMD = 0`)
                                <|`3:0`                                ^| -/w <| chip-select-enable (bit 3) and chip-select (bit 2:0), only for command mode (`SPI_DATA_CMD = 1`)
                                <|`30:8` -                             ^| r/- <| _reserved_, read as zero
                                <|`31`   `SPI_DATA_CMD`                ^| -/w <| `0` = data, `1` = chip-select-command
|=======================
