Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SPI MASTER CONTROLLER

A configurable, synthesizable SPI master in Verilog supporting all four SPI modes, full-duplex 8-bit transfers, and a self-checking testbench against a behavioral slave model.

Author: Avinash Kollu · GitHub: @avinashkollu-git

Overview

spi_master is a parameterized SPI master controller implementing full-duplex, MSB-first, 8-bit serial transfers with a single active-low chip select. It generates the serial clock (SCLK) from the system clock via a configurable divider, drives MOSI, and samples MISO on the correct edge for the selected SPI mode. A three-state FSM (IDLETRANSFERFINISH) sequences each byte and exposes a simple busy/done handshake alongside the received byte on rx_byte.

All four SPI modes are supported through the CPOL and CPHA parameters, so the same RTL retargets to any standard SPI slave without modification.

Features

  • All 4 SPI modes selectable via CPOL and CPHA parameters
  • Configurable clock divider: CLK_DIV sets the SCLK period to 2 * CLK_DIV system clocks
  • Full-duplex: simultaneous transmit on MOSI and receive on MISO
  • MSB-first, 8-bit transfers
  • done / busy handshake for clean integration with a host FSM or bus
  • Fully parameterized: no hard-coded mode or timing

SPI Modes

Mode CPOL CPHA Sample edge
0 0 0 Sample on rising (leading) edge; SCLK idles low
1 0 1 Sample on falling (trailing) edge; SCLK idles low
2 1 0 Sample on falling (leading) edge; SCLK idles high
3 1 1 Sample on rising (trailing) edge; SCLK idles high

Block Diagram

                         spi_master
        ┌──────────────────────────────────────────────┐
        │                                              │
  tx_byte[7:0] ─►┌──────────────────┐                  │
        │        │  TX shift register├──► MOSI          │──► MOSI
        │        └──────────────────┘                  │
        │                                              │
  MISO ─┼──────► ┌──────────────────┐                  │
        │        │  RX shift register├──► rx_byte[7:0]  │──► rx_byte[7:0]
        │        └──────────────────┘                  │
        │                                              │
  CLK_DIV ─────► ┌──────────────────┐                  │
        │        │  SCLK generator   ├──► SCLK          │──► SCLK
        │        └──────────────────┘                  │
        │                                              │
        │        ┌──────────────────┐                  │
        │        │ FSM: IDLE/TRANSFER├──► cs_n control  │──► cs_n (active low)
        │        │      /FINISH      ├──► busy, done    │──► busy, done
        │        └──────────────────┘                  │
        │                                              │
        └──────────────────────────────────────────────┘

Repository Layout

spi-master/
├── rtl/
│   └── spi_master.v        # configurable SPI master RTL
├── tb/
│   ├── spi_slave_model.v   # behavioral SPI slave for loopback
│   └── tb_spi_master.v     # self-checking testbench (all four modes)
├── tools/
│   └── vcd2svg.py          # VCD → SVG waveform renderer
├── docs/
│   └── spi_wave.svg        # committed reference waveform
├── Makefile
├── LICENSE                 # MIT
└── README.md

Simulation & Results

Built and run on the open-source flow, Icarus Verilog for simulation, GTKWave for waveform inspection.

make test    # run all four SPI modes, full-duplex, self-checking
make wave    # regenerate docs/spi_wave.svg from the VCD

The testbench instantiates a spi_master + spi_slave_model pair for each of the four modes (CPOL/CPHA) and runs a full-duplex transfer, checking both directions:

Mode CPOL CPHA Master TX Master RX (exp/got) Slave RX (exp/got) Result
0 0 0 0xA5 0x3C / 0x3C 0xA5 / 0xA5 PASS
1 0 1 0x5A 0xC3 / 0xC3 0x5A / 0x5A PASS
2 1 0 0x0F 0xF0 / 0xF0 0x0F / 0x0F PASS
3 1 1 0x99 0x66 / 0x66 0x99 / 0x99 PASS
RESULT: ALL TESTS PASSED

Waveform

SPI waveform

In this mode-0 capture, cs_n asserts to frame the transfer, SCLK toggles for eight cycles, and 0xA5 shifts out MSB-first on MOSI while 0x3C is captured on MISO.

Design Notes

  • CPOL / CPHA edge semantics. CPOL sets the idle level of SCLK; CPHA selects which of the two clock edges captures data. Sampling and shifting always occur on opposite SCLK edges so that data is stable when latched.
  • CPHA first-edge MSB handling. For CPHA = 0, the first data bit is presented before the leading edge and sampled on that leading edge. For CPHA = 1, the MSB is presented on the first leading edge; a dedicated first-edge guard prevents the MSB from being dropped, which is a common source of off-by-one bugs in CPHA=1 implementations.
  • Clock divider. CLK_DIV sets the SCLK period to 2 * CLK_DIV system clocks, giving a symmetric, integer-divided serial clock and decoupling the design from any specific system-clock frequency.

Skills Demonstrated

  • Protocol / interface design (SPI, all four modes)
  • Finite state machine design (IDLE / TRANSFER / FINISH)
  • Clock generation and integer clock division
  • Full-duplex serial data path (parallel-in/serial-out and serial-in/parallel-out shift registers)
  • Parameterized, reusable IP
  • Self-checking verification against a reference slave model

License

Released under the MIT License.

About

Configurable SPI master in Verilog: all four CPOL/CPHA modes, full-duplex, self-checking testbench.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages