neorv32/docs/datasheet/soc_sdi.adoc
2025-04-17 18:53:51 +00:00

109 lines
6.8 KiB
Text

<<<
:sectnums:
==== Serial Data Interface Controller (SDI)
[cols="<3,<3,<4"]
[grid="none"]
|=======================
| Hardware source files: | neorv32_sdi.vhd |
| Software driver files: | neorv32_sdi.c | link:https://stnolting.github.io/neorv32/sw/neorv32__sdi_8c.html[Online software reference (Doxygen)]
| | neorv32_sdi.h | link:https://stnolting.github.io/neorv32/sw/neorv32__sdi_8h.html[Online software reference (Doxygen)]
| Top entity ports: | `sdi_clk_i` | 1-bit serial clock input
| | `sdi_dat_o` | 1-bit serial data output
| | `sdi_dat_i` | 1-bit serial data input
| | `sdi_csn_i` | 1-bit chip-select input (low-active)
| Configuration generics: | `IO_SDI_EN` | implement SDI controller when `true`
| | `IO_SDI_FIFO` | data FIFO size, has to a power of two, min 1
| CPU interrupts: | fast IRQ channel 11 | configurable SDI interrupt (see <<_processor_interrupts>>)
|=======================
**Overview**
The serial data interface module provides a **device-class** SPI interface and allows to connect the processor
to an **external SPI host**, which is responsible of performing the actual transmission - the SDI is entirely
passive. An optional receive/transmit ring buffer (FIFOs) can be configured via the `IO_SDI_FIFO` generic to
support block-based transmissions without CPU interaction.
.Device-Mode Only
[NOTE]
The NEORV32 SDI module only supports _device mode_. Transmission is initiated by an external host and not by
the processor itself. If you are looking for a _host-mode_ serial peripheral interface (transactions
performed by the NEORV32) check out the <<_serial_peripheral_interface_controller_spi>>.
The SDI 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. Any access to the `DATA` register
actually accesses the internal ring buffer.
**Theory of Operation**
The SDI module is enabled by setting the `SDI_CTRL_EN` bit in the `CTRL` control register. Clearing this bit
resets the entire module and will also clear the entire RX/TX ring buffer.
The SDI operates on byte-level only. Data written to the `DATA` register will be pushed to the TX FIFO. Received
data can be retrieved by reading the RX FIFO via the `DATA` register. The current state of these FIFOs is available
via the control register's `SDI_CTRL_RX_*` and `SDI_CTRL_TX_*` flags. If no data is available in the TX FIFO while
an external device performs a transmission the external device will read all-zero from the SDI controller.
Application software can check the current state of the SDI chip-select input via the control register's
`SDI_CTRL_CS_ACTIVE` flag (the flag is set when the chip-select line is active (pulled low)).
.MSB-first Only
[NOTE]
The NEORV32 SDI module only supports MSB-first mode.
.In-Transmission Abort
[NOTE]
If the external SPI controller aborts the transmission by setting the chip-select signal high again _before_
8 data bits have been transferred, no data is written to the RX FIFO.
**SDI Clocking**
The SDI module supports both SPI clock polarity modes ("CPOL") but only "CPHA=0"-clock-phase is _officially_ supported
yet. However, experiments have shown that the SDI module can also deal with both clock phase modes (for slow SDI clock speeds).
All SDI operations are clocked by the external `sdi_clk_i` signal. This signal is synchronized to the processor's
clock domain to simplify timing behavior. This clock synchronization requires the external SDI clock
(`sdi_clk_i`) to not **not exceed 1/4 of the processor's main clock**.
**SDI Interrupt**
The SDI module provides a set of programmable interrupt conditions based on the level of the RX & TX FIFOs. The different
interrupt sources are enabled by setting the according control register's `SDI_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 SDI interrupt has fired it will remain active until the actual cause of the interrupt is resolved; for
example if just the `SDI_CTRL_IRQ_RX_AVAIL` bit is set, the interrupt will keep firing until the RX FIFO is empty again.
**Register Map**
.SDI register map (`struct NEORV32_SDI`)
[cols="<2,<1,<4,^1,<7"]
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.18+<| `0xfff70000` .18+<| `CTRL` <|`0` `SDI_CTRL_EN` ^| r/w <| SDI module enable
<|`3:1` _reserved_ ^| r/- <| reserved, read as zero
<|`7:4` `SDI_CTRL_FIFO_MSB : SDI_CTRL_FIFO_LSB` ^| r/- <| FIFO depth; log2(_IO_SDI_FIFO_)
<|`14:8` _reserved_ ^| r/- <| reserved, read as zero
<|`15` `SDI_CTRL_IRQ_RX_AVAIL` ^| r/w <| fire interrupt if RX FIFO is not empty
<|`16` `SDI_CTRL_IRQ_RX_HALF` ^| r/w <| fire interrupt if RX FIFO is at least half full
<|`17` `SDI_CTRL_IRQ_RX_FULL` ^| r/w <| fire interrupt if if RX FIFO is full
<|`18` `SDI_CTRL_IRQ_TX_EMPTY` ^| r/w <| fire interrupt if TX FIFO is empty
<|`19` `SDI_CTRL_IRQ_TX_NHALF` ^| r/w <| fire interrupt if TX FIFO is not at least half full
<|`22:20` _reserved_ ^| r/- <| reserved, read as zero
<|`23` `SDI_CTRL_RX_AVAIL` ^| r/- <| RX FIFO data available (RX FIFO not empty)
<|`24` `SDI_CTRL_RX_HALF` ^| r/- <| RX FIFO at least half full
<|`25` `SDI_CTRL_RX_FULL` ^| r/- <| RX FIFO full
<|`26` `SDI_CTRL_TX_EMPTY` ^| r/- <| TX FIFO empty
<|`27` `SDI_CTRL_TX_NHALF` ^| r/- <| TX FIFO not at least half full
<|`28` `SDI_CTRL_TX_FULL` ^| r/- <| TX FIFO full
<|`30:29` _reserved_ ^| r/- <| reserved, read as zero
<|`31` `SDI_CTRL_CS_ACTIVE` ^| r/- <| Chip-select is active when set
.2+<| `0xfff70004` .2+<| `DATA` <|`7:0` ^| r/w <| receive/transmit data (FIFO)
<|`31:8` _reserved_ ^| r/- <| reserved, read as zero
|=======================