Projet_SETI_RISC-V/neorv32/docs/datasheet/soc_spi.adoc
2023-03-06 14:48:14 +01:00

172 lines
10 KiB
Text

<<<
:sectnums:
==== Serial Peripheral Interface Controller (SPI)
[cols="<3,<3,<4"]
[frame="topbot",grid="none"]
|=======================
| Hardware source file(s): | neorv32_spi.vhd |
| Software driver file(s): | neorv32_spi.c |
| | neorv32_spi.h |
| Top entity port: | `spi_sck_o` | 1-bit serial clock output
| | `spi_sdo_o` | 1-bit serial data output
| | `spi_sdi_i` | 1-bit serial data input
| | `spi_csn_i` | 8-bit dedicated chip select (low-active)
| Configuration generics: | _IO_SPI_EN_ | implement SPI controller when _true_
| | _IO_SPI_FIFO_ | data FIFO size, has to be zero or a power of two
| CPU interrupts: | fast IRQ channel 6 | transmission done interrupt (see <<_processor_interrupts>>)
|=======================
**Overview**
SPI is a synchronous serial transmission interface for fast on-board communications.
The NEORV32 SPI transceiver module supports 8-, 16-, 24- and 32-bit wide transmissions, all 4 standard clock modes
and 8 dedicated chip select signals via the top entity's `spi_csn_o` signal, which are
directly controlled by the SPI module (no additional GPIOs required). An optional receive/transmit FIFO can be
implemented via the _IO_SPI_FIFO_ generic to support block-based transmissions without CPU interaction.
.Host-Mode Only
[NOTE]
The NEORV32 SPI module only supports _host mode_. Transmission are initiated only by the processor's SPI module
and not by an external SPI module.
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. If the data FIFO is implemented, this register
is used to interface the FIFO.
**Theory of Operation**
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 will reset the module (also clearing
the FIFO if implemented) and will also terminate any transfer being in process.
The data quantity to be transferred within a single data transmission is defined via the _SPI_CTRL_SIZEx_ bits.
The SPI module supports 8-bit (`00`), 16-bit (`01`), 24-bit (`10`) and 32-bit (`11`) transfers.
A transmission is started when writing data to the `DATA` register. The data must be LSB-aligned. So if
the SPI transceiver is configured for less than 32-bit transfer data quantity, the transmit data must be placed
into the lowest 8/16/24 bits of `DATA`. Vice versa, the received data is also always LSB-aligned. Application
software should only process the amount of bits that was configured using _SPI_CTRL_SIZEx_ when
reading `DATA`.
The SPI operation is completed as soon as the _SPI_CTRL_BUSY_ flag clears. If a FIFO size greater than zero is configured,
the busy flag clears when the current serial engine operation is completed and there is no data left in the send buffer.
.MSB-first Only
[NOTE]
The NEORV32 SPI module only support MSB-first mode. Data can be reversed before writing `DATA` (for TX) / after
reading `DATA` (for RX) to implement LSB-first transmissions. Note that in both cases data in `DATA` still
needs to be LSB-aligned.
.Arbitrary Transmission Length
[TIP]
The total transmission length, which can be an arbitrary number of individual data transfers, is left to the user:
after asserting chip-select an arbitrary amount of transmission with arbitrary data quantity (_SPI_CTRL_SIZEx_) can
be made before de-asserting chip-select again.
The SPI controller features 8 dedicated chip-select lines. These lines are controlled via the control register's
_SPI_CTRL_CS_SELx_ and _SPI_CTRL_CS_EN_ bits. The 3-bit _SPI_CTRL_CSx_ bits are used to select one out of the eight
dedicated chip select line. As soon as _SPI_CTRL_CS_EN_ is _set_ the selected chip select line is activated (driven _low_).
Note that disabling the SPI module via the _SPI_CTRL_EN_ bit will also deactivate any currently activated chip select line.
**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; image from https://en.wikipedia.org/wiki/File:SPI_timing_diagram2.svg (license: (Wikimedia) https://en.wikipedia.org/wiki/Creative_Commons[Creative Commons] https://creativecommons.org/licenses/by-sa/3.0/deed.en[Attribution-Share Alike 3.0 Unported])
image::SPI_timing_diagram2.wikimedia.png[]
.SPI standard clock modes
[cols="<2,^1,^1,^1,^1"]
[options="header",grid="rows"]
|=======================
| | Mode 0 | Mode 1 | Mode 2 | Mode 3
| _SPI_CTRL_CPOL_ | `0` | `0` | `1` | `1`
| _SPI_CTRL_CPHA_ | `0` | `1` | `0` | `1`
|=======================
The SPI clock frequency (`spi_sck_o`) is programmed by the 3-bit _SPI_CTRL_PRSCx_ clock prescaler for a coarse selection
and a 4-bit clock divider _SPI_CTRL_CDIVx_ for a fine selection.
The following pre-scalers (_SPI_CTRL_PRSCx_) are available:
.SPI prescaler configuration
[cols="<4,^1,^1,^1,^1,^1,^1,^1,^1"]
[options="header",grid="rows"]
|=======================
| **`SPI_CTRL_PRSCx`** | `0b000` | `0b001` | `0b010` | `0b011` | `0b100` | `0b101` | `0b110` | `0b111`
| Resulting `clock_prescaler` | 2 | 4 | 8 | 64 | 128 | 1024 | 2048 | 4096
|=======================
Based on the _SPI_CTRL_PRSCx_ and _SPI_CTRL_CDIVx_ 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 FIFO**
An optional FIFO buffer can be implemented by setting the _IO_SPI_FIFO_ generic to a value greater than zero.
Implementing a data FIFO allows (more) CPU-independent operation of the SPI module.
Internally, two FIFOs are implemented: one for TX data and one for RX data. However, these two FIFOs are transparent for
the software and operate as a single, unified "ring buffer". The status signals of the TX FIFO ("empty", "at least half full",
"full") are exposed as read-only signals via the SPI control register. In contrast, the RX FIFO only provides a "data available"
flag (= RX FIFO not empty) also exposed via the SPI control register.
.Double-Buffering
[TIP]
Application programs can implement "double buffering" when using the "FIFO less than half full" interrupt configuration
option (see below).
**SPI Interrupt**
The SPI module provides a single interrupt that can be used to signal certain transmission states to the CPU.
The actual interrupt condition is configured by the two _SPI_CTRL_IRQx_ bits in the SPI module's control register:
* `00`, `01` : trigger interrupt when SPI serial engine _completes_ current transmission
* `10` : trigger interrupt when TX FIFO _becomes_ less than half full; this mode is not available if _IO_SPI_FIFO_ is zero
* `11` : trigger interrupt when TX FIFO _becomes_ empty; this mode is not available if _IO_SPI_FIFO_ is zero
Once the SPI CPU is triggered it has to be explicitly cleared again by writing zero to the according
<<_mip>> CSR bit inside the SPI trap handler.
[IMPORTANT]
If no FIFO is implemented (_IO_SPI_FIFO_ = 0) the _SPI_CTRL_IRQx_ are hardwired to `00` statically configuring
"SPI serial engine _completes_ current transmission" as interrupt condition.
**Register Map**
.SPI register map (`struct NEORV32_SPI`)
[cols="<2,<2,<4,^1,<7"]
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.16+<| `0xffffffa8` .16+<| `NEORV32_SPI.CTRL` <|`0` _SPI_CTRL_EN_ ^| r/w <| SPI module enable
<|`1` _SPI_CTRL_CPHA_ ^| r/w <| clock phase (`0`=sample RX on rising edge & update TX on falling edge; `1`=sample RX on falling edge & update TX on rising edge)
<|`2` _SPI_CTRL_CPOL_ ^| r/w <| clock polarity
<|`4:3` _SPI_CTRL_SIZE1_ : _SPI_CTRL_SIZE0_ ^| r/w <| transfer size (`00`=8-bit, `01`=16-bit, `10`=24-bit, `11`=32-bit)
<|`7:5` _SPI_CTRL_CS_SEL2_ : _SPI_CTRL_CS_SEL0_ ^| r/w <| Direct chip-select 0..7
<|`8` _SPI_CTRL_CS_EN_ ^| r/w <| Direct chip-select enable; setting `spi_csn_o(x)` low when set
<|`11:9` _SPI_CTRL_PRSC2_ : _SPI_CTRL_PRSC0_ ^| r/w <| 3-bit clock prescaler select
<|`15:12` _SPI_CTRL_CDIV2_ : _SPI_CTRL_CDIV0_ ^| r/w <| 4-bit clock divider
<|`17:16` _SPI_CTRL_IRQ1_ : _SPI_CTRL_IRQ0_ ^| r/w <| interrupt configuration (`0-` = SPI serial engine becomes idle, `10` = TX FIFO _become_ less than half full, `11` = TX FIFO _becomes_ empty)
<|`22:18` _reserved_ ^| r/- <| reserved, read as zero
<|`26:23` _SPI_CTRL_FIFO_MSB_ : _SPI_CTRL_FIFO_LSB_ ^| r/- <| FIFO depth; log2(_IO_SPI_FIFO_)
<|`27` _SPI_CTRL_RX_AVAIL_ ^| r/- <| RX FIFO data available (RX FIFO not empty); zero if FIFO not implemented
<|`28` _SPI_CTRL_TX_EMPTY_ ^| r/- <| TX FIFO empty; zero if FIFO not implemented
<|`29` _SPI_CTRL_TX_HALF_ ^| r/- <| TX FIFO at least half full; zero if FIFO not implemented
<|`30` _SPI_CTRL_TX_FULL_ ^| r/- <| TX FIFO full; zero if FIFO not implemented
<|`31` _SPI_CTRL_BUSY_ ^| r/- <| SPI module busy when set (serial engine operation in progress and TX FIFO not empty yet)
| `0xffffffac` | `NEORV32_SPI.DATA` |`31:0` | r/w | receive/transmit data (FIFO), LSB-aligned
|=======================