<<<
|
<<<
|
:sectnums:
|
:sectnums:
|
==== Serial Peripheral Interface Controller (SPI)
|
==== Serial Peripheral Interface Controller (SPI)
|
|
|
[cols="<3,<3,<4"]
|
[cols="<3,<3,<4"]
|
[frame="topbot",grid="none"]
|
[frame="topbot",grid="none"]
|
|=======================
|
|=======================
|
| Hardware source file(s): | neorv32_spi.vhd |
|
| Hardware source file(s): | neorv32_spi.vhd |
|
| Software driver file(s): | neorv32_spi.c |
|
| Software driver file(s): | neorv32_spi.c |
|
| | neorv32_spi.h |
|
| | neorv32_spi.h |
|
| Top entity port: | `spi_sck_o` | 1-bit serial clock output
|
| Top entity port: | `spi_sck_o` | 1-bit serial clock output
|
| | `spi_sdo_o` | 1-bit serial data output
|
| | `spi_sdo_o` | 1-bit serial data output
|
| | `spi_sdi_i` | 1-bit serial data input
|
| | `spi_sdi_i` | 1-bit serial data input
|
| | `spi_csn_i` | 8-bit dedicated chip select (low-active)
|
| | `spi_csn_i` | 8-bit dedicated chip select (low-active)
|
| Configuration generics: | _IO_SPI_EN_ | implement SPI controller when _true_
|
| Configuration generics: | _IO_SPI_EN_ | implement SPI controller when _true_
|
| CPU interrupts: | fast IRQ channel 6 | transmission done interrupt (see <<_processor_interrupts>>)
|
| CPU interrupts: | fast IRQ channel 6 | transmission done interrupt (see <<_processor_interrupts>>)
|
|=======================
|
|=======================
|
|
|
|
|
**Theory of Operation**
|
**Theory of Operation**
|
|
|
SPI is a synchronous serial transmission interface for fast on-board communications.
|
SPI is a synchronous serial transmission interface for fast on-board communications.
|
The NEORV32 SPI transceiver supports 8-, 16-, 24- and 32-bit wide transmissions.
|
The NEORV32 SPI transceiver supports 8-, 16-, 24- and 32-bit wide transmissions.
|
The unit provides 8 dedicated chip select signals via the top entity's `spi_csn_o` signal, which are
|
The unit provides 8 dedicated chip select signals via the top entity's `spi_csn_o` signal, which are
|
directly controlled by the SPI module (no additional GPIO required).
|
directly controlled by the SPI module (no additional GPIO required).
|
|
|
|
[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 unit is enabled by setting the _SPI_CTRL_EN_ bit in the `CTRL` control register. No transfer can be initiated
|
The SPI unit 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. Furthermore, a transfer being in process
|
and no interrupt request will be triggered if this bit is cleared. Furthermore, a transfer being in process
|
can be terminated at any time by clearing this bit.
|
can be terminated at any time by clearing this bit.
|
|
|
|
[IMPORTANT]
|
|
Changes to the `CTRL` control register should be made only when the SPI module is idle as they directly effect
|
|
transmissions being in-progress.
|
|
|
|
[TIP]
|
|
A transmission can be terminated at any time by disabling the SPI module
|
|
by clearing the _SPI_CTRL_EN_ control register bit.
|
|
|
The data quantity to be transferred within a single transmission is defined via the _SPI_CTRL_SIZEx_ bits.
|
The data quantity to be transferred within a single transmission is defined via the _SPI_CTRL_SIZEx_ bits.
|
The SPI module supports 8-bit (`00`), 16-bit (`01`), 24-
|
The SPI module supports 8-bit (`00`), 16-bit (`01`), 24-bit (`10`) and 32-bit (`11`) transfers.
|
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
|
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 transfers data quantity, the transmit data must be placed
|
the SPI transceiver is configured for less than 32-bit transfers data quantity, the transmit data must be placed
|
into the lowest 8/16/24 bit of `DATA`. Vice versa, the received data is also always LSB-aligned. Application
|
into the lowest 8/16/24 bit of `DATA`. Vice versa, the received data is also always LSB-aligned. Application
|
software should only actually process the amount of bits that were configured using _SPI_CTRL_SIZEx_ when
|
software should only actually process the amount of bits that were configured using _SPI_CTRL_SIZEx_ when
|
reading `DATA`.
|
reading `DATA`.
|
|
|
The SPI controller features 8 dedicated chip-select lines. These lines are controlled via the control register's
|
[NOTE]
|
_SPI_CTRL_CSx_ bits. When a specific _SPI_CTRL_CSx_ bit is **set**, the according chip-select line `spi_csn_o(x)`
|
The NEORV32 SPI module only support MSB-first mode. Data can be reversed before writing `DATA` (for TX) / after
|
goes **low** (low-active chip-select lines).
|
reading `DATA` (for RX) to implement LSB-first transmissions. Note that in both cases data in ` DATA` still
|
|
needs to be LSB-aligned.
|
[IMPORTANT]
|
|
Changes to the `CTRL` control register should be made only when the SPI module is idle as they directly effect
|
|
transmissions being in-progress.
|
|
|
|
[TIP]
|
[TIP]
|
The actual transmission length is left to the user: after asserting chip-select an arbitrary amount of
|
The actual transmission length 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.
|
transmission with arbitrary data quantity (_SPI_CTRL_SIZEx_) can be made before de-asserting chip-select again.
|
|
|
[NOTE]
|
The SPI controller features 8 dedicated chip-select lines. These lines are controlled via the control register's
|
The NEORV32 SPI module only supports _host mode_. Transmission are initiated only by the processor's SPI module
|
_SPI_CTRL_CSx_ bits. When a specific _SPI_CTRL_CSx_ bit is **set**, the according chip-select line `spi_csn_o(x)`
|
(and not by an external SPI module).
|
goes **low** (low-active chip-select lines).
|
|
|
[NOTE]
|
[TIP]
|
The NEORV32 SPI module only support MSB-first mode. Data can be reversed before writing `DATA` (for TX) / after
|
The dedicated SPI chip-select signals can be seen as _general purpose_ outputs. These are intended to control
|
reading `DATA` (for RX) to provide LSB-first transmissions.
|
the accessed device's chip-select signal but can also be use for controlling other shift register signals
|
|
(like data strobe or output-enables).
|
|
|
|
|
**SPI Clock Configuration**
|
**SPI Clock Configuration**
|
|
|
The SPI module supports all _standard SPI clock modes_ (0, 1, 2, 3), which is via the two control register bits
|
The SPI module supports all _standard SPI clock modes_ (0, 1, 2, 3), which is 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_
|
_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_.
|
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])
|
.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[]
|
image::SPI_timing_diagram2.wikimedia.png[]
|
|
|
.SPI standard clock modes
|
.SPI standard clock modes
|
[cols="<2,^1,^1,^1,^1"]
|
[cols="<2,^1,^1,^1,^1"]
|
[options="header",grid="rows"]
|
[options="header",grid="rows"]
|
|=======================
|
|=======================
|
| | Mode 0 | Mode 1 | Mode 2 | Mode 4
|
| | Mode 0 | Mode 1 | Mode 2 | Mode 4
|
| _SPI_CTRL_CPOL_ | `0` | `0` | `1` | `1`
|
| _SPI_CTRL_CPOL_ | `0` | `0` | `1` | `1`
|
| _SPI_CTRL_CPHA_ | `0` | `1` | `0` | `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.
|
The SPI clock frequency (`spi_sck_o`) is programmed by the 3-bit _SPI_CTRL_PRSCx_ clock prescaler.
|
The following prescalers are available:
|
The following prescalers are available:
|
|
|
.SPI prescaler configuration
|
.SPI prescaler configuration
|
[cols="<4,^1,^1,^1,^1,^1,^1,^1,^1"]
|
[cols="<4,^1,^1,^1,^1,^1,^1,^1,^1"]
|
[options="header",grid="rows"]
|
[options="header",grid="rows"]
|
|=======================
|
|=======================
|
| **`SPI_CTRL_PRSCx`** | `0b000` | `0b001` | `0b010` | `0b011` | `0b100` | `0b101` | `0b110` | `0b111`
|
| **`SPI_CTRL_PRSCx`** | `0b000` | `0b001` | `0b010` | `0b011` | `0b100` | `0b101` | `0b110` | `0b111`
|
| Resulting `clock_prescaler` | 2 | 4 | 8 | 64 | 128 | 1024 | 2048 | 4096
|
| Resulting `clock_prescaler` | 2 | 4 | 8 | 64 | 128 | 1024 | 2048 | 4096
|
|=======================
|
|=======================
|
|
|
Based on the _SPI_CTRL_PRSCx_ configuration, the actual SPI clock frequency f~SPI~ is derived from the processor's
|
Based on the _SPI_CTRL_PRSCx_ configuration, the actual SPI clock frequency f~SPI~ is derived from the processor's
|
main clock f~main~ and is determined by:
|
main clock f~main~ and is determined by:
|
|
|
_**f~SPI~**_ = _f~main~[Hz]_ / (2 * `clock_prescaler`)
|
_**f~SPI~**_ = _f~main~[Hz]_ / (2 * `clock_prescaler`)
|
|
|
Hence, the maximum SPI clock is f~main~ / 4.
|
Hence, the maximum SPI clock is f~main~ / 4.
|
|
|
|
|
**SPI Interrupt**
|
**SPI Interrupt**
|
|
|
The SPI module provides a single interrupt to signal "ready for new transmission" to the CPU. Whenever the SPI
|
The SPI module provides a single interrupt to signal "ready for new transmission" to the CPU. Whenever the SPI
|
module is currently idle (and enabled), the interrupt request is active. A pending interrupt request is cleared
|
module is currently idle (and enabled), the interrupt request is active. A pending interrupt request is cleared
|
by triggering a new SPI transmission or by disabling the SPI module.
|
by triggering a new SPI transmission or by disabling the SPI module.
|
|
|
|
|
.SPI register map (`struct NEORV32_SPI`)
|
.SPI register map (`struct NEORV32_SPI`)
|
[cols="<2,<2,<4,^1,<7"]
|
[cols="<2,<2,<4,^1,<7"]
|
[options="header",grid="all"]
|
[options="header",grid="all"]
|
|=======================
|
|=======================
|
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
|
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
|
.18+<| `0xffffffa8` .18+<| `NEORV32_SPI.CTRL` <|`0` _SPI_CTRL_CS0_ ^| r/w .8+<| Direct chip-select 0..7; setting `spi_csn_o(x)` low when set
|
.18+<| `0xffffffa8` .18+<| `NEORV32_SPI.CTRL` <|`0` _SPI_CTRL_CS0_ ^| r/w .8+<| Direct chip-select 0..7; setting `spi_csn_o(x)` low when set
|
<|`1` _SPI_CTRL_CS1_ ^| r/w
|
<|`1` _SPI_CTRL_CS1_ ^| r/w
|
<|`2` _SPI_CTRL_CS2_ ^| r/w
|
<|`2` _SPI_CTRL_CS2_ ^| r/w
|
<|`3` _SPI_CTRL_CS3_ ^| r/w
|
<|`3` _SPI_CTRL_CS3_ ^| r/w
|
<|`4` _SPI_CTRL_CS4_ ^| r/w
|
<|`4` _SPI_CTRL_CS4_ ^| r/w
|
<|`5` _SPI_CTRL_CS5_ ^| r/w
|
<|`5` _SPI_CTRL_CS5_ ^| r/w
|
<|`6` _SPI_CTRL_CS6_ ^| r/w
|
<|`6` _SPI_CTRL_CS6_ ^| r/w
|
<|`7` _SPI_CTRL_CS7_ ^| r/w
|
<|`7` _SPI_CTRL_CS7_ ^| r/w
|
<|`8` _SPI_CTRL_EN_ ^| r/w <| SPI enable
|
<|`8` _SPI_CTRL_EN_ ^| r/w <| SPI enable
|
<|`9` _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)
|
<|`9` _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)
|
<|`10` _SPI_CTRL_PRSC0_ ^| r/w .3+| 3-bit clock prescaler select
|
<|`10` _SPI_CTRL_PRSC0_ ^| r/w .3+| 3-bit clock prescaler select
|
<|`11` _SPI_CTRL_PRSC1_ ^| r/w
|
<|`11` _SPI_CTRL_PRSC1_ ^| r/w
|
<|`12` _SPI_CTRL_PRSC2_ ^| r/w
|
<|`12` _SPI_CTRL_PRSC2_ ^| r/w
|
<|`13` _SPI_CTRL_SIZE0_ ^| r/w .2+<| transfer size (`00`=8-bit, `01`=16-bit, `10`=24-bit, `11`=32-bit)
|
<|`13` _SPI_CTRL_SIZE0_ ^| r/w .2+<| transfer size (`00`=8-bit, `01`=16-bit, `10`=24-bit, `11`=32-bit)
|
<|`14` _SPI_CTRL_SIZE1_ ^| r/w
|
<|`14` _SPI_CTRL_SIZE1_ ^| r/w
|
<|`15` _SPI_CTRL_CPOL_ ^| r/w <| clock polarity
|
<|`15` _SPI_CTRL_CPOL_ ^| r/w <| clock polarity
|
<|`16` .. `30` ^| r/- <| _reserved, read as zero
|
<|`16` .. `30` ^| r/- <| _reserved, read as zero
|
<|`31` _SPI_CTRL_BUSY_ ^| r/- <| transmission in progress when set
|
<|`31` _SPI_CTRL_BUSY_ ^| r/- <| transmission in progress when set
|
| `0xffffffac` | `NEORV32_SPI.DATA` |`31:0` | r/w | receive/transmit data, LSB-aligned
|
| `0xffffffac` | `NEORV32_SPI.DATA` |`31:0` | r/w | receive/transmit data, LSB-aligned
|
|=======================
|
|=======================
|
|
|