AXI SPI Engine Module

The AXI SPI Engine IP core allows asynchronous interrupt-driven memory-mapped access to a SPI Engine Control Interface. This is typically used in combination with a software program to dynamically generate SPI transactions.

The peripheral has also support for providing memory-mapped access to one or more SPI Engine Offload Module cores and change its content dynamically at runtime.

Files

Name

Description

library/spi_engine/axi_spi_engine/axi_spi_engine.v

Verilog source for the peripheral.

library/spi_engine/axi_spi_engine/axi_spi_engine_ip.tcl

TCL script to generate the Vivado IP-integrator project for the peripheral.

Configuration Parameters

Name

Description

Default Value

Choices/Range

CMD_FIFO_ADDRESS_WIDTH

Configures the size of the command FIFO.

4

From 1 to 16.

SYNC_FIFO_ADDRESS_WIDTH

SYNC FIFO address width.

4

From 1 to 16.

SDO_FIFO_ADDRESS_WIDTH

Configures the size of the serial-data out FIFO.

5

From 1 to 16.

SDI_FIFO_ADDRESS_WIDTH

Configures the size of the serial-data in FIFO.

5

From 1 to 16.

MM_IF_TYPE

Memory Mapped Interface Type.

0

AXI4 Memory Mapped (0), ADI uP FIFO (1)

ASYNC_SPI_CLK

If set to 1 the s_axi_aclk and spi_clk clocks are assumed to be asynchronous.

False

NUM_OFFLOAD

The number of offload control interfaces.

0

From 0 to 8.

OFFLOAD0_CMD_MEM_ADDRESS_WIDTH

Offload command FIFO address width.

4

From 1 to 16.

OFFLOAD0_SDO_MEM_ADDRESS_WIDTH

Offload MOSI FIFO address width.

4

From 1 to 16.

ID

Core ID.

0

From 0 to 255.

DATA_WIDTH

Parallel data width.

8

From 8 to 256.

NUM_OF_SDI

Number of MISO lines.

1

From 1 to 8.

CFG_INFO_0

Cfg Info 0.

0

CFG_INFO_1

Cfg Info 1.

0

CFG_INFO_2

Cfg Info 2.

0

CFG_INFO_3

Cfg Info 3.

0

Signal and Interface Pins

Physical Port

Logical Port

Direction

Dependency

s_axi_awaddr AWADDR

in [15:0]

MM_IF_TYPE = 0
s_axi_awprot AWPROT

in [2:0]

MM_IF_TYPE = 0
s_axi_awvalid AWVALID

in

MM_IF_TYPE = 0
s_axi_awready AWREADY

out

MM_IF_TYPE = 0
s_axi_wdata WDATA

in [31:0]

MM_IF_TYPE = 0
s_axi_wstrb WSTRB

in [3:0]

MM_IF_TYPE = 0
s_axi_wvalid WVALID

in

MM_IF_TYPE = 0
s_axi_wready WREADY

out

MM_IF_TYPE = 0
s_axi_bresp BRESP

out [1:0]

MM_IF_TYPE = 0
s_axi_bvalid BVALID

out

MM_IF_TYPE = 0
s_axi_bready BREADY

in

MM_IF_TYPE = 0
s_axi_araddr ARADDR

in [15:0]

MM_IF_TYPE = 0
s_axi_arprot ARPROT

in [2:0]

MM_IF_TYPE = 0
s_axi_arvalid ARVALID

in

MM_IF_TYPE = 0
s_axi_arready ARREADY

out

MM_IF_TYPE = 0
s_axi_rdata RDATA

out [31:0]

MM_IF_TYPE = 0
s_axi_rresp RRESP

out [1:0]

MM_IF_TYPE = 0
s_axi_rvalid RVALID

out

MM_IF_TYPE = 0
s_axi_rready RREADY

in

MM_IF_TYPE = 0

Physical Port

Logical Port

Direction

