neorv32/docs/datasheet/soc_spi.adoc

141 lines
8.6 KiB
Plaintext
Raw Permalink Normal View History

2024-02-24 08:25:27 +00:00
<<<
: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_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>>)
|=======================
**Overview**
The NEORV32 SPI transceiver module operates on 8-bit base, supports all 4 standard clock modes
and provides up to 8 dedicated chip select signals via the top entity's `spi_csn_o` signal.
An receive/transmit FIFO can be configured via the `IO_SPI_FIFO` generic to support block-based
transmissions without CPU interaction.
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.
.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. 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 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, clear
the FIFO and terminate any transfer being in process.
The data quantity to be transferred within a single data transmission is fixed to 8 bits. However, the
total transmission length is left to the user: after asserting chip-select an arbitrary amount of 8-bit transmission
can be made before de-asserting chip-select again.
A transmission is started when writing data to the transmitter FIFO via the `DATA` register. Note that data always
transferred MSB-first. The SPI operation is completed as soon as the `SPI_CTRL_BUSY` flag clears. Received data can
be retrieved by reading the RX FIFO also via the `DATA` register. The control register's `SPI_CTRL_RX_AVAIL`,
`SPI_CTRL_TX_EMPTY`, `SPI_CTRL_TX_NHALF` and `SPI_CTRL_TX_FULL` flags provide information regarding the RX/TX FIFO levels.
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_CS_SELx` bits are used to select one out of the eight
dedicated chip select lines. 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[]
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_PRSCx`** | `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 50%.
**High-Speed Mode**
The SPI provides a high-speed mode to further boost the maximum SPI clock frequency. When enabled via the control
register's `SPI_CTRL_HIGHSPEED` bit the clock prescaler configuration (`SPI_CTRL_PRSCx` bits) is overridden setting it
to a minimal factor of 1. However, the clock speed can still be fine-tuned using the `SPI_CTRL_CDIVx` bits.
_**f~SPI~**_ = _f~main~[Hz]_ / (2 * 1 * (1 + `SPI_CTRL_CDIVx`))
Hence, the maximum SPI clock when in high-speed mode is f~main~ / 2.
**SPI Interrupt**
The SPI module provides a set of programmable interrupt conditions based on the level of the RX/TX FIFO. The different
interrupt sources are enabled by setting the according control register's `SPI_CTRL_IRQ_*` bits. All enabled interrupt
conditions are logically OR-ed so any enabled interrupt source will trigger the module's interrupt signal.
Once the SPI interrupt has fired it remains pending until the actual cause of the interrupt is resolved; for
example if just the `SPI_CTRL_IRQ_RX_AVAIL` bit is set, the interrupt will keep firing until the RX FIFO is empty again.
Furthermore, an active SPI interrupt has to be explicitly cleared again by writing zero to the according
<<_mip>> CSR bit.
**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
.19+<| `0xfffff800` .19+<| `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_CS_SEL2 : SPI_CTRL_CS_SEL0` ^| r/w <| Direct chip-select 0..7
<|`6` `SPI_CTRL_CS_EN` ^| r/w <| Direct chip-select enable: setting `spi_csn_o(SPI_CTRL_CS_SEL)` low when set
<|`9:7` `SPI_CTRL_PRSC2 : SPI_CTRL_PRSC0` ^| r/w <| 3-bit clock prescaler select
<|`13:10` `SPI_CTRL_CDIV2 : SPI_CTRL_CDIV0` ^| r/w <| 4-bit clock divider for fine-tuning
<|`14` `SPI_CTRL_HIGHSPEED` ^| r/w <| high-speed mode enable (overriding `SPI_CTRL_PRSC`)
<|`15` _reserved_ ^| 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_NHALF` ^| r/- <| TX FIFO _not_ at least half full
<|`19` `SPI_CTRL_TX_FULL` ^| r/- <| TX FIFO full
<|`20` `SPI_CTRL_IRQ_RX_AVAIL` ^| r/w <| Trigger IRQ if RX FIFO not empty
<|`21` `SPI_CTRL_IRQ_TX_EMPTY` ^| r/w <| Trigger IRQ if TX FIFO empty
<|`22` `SPI_CTRL_IRQ_TX_NHALF` ^| r/w <| Trigger IRQ if TX FIFO _not_ at least half full
<|`26:23` `SPI_CTRL_FIFO_MSB : SPI_CTRL_FIFO_LSB` ^| r/- <| FIFO depth; log2(_IO_SPI_FIFO_)
<|`30:27` _reserved_ ^| r/- <| reserved, read as zero
<|`31` `SPI_CTRL_BUSY` ^| r/- <| SPI module busy when set (serial engine operation in progress and TX FIFO not empty yet)
| `0xfffff804` | `DATA` |`7:0` | r/w | receive/transmit data (FIFO)
|=======================