OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [docs/] [datasheet/] [soc_spi.adoc] - Rev 71

Go to most recent revision | Compare with Previous | Blame | View Log

<<<
: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_
| CPU interrupts:          | fast IRQ channel 6 | transmission done interrupt (see <<_processor_interrupts>>)
|=======================


**Theory of Operation**

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 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).

[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
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.

[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 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 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
software should only actually process the amount of bits that were configured using _SPI_CTRL_SIZEx_ when
reading `DATA`.

[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.

[TIP]
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.

The SPI controller features 8 dedicated chip-select lines. These lines are controlled via the control register's
_SPI_CTRL_CSx_ bits. When a specific _SPI_CTRL_CSx_ bit is **set**, the according chip-select line `spi_csn_o(x)`
goes **low** (low-active chip-select lines).

[TIP]
The dedicated SPI chip-select signals can be seen as _general purpose_ outputs. These are intended to control
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**

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_
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 4
| _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.
The following prescalers 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_ configuration, the actual SPI clock frequency f~SPI~ is derived from the processor's
main clock f~main~ and is determined by:

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

Hence, the maximum SPI clock is f~main~ / 4.

.High-Speed SPI mode
[TIP]
The module provides a "high-speed" SPI mode. In this mode the clock prescaler configuration (SPI_CTRL_PRSCx) is ignored
and the SPI clock operates at f~main~ / 2 (half of the processor's main clock). High speed SPI mode is enabled by setting
the control register's _SPI_CTRL_HIGHSPEED_ bit.


**SPI Interrupt**

The SPI module provides a single interrupt to signal "transmission done" to the CPU. Whenever the SPI
module completes the current transfer operation, the interrupt is triggered and has to be explicitly cleared again
by setting the according `mip` CSR bit.


.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
.19+<| `0xffffffa8` .19+<| `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 
                                              <|`2` _SPI_CTRL_CS2_        ^| r/w 
                                              <|`3` _SPI_CTRL_CS3_        ^| r/w 
                                              <|`4` _SPI_CTRL_CS4_        ^| r/w 
                                              <|`5` _SPI_CTRL_CS5_        ^| r/w 
                                              <|`6` _SPI_CTRL_CS6_        ^| r/w 
                                              <|`7` _SPI_CTRL_CS7_        ^| r/w 
                                              <|`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)
                                              <|`10` _SPI_CTRL_PRSC0_     ^| r/w .3+| 3-bit clock prescaler select
                                              <|`11` _SPI_CTRL_PRSC1_     ^| 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)
                                              <|`14` _SPI_CTRL_SIZE1_     ^| r/w
                                              <|`15` _SPI_CTRL_CPOL_      ^| r/w <| clock polarity
                                              <|`16` _SPI_CTRL_HIGHSPEED_ ^| r/w <| enable SPI high-speed mode (ignoring _SPI_CTRL_PRSC_)
                                              <|`17:30`                   ^| r/- <| _reserved, read as zero
                                              <|`31` _SPI_CTRL_BUSY_      ^| r/- <| transmission in progress when set
| `0xffffffac` | `NEORV32_SPI.DATA` |`31:0` | r/w | receive/transmit data, LSB-aligned
|=======================

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.