Quanta ControlQuantaControl

Projects / IP Core

OctoSPI FPGA IP Core

OctoSPI slave IP core for Xilinx FPGAs with AXI4-Lite bridge and Embassy/Rust async driver for STM32U595. Enables high-speed MCU ↔ FPGA communication over an 8-bit single-transfer-rate interface.

View on GitHub ↗

System Overview

STM32U595  ──OctoSPI──▶  octo_spi_slave  ──▶  octo_spi_axi_master  ──▶  BRAM A/B/C/D
Embassy/Rust driver       Protocol FSM           AXI4-Lite bridge          axi_addr_decoder
                         (dual-buffer prefetch)  (req/rsp bridge)

The STM32U595 drives the OctoSPI master using the driver on top of Embassy async runtime. All IO[7:0] transfers run in 8-bit STR (single-transfer-rate) mode.

Inside the FPGA, octo_spi_slave parses the 7-state protocol FSM and issues AXI4-Lite requests via octo_spi_axi_master. An address decoder routes each transaction to one of four BRAM slaves based on addr[17:16].

Clock domain: 54 MHz board input → PLL → aclk at 100 MHz.

Protocol Frame Structure

CMD
1 byte
AUX
2 bytes
ADDR
4 bytes
DUMMY
8 cycles
DATA
N bytes

All fields transferred in 8-bit STR mode on IO[7:0]. DUMMY cycles are used for dual-buffer AXI prefetch on read transactions.

Command Opcodes

OpcodeHexDescription
CMD_WRITE_INCR0xCABurst write, auto-increment address
CMD_WRITE_FIXED0xFERepeated write to fixed address (FIFO push)
CMD_READ_INCR0xBABurst read, auto-increment address
CMD_READ_FIXED0xBERepeated read from fixed address (FIFO pop)

Module Responsibilities

ModuleFileRole
octo_spi_slaveospi/rtl/octo_spi_slave.svProtocol parser FSM, dual-buffer prefetch, write accumulator
octo_spi_axi_masterospi/rtl/octo_spi_axi_master.svAXI4-Lite request/response bridge
octo_spi_topospi/rtl/octo_spi_top.svI/O synchronizer wrapper
octospi_bram_test_topeval/rtl/octospi_bram_test_top.svBoard top: PLL, reset sync, 2-to-1 arbiter
axi_addr_decodereval/rtl/axi_addr_decoder.svRoutes AXI transactions to BRAM A/B/C/D via addr[17:16]
axi_lite_brameval/rtl/axi_lite_bram.svPlain synchronous BRAM (BRAM C)
axi_lite_bram_fifoeval/rtl/axi_lite_bram_fifo.svCircular BRAM with software FIFO API (BRAM D)
bram_incr_fill_mastereval/rtl/bram_incr_fill_master.svAuto-fills BRAM A with a counter on each read request
bram_fifo_mastereval/rtl/bram_fifo_master.svHardware FIFO producer for BRAM B

BRAM Address Map

ExampleBRAMAXI Base AddressFunction
bram_aA0x0000_0000READ_INCR — triggers auto counter fill on read
bram_bB0x0001_0000READ_FIXED — pops from hardware FIFO
bram_cC0x0002_0000WRITE_INCR + READ_INCR roundtrip
bram_dD0x0003_0000WRITE_FIXED + READ_FIXED software FIFO

ILA Probe Reference

Trigger position: 3000 pre-trigger + 1096 post-trigger = 4096 total depth. Clock domain: aclk (100 MHz). Primary trigger probe: probe7 (req_valid).

ProbeWidthSignal
probe024{state[3:0], cnt[7:0], captured_byte[7:0], driving, initial_valid, prefetch_valid, word1_done}
probe132shift_out — OctoSPI shift register contents
probe232initial_buf — first AXI read response buffer
probe332prefetch_buf — prefetch read response buffer
probe48ospi_io_in — IO pins driven by STM32
probe58ospi_io_out — IO pins driven by FPGA
probe65{aresetn, csn_sync, sclk_sync, sclk_rise, byte_ready}
probe734{req_valid, req_read, req_addr[31:0]} ← primary trigger
probe833{rsp_valid, rsp_rdata[31:0]} — AXI read return data

FSM State Decode (probe0[23:20])

ValueStateMeaning
0ST_IDLEWaiting for CSn assertion
1ST_CMDReceiving CMD byte
2ST_AUXReceiving AUX bytes
3ST_ADDRReceiving address bytes
4ST_DUMMYDummy cycles — prefetch AXI reads issued here
5ST_DATAData read/write phase
6ST_DONETransaction complete

Quick Start

1

Build the FPGA Bitstream

Requires Vivado 2024.x or 2025.x. Synthesis + implementation takes ~30 minutes.

cd fpga
make bitstream   # or: make project && make gui
2

Program the FPGA

Start hw_server (or open Hardware Manager in Vivado GUI) first.

cd fpga
make program
3

Run STM32 Tests

Requires Rust stable + thumbv8m.main-none-eabihf target and probe-rs ≥ 0.24.

cd stm32
export PROBE_RS_PROBE=<your-probe-serial>
cargo run --example bram_a   # READ_INCR auto-fill
cargo run --example bram_b   # READ_FIXED FIFO pop
cargo run --example bram_c   # WRITE+READ roundtrip
cargo run --example bram_d   # WRITE+READ software FIFO

Related