141 lines
8.6 KiB
Plaintext
141 lines
8.6 KiB
Plaintext
<<<
|
|
: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)
|
|
|=======================
|