Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ [rtl] add optional SPI data FIFO #381

Merged
merged 28 commits into from
Aug 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c71dd09
[system_integration] add SPI FIFO generic
stnolting Jul 31, 2022
32ed1c5
:sparkles: [rtl] add optional SPI RTX FIFO
stnolting Jul 31, 2022
100708e
[sw] update SPI FIFO bit definitions
stnolting Jul 31, 2022
96c50de
[svd] add new SPI FIFO flags
stnolting Jul 31, 2022
53dbed0
[sim] set SPI FIFO configuration
stnolting Jul 31, 2022
ba2290b
[sw] update SPI HAL
stnolting Jul 31, 2022
df9632f
[rtl] update version to 1.7.4.8
stnolting Jul 31, 2022
db5d1d4
[sw] update SPI example programs
stnolting Jul 31, 2022
5b74746
[docs.soc] add IO_SPI_FIFO generic
stnolting Jul 31, 2022
d3ca993
[bootloader] update SPI setup function call
stnolting Jul 31, 2022
c0d2d7a
[rtl] minor fix
stnolting Jul 31, 2022
e303e27
[sim] test case SPI_FIFO = 0
stnolting Jul 31, 2022
8d52ad5
[rtl] minor fix; clean-ups
stnolting Jul 31, 2022
6565fd1
[sim] revert
stnolting Jul 31, 2022
8fe03ad
[rtl] simplify SPI FIFO flags
stnolting Aug 1, 2022
07485f1
[sw] simplify SPI FIFO flags
stnolting Aug 1, 2022
dfa7fc7
[sw example] add: 'neorv32_spi_init': initializes data flow storage e…
akaeba Aug 1, 2022
32f843f
adjust example
akaeba Aug 1, 2022
9f46785
[sw example] add: 'neorv32_spi_init': initializes data flow storage e…
akaeba Aug 1, 2022
91d035c
Merge branch 'demo_spi_irq_fifo' of https://github.com/akaeba/neorv32…
akaeba Aug 1, 2022
b5e81b6
bugfix: typing issue
akaeba Aug 1, 2022
74ef903
[docs] update section "SPI"
stnolting Aug 1, 2022
478901e
[rtl] minor reworks
stnolting Aug 1, 2022
a4d0c11
[changelog] add v1.7.4.8
stnolting Aug 1, 2022
4a0c471
Merge branch 'add_spi_fifo' into demo_spi_irq_fifo
stnolting Aug 1, 2022
f9d8ece
bugfix: 'neorv32_spi_rw' can only write on element to SPI, otherwise …
akaeba Aug 2, 2022
cf907c8
minor: format code
akaeba Aug 2, 2022
7eaf2c2
Merge pull request #382 from akaeba/demo_spi_irq_fifo
stnolting Aug 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ mimpid = 0x01040312 => 01.04.03.12 => Version 01.04.03.12 => v1.4.3.12

| Date (*dd.mm.yyyy*) | Version | Comment |
|:-------------------:|:-------:|:--------|
| 01.08.2022 | 1.7.4.8 | :sparkles: add configurable data FIFO to **SPI** module; [#381](https://github.com/stnolting/neorv32/pull/381) |
| 31.07.2022 | 1.7.4.7 | :warning: rework **SLINK** module; [#377](https://github.com/stnolting/neorv32/pull/377) |
| 25.07.2022 | 1.7.4.6 | :warning: simplify memory configuration of **linker script**; :sparkles: add in-console configuration option; [#]375(https://github.com/stnolting/neorv32/pull/375) |
| 22.07.2022 | 1.7.4.5 | add `CUSTOM_ID` generic; update bootloader; [#374](https://github.com/stnolting/neorv32/pull/374) |
Expand Down
12 changes: 12 additions & 0 deletions docs/datasheet/soc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,18 @@ implemented reducing access latency by one cycle but eventually increasing the c
|======


:sectnums!:
===== _IO_SPI_FIFO_

[cols="4,4,2"]
[frame="all",grid="none"]
|======
| **IO_SPI_FIFO** | _natural_ | 0
3+| Depth of the <<_serial_peripheral_interface_controller_spi>> FIFO. Has to be zero or a power of two.
Maximum value is 32*1024.
|======


:sectnums!:
===== _IO_TWI_EN_

Expand Down
121 changes: 74 additions & 47 deletions docs/datasheet/soc_spi.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,51 +12,57 @@
| | `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_
| Configuration generics: | _IO_SPI_EN_ | implement SPI controller when _true_
| | _IO_SPI_FIFO_ | data FIFO size, has to be zero or a power of two
| CPU interrupts: | fast IRQ channel 6 | transmission done interrupt (see <<_processor_interrupts>>)
|=======================


**Theory of Operation**
**Overview**

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
The NEORV32 SPI transceiver module supports 8-, 16-, 24- and 32-bit wide transmissions, all 4 standard clock mode
and 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).
An optional FIFO can be implemented via the _IO_SPI_FIFO_ generic to support block-based transmissions
without CPU interaction.

[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).
and not by any 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.
The SPI module provides a single control register `CTRL` used to configure the module and to check its status
and a data register `DATA` for receiving/transmitting data. If the data FIFO is implemented, this register
is used to interface the FIFO.

[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.
**Theory of Operation**

The data quantity to be transferred within a single transmission is defined via the _SPI_CTRL_SIZEx_ bits.
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 (also clearing
any FIFOs if implemented) and will also terminate any a transfer being in process.

The data quantity to be transferred within a single data 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
the SPI transceiver is configured for less than 32-bit transfer data quantity, the transmit data must be placed
into the lowest 8/16/24 bits of `DATA`. Vice versa, the received data is also always LSB-aligned. Application
software should only process the amount of bits that was configured using _SPI_CTRL_SIZEx_ when
reading `DATA`.

The SPI operation is completed as soon as the _SPI_CTRL_BUSY_ flag clears. If a FIFO size greater than zero is configured,
the busy flag clears when the current serial engine operation is completed and there is no data left in send buffer.

[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
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 total transmission length, which can be an arbitrary number of individual data transfers, 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)`
Expand All @@ -70,7 +76,7 @@ the accessed device's chip-select signal but can also be use for controlling oth

**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 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_.

Expand All @@ -87,7 +93,7 @@ image::SPI_timing_diagram2.wikimedia.png[]
|=======================

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 pre-scalers are available:

.SPI prescaler configuration
[cols="<4,^1,^1,^1,^1,^1,^1,^1,^1"]
Expand All @@ -107,15 +113,40 @@ 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
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 FIFO**

An optional FIFO buffer can be implemented by setting _IO_SPI_FIFO_ to a value greater than zero. Having a data FIFO
allows (more) CPU-independent operation of the SPI module.

Internally, two FIFOs are implemented: one for TX data and one for RX data. However, those two FIFOs are transparent for
the software and operate as a single, unified "ring buffer". The status signals of the TX FIFO (empty, at least half full,
full) are exposed as read-only signals via the SPI control register. In contrast, the RX FIFO only provides a "data available"
flag (= RX FIFO not empty) via the SPI control register.

[TIP]
Application programs can implement "double buffering" when using the "FIFO less than half full" interrupt configuration
option (see below).


**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 writing zero to the according <<_mip>> CSR bit.
The SPI module provides a single interrupt that can be used to signal certain transmission states to the CPU.
The actual interrupt condition is configured by the two _SPI_CTRL_IRQx_ in the SPI module's control register:

* `00`, `01` : trigger interrupt when SPI serial engine _completes_ current transmission
* `10` : trigger interrupt when TX FIFO _becomes_ less than half full, not available if _IO_SPI_FIFO_ is zero
* `11` : trigger interrupt when TX FIFO _becomes_ empty, not available if _IO_SPI_FIFO_ is zero

Once the SPI CPU is triggered it has to be explicitly cleared again by writing zero to the according
<<_mip>> CSR bit inside the SPI trap handler.

[IMPORTANT]
If not FIFO is implemented (_IO_SPI_FIFO_ = 0) the _SPI_CTRL_IRQx_ are hardwired to `00` statically configuring
"SPI serial engine _completes_ current transmission" as interrupt condition.


**Register Map**
Expand All @@ -125,24 +156,20 @@ by writing zero to the according <<_mip>> CSR bit.
[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
.15+<| `0xffffffa8` .15+<| `NEORV32_SPI.CTRL` <|`7:0` _SPI_CTRL_CS7_ : _SPI_CTRL_CS0_ ^| r/w <| Direct chip-select 0..7; setting `spi_csn_o(x)` low when set
<|`8` _SPI_CTRL_EN_ ^| r/w <| SPI module 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)
<|`12:10` _SPI_CTRL_PRSC2_ : _SPI_CTRL_PRSC0_ ^| r/w <| 3-bit clock prescaler select
<|`14:13` _SPI_CTRL_SIZE1_ : _SPI_CTRL_SIZE0_ ^| r/w <| transfer size (`00`=8-bit, `01`=16-bit, `10`=24-bit, `11`=32-bit)
<|`15` _SPI_CTRL_CPOL_ ^| r/w <| clock polarity
<|`16` _SPI_CTRL_HIGHSPEED_ ^| r/w <| enable SPI high-speed mode (ignoring _SPI_CTRL_PRSC_)
<|`18:17` _SPI_CTRL_IRQ1_ : _SPI_CTRL_IRQ0_ ^| r/w <| interrupt configuration (`0-` = SPI serial engine becomes idle, `10` = TX FIFO _become_ less than half full, `11` = TX FIFO _becomes_ empty)
<|`22:19` _SPI_CTRL_FIFO_MSB_ : _SPI_CTRL_FIFO_LSB_ ^| r/- <| FIFO depth; log2(_IO_SPI_FIFO_)
<|`23:26` _reserved_ ^| r/- <| reserved, read as zero
<|`27` _SPI_CTRL_RX_AVAIL_ ^| r/- <| RX FIFO data available (RX FIFO not empty); zero if FIFO not implemented
<|`28` _SPI_CTRL_TX_EMPTY_ ^| r/- <| TX FIFO empty; zero if FIFO not implemented
<|`29` _SPI_CTRL_TX_HALF_ ^| r/- <| TX FIFO at least half full; zero if FIFO not implemented
<|`30` _SPI_CTRL_TX_FULL_ ^| r/- <| TX FIFO full; zero if FIFO not implemented
<|`31` _SPI_CTRL_BUSY_ ^| r/- <| SPI module busy when set (serial engine operation in progress and TX FIFO not empty yet)
| `0xffffffac` | `NEORV32_SPI.DATA` |`31:0` | r/w | receive/transmit data (FIFO), LSB-aligned
|=======================
6 changes: 5 additions & 1 deletion rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ package neorv32_package is
-- Architecture Constants (do not modify!) ------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant data_width_c : natural := 32; -- native data path width - do not change!
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01070407"; -- NEORV32 version - no touchy!
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01070408"; -- NEORV32 version - no touchy!
constant archid_c : natural := 19; -- official RISC-V architecture ID - hands off!

-- Check if we're inside the Matrix -------------------------------------------------------
Expand Down Expand Up @@ -1025,6 +1025,7 @@ package neorv32_package is
IO_UART1_RX_FIFO : natural := 1; -- RX fifo depth, has to be a power of two, min 1
IO_UART1_TX_FIFO : natural := 1; -- TX fifo depth, has to be a power of two, min 1
IO_SPI_EN : boolean := false; -- implement serial peripheral interface (SPI)?
IO_SPI_FIFO : natural := 0; -- SPI RTX fifo depth, has to be zero or a power of two
IO_TWI_EN : boolean := false; -- implement two-wire interface (TWI)?
IO_PWM_NUM_CH : natural := 0; -- number of PWM channels to implement (0..60); 0 = disabled
IO_WDT_EN : boolean := false; -- implement watch dog timer (WDT)?
Expand Down Expand Up @@ -1751,6 +1752,9 @@ package neorv32_package is
-- Component: Serial Peripheral Interface (SPI) -------------------------------------------
-- -------------------------------------------------------------------------------------------
component neorv32_spi
generic (
IO_SPI_FIFO : natural -- SPI RTX fifo depth, has to be zero or a power of two
);
port (
-- host access --
clk_i : in std_ulogic; -- global clock line
Expand Down
Loading