Dependency

s_axi_aclk CLK

in

MM_IF_TYPE = 0

Physical Port

Logical Port

Direction

Dependency

s_axi_aresetn RST

in

MM_IF_TYPE = 0

Physical Port

Logical Port

Direction

Dependency

cmd_ready cmd_ready

in

cmd_valid cmd_valid

out

cmd_data cmd_data

out [15:0]

sdo_data_ready sdo_ready

in

sdo_data_valid sdo_valid

out

sdo_data sdo_data

out [7:0]

sdi_data_ready sdi_ready

out

sdi_data_valid sdi_valid

in

sdi_data sdi_data

in [7:0]

sync_ready sync_ready

out

sync_valid sync_valid

in

sync_data sync_data

in [7:0]

Physical Port

Logical Port

Direction

Dependency

offload0_cmd_wr_en cmd_wr_en

out

offload0_cmd_wr_data cmd_wr_data

out [15:0]

offload0_sdo_wr_en sdo_wr_en

out

offload0_sdo_wr_data sdo_wr_data

out [7:0]

offload0_enable enable

out

offload0_enabled enabled

in

offload0_mem_reset mem_reset

out

offload_sync_ready sync_ready

out

offload_sync_valid sync_valid

in

offload_sync_data sync_data

in [7:0]

Physical Port

Direction

Dependency

Description

up_clk

in

MM_IF_TYPE = 1

up_rstn

in

MM_IF_TYPE = 1

up_wreq

in

MM_IF_TYPE = 1

up_waddr

in [13:0]

MM_IF_TYPE = 1

up_wdata

in [31:0]

MM_IF_TYPE = 1

up_wack

out

MM_IF_TYPE = 1

up_rreq

in

MM_IF_TYPE = 1

up_raddr

in [13:0]

MM_IF_TYPE = 1

up_rdata

out [31:0]

MM_IF_TYPE = 1

up_rack

out

MM_IF_TYPE = 1

irq

out

Level-High Interrupt. Interrupt output of the module. Is asserted when at least one of the modules interrupt is pending and unmasked.

spi_clk

in

spi_resetn is synchronous to this clock. Bus spi_engine_ctrl is synchronous to this clock domain.

spi_resetn

out

This signal is asserted when the module is disabled through the ENABLE register. Typically used as the reset for the SPI Engine modules connected to these modules. Bus spi_engine_ctrl is synchronous to this reset signal.

Register Map

DWORD

BYTE

Reg Name

Description

BITS

Field Name

Type

Default Value

Description

0x0 0x0 VERSION

Version of the peripheral. Follows semantic versioning. Current version 1.03.01.

[31:16] VERSION_MAJOR RO 0x0001

[15:8] VERSION_MINOR RO 0x03

[7:0] VERSION_PATCH RO 0x01

0x1 0x4 PERIPHERAL_ID

[31:0] PERIPHERAL_ID RO ID

Value of the ID configuration parameter. In case of multiple instances, each instance will have a unique ID.

0x2 0x8 SCRATCH

[31:0] SCRATCH RW 0x00000000

Scratch register useful for debug.

0x3 0xc DATA_WIDTH

[7:4] NUM_OF_SDI RO NUM_​OF_​SDI

Number of SDI. It is equal with the maximum supported SDI lines in bits.

[3:0] DATA_WIDTH RO DATA_​WIDTH

Data width of the SDI/SDO parallel interface. It is equal with the maximum supported transfer length in bits.

0x4 0x10 OFFLOAD_MEM_ADDR_WIDTH

[15:8] SDO_MEM_ADDRESS_WIDTH RO 0x04

Address width for the data (SDO) memory on the Offload Module. The size of the memory is thus 2**SDO_MEM_ADDRESS_WIDTH data words.

[7:0] CMD_MEM_ADDRESS_WIDTH RO 0x04

Address width for the command memory on the Offload Module. The size of the command memory is thus 2**CMD_MEM_ADDRESS_WIDTH instructions.

0x5 0x14 FIFO_ADDR_WIDTH

[31:24] SDI_FIFO_ADDRESS_WIDTH RO 0x05

Address width for the SDI FIFO. The size of the SDI FIFO is thus 2**SDI_FIFO_ADDRESS_WIDTH.

[23:16] SDO_FIFO_ADDRESS_WIDTH RO 0x05

Address width for the SDO FIFO. The size of the SDO FIFO is thus 2**SDO_FIFO_ADDRESS_WIDTH.

[15:8] SYNC_FIFO_ADDRESS_WIDTH RO 0x04

Address width for the synchronization FIFO. The size of the synchronization FIFO is thus 2**SYNC_FIFO_ADDRESS_WIDTH.

[7:0] CMD_FIFO_ADDRESS_WIDTH RO 0x04

Address width for the command FIFO. The size of the command FIFO is thus 2**CMD_FIFO_ADDRESS_WIDTH.

0x10 0x40 ENABLE

[31:0] ENABLE RW 0x00000001

Enable register. If the enable bit is set to 1 the internal state of the peripheral is reset. For proper operation, the bit needs to be set to 0.

0x20 0x80 IRQ_MASK

[0] CMD_ALMOST_EMPTY RW 0x0

If set to 0 the CMD_ALMOST_EMPTY interrupt is masked.

[1] SDO_ALMOST_EMPTY RW 0x0

If set to 0 the SDO_ALMOST_EMPTY interrupt is masked.

[2] SDI_ALMOST_FULL RW 0x0

If set to 0 the SDI_ALMOST_FULL interrupt is masked.

[3] SYNC_EVENT RW 0x0

If set to 0 the SYNC_EVENT interrupt is masked.

[4] OFFLOAD_SYNC_ID_PENDING RW 0x0

If set to 0 the OFFLOAD_SYNC_ID_PENDING interrupt is masked.

0x21 0x84 IRQ_PENDING

[31:0] IRQ_PENDING RW1C 0x00000000

Pending IRQs with mask.

0x22 0x88 IRQ_SOURCE

[31:0] IRQ_SOURCE RO 0x00000000

Pending IRQs without mask.

0x30 0xc0 SYNC_ID

[31:0] SYNC_ID RO

Last synchronization event ID received from the SPI engine control interface.

0x31 0xc4 OFFLOAD_SYNC_ID

[31:0] OFFLOAD_SYNC_ID RO 0x00000000

Offload Sync ID.

0x34 0xd0 CMD_FIFO_ROOM

[31:0] CMD_FIFO_ROOM RO CMD_​FIFO_​ROOM

Number of free entries in the command FIFO. The reset value of the CMD_FIFO_ROOM register depends on the setting of the CMD_FIFO_ADDRESS_WIDTH parameter. CMD_FIFO_ROOM = $clog2((2**CMD_FIFO_ADDRESS_WIDTH)-1)

0x35 0xd4 SDO_FIFO_ROOM

[31:0] SDO_FIFO_ROOM RO SDO_​FIFO_​ROOM

Number of free entries in the serial-data-out FIFO. The reset value of the SDO_FIFO_ROOM register depends on the setting of the SDO_FIFO_ADDRESS_WIDTH parameter. SDO_FIFO_ROOM = $clog2((2**SDO_FIFO_ADDRESS_WIDTH)-1)

0x36 0xd8 SDI_FIFO_LEVEL

[31:0] SDI_FIFO_LEVEL RO 0x00000000

Number of valid entries in the serial-data-in FIFO.

0x38 0xe0 CMD_FIFO

[31:0] CMD_FIFO WO

Command FIFO register. Writing to this register inserts an entry into the command FIFO. Writing to this register when the command FIFO is full has no effect and the written entry is discarded. Reading from this register always returns 0x0.

0x39 0xe4 SDO_FIFO

[31:0] SDO_FIFO WO

SDO FIFO register. Writing to this register inserts an entry into the SDO FIFO. Writing to this register when the SDO FIFO is full has no effect and the written entry is discarded. Reading from this register always returns 0x0.

0x3a 0xe8 SDI_FIFO

[31:0] SDI_FIFO RO

SDI FIFO register. Reading from this register removes the first entry from the SDI FIFO. Reading this register when the SDI FIFO is empty will return undefined data. Writing to it has no effect.

0x3b 0xec SDI_FIFO_MSB

[31:0] SDI_FIFO_MSB RO

Store SDI’s 32 bits MSB, if exists.

0x3c 0xf0 SDI_FIFO_PEEK

[31:0] SDI_FIFO_PEEK RO

SDI FIFO peek register. Reading from this register returns the first entry from the SDI FIFO, but without removing it from the FIFO. Reading this register when the SDI FIFO is empty will return undefined data. Writing to it has no effect.

0x40 0x100 OFFLOAD0_EN

[31:0] OFFLOAD0_EN RW 0x00000000

Set this bit to enable the offload module.

0x41 0x104 OFFLOAD0_STATUS

[31:0] OFFLOAD0_STATUS RO 0x00000000

Offload status register.

0x42 0x108 OFFLOAD0_MEM_RESET

[31:0] OFFLOAD0_MEM_RESET WO 0x00000000

Reset the memory of the offload module.

0x44 0x110 OFFLOAD0_CDM_FIFO

[31:0] OFFLOAD0_CDM_FIFO WO

Offload command FIFO register. Writing to this register inserts an entry into the command FIFO of the offload module. Writing to this register when the command FIFO is full has no effect and the written entry is discarded. Reading from this register always returns 0x0.

0x45 0x114 OFFLOAD0_SDO_FIFO

[31:0] OFFLOAD0_SDO_FIFO WO

Offload SDO FIFO register. Writing to this register inserts an entry into the offload SDO FIFO. Writing to this register when the SDO FIFO is full has no effect and the written entry is discarded. Reading from this register always returns 0x0.

0x80 0x200 CFG_INFO_0

[31:0] CFG_INFO_0 RO CFG_​INFO_​0

Configuration Info.

0x81 0x204 CFG_INFO_1

[31:0] CFG_INFO_1 RO CFG_​INFO_​1

Configuration Info.

0x82 0x208 CFG_INFO_2

[31:0] CFG_INFO_2 RO CFG_​INFO_​2

Configuration Info.

0x83 0x20c CFG_INFO_3

[31:0] CFG_INFO_4 RO CFG_​INFO_​3

Configuration Info.

Access Type

Name

Description

RO

Read-only

Reads will return the current register value. Writes have no effect.

RW

Read-write

Reads will return the current register value. Writes will change the current register value.

RW1C

Read,write-1-to-clear

Reads will return the current register value. Writing the register will clear those bits of the register which were set to 1 in the value written. Bits are set by hardware.

WO

Write-only

Writes will change the current register value. Reads have no effect.

Theory of Operation

Typically a software application running on a CPU will be able to execute much faster than the SPI engine command will be processed. In order to allow the software to execute other tasks while the SPI engine is busy processing commands the AXI SPI Engine peripheral offers interrupt-driven notification which can be used to notify the software when a SPI command has been executed. In order to reduce the necessary context switches the AXI SPI Engine peripheral incorporates FIFOs to buffer the command as well as the data streams.

FIFOs

The AXI SPI Engine peripheral has three FIFOs, one for each of the command, SDO and SDI streams. The size of the FIFOs can be configured by setting the CMD_FIFO_ADDRESS_WIDTH, SDO_FIFO_ADDRESS_WIDTH and SDI_FIFO_ADDRESS_WIDTH parameters.

One end of the FIFOs are connected to a memory-mapped register and can be accessed via the AXI-Lite interface. The other end is directly connected to the matching stream of the SPI Engine Control Interface.

Data can be inserted into the command FIFO by writing to the CMD_FIFO register and new data can be inserted into the SDO_FIFO register. If an application attempts to write to a FIFO while the FIFO is already full the data is discarded and the state of the FIFO remains unmodified. The number of empty entries in the command and SDO FIFO can be queried by reading the CMD_FIFO_ROOM or SDO_FIFO_ROOM register.

Data can be removed from the SDI FIFO by reading from the SDI_FIFO register. If an application attempts to read data while the FIFO is empty undefined data is returned and the state of the FIFO remains unmodified. It is possible to read the first entry in the SDI FIFO without removing it by reading from the SDI_FIFO_PEEK register. The number of valid entries in the SDI FIFO register can be queried by reading the SDI_FIFO_LEVEL register.

If the peripheral is disabled by setting the ENABLE register to 0 any data stored in the FIFOs is discarded and the state of the FIFO is reset.

Synchronization Events

Synchronization events can be used to notify the software application about the progress of the command stream. An application can insert a SYNC instruction at any point in the command stream. If the execution module reaches the SYNC instruction it will generate an event on the SYNC stream. When this event is received by the AXI SPI Engine peripheral it will update the SYNC_ID register with the received event ID and will assert the SYNC_EVENT interrupt.

Typically the SYNC instruction should be inserted after the last instruction in a SPI transaction. This will allow the application to be notified about the completion of the transaction and allows it to do further processing based on the result of the transaction.

It is recommended that synchronization IDs are generated in a monotonic incrementing or decrementing manner. This makes it possible to easily check if an event has completed by checking if it is less or equal (incrementing IDs) or more or equal (decrementing IDs) to the ID of the last completed event.

Interrupts

The SPI Engine AXI peripheral has 4 internal interrupts, which are asserted when:

  • CMD_ALMOST_EMPTY: the level falls bellow the almost empty level.

  • SDO_ALMOST_EMPTY: the level falls bellow the almost empty level.

  • SDI_ALMOST_FULL: the level rises above the almost full level.

  • SYNC_EVENT: a new synchronization event arrives.

The peripheral has 1 external interrupt which is supposed to be connected to the upstream interrupt controller. The external interrupt is a logical OR-operation over the internal interrupts, meaning if at least one of the internal interrupts is asserted the external interrupt is asserted and only if all internal interrupts are de-asserted the external interrupt is de-asserted.

In addition, each interrupt has a mask bit which can be used to stop the propagation of the internal interrupt to the external interrupt. If an interrupt is masked it will count towards the external interrupt state as if it were not asserted.

The mask bits can be modified by writing to the IRQ_MASK register. The raw interrupt status can be read from the IRQ_SOURCE register and the combined state of the IRQ_MASK and raw interrupt state can be read from the IRQ_PENDING register:

IRQ_PENDING = IRQ_SOURCE & IRQ_MASK;
IRQ = |IRQ_PENDING;

FIFO Threshold Interrupts

The FIFO threshold interrupts can be used by software for flow control of the command, SDI and SDO streams.

If an application wants to send more data than what fits into the FIFO can write samples into the FIFO until it is full then suspend operation wait for the almost empty interrupt and continue writing data to the FIFO. Similarly, when the application wants to read more data than what fits into FIFO it should listen for the almost full interrupt and read data from the FIFO when it occurs.

The FIFO threshold interrupt is asserted when then FIFO level rises above the watermark and is automatically de-asserted when the level drops below the watermark.

SYNC_EVENT Interrupt

The SYNC_EVENT interrupt is asserted when a new sync event is received from the sync stream. An application that generated a SYNC instruction on the command stream can use this interrupt to be notified when the sync instruction has been completed.

To de-assert the SYNC_EVENT interrupt, the application needs to acknowledge its reception by writing 1 to the SYNC_EVENT bit in the IRQ_PENDING register.