VHDL Code for SPI Slave: Syntax, Example, and Tips
A basic
SPI slave in VHDL uses signals for SCLK, MOSI, MISO, and SS. The slave reads data on the clock edges when SS is active and shifts data out on MISO. This requires a state machine to track bits and synchronize communication.Syntax
An SPI slave in VHDL typically has these ports:
- SCLK: Serial clock input from master
- MOSI: Master Out Slave In data input
- MISO: Master In Slave Out data output
- SS: Slave select input (active low)
- clk: Internal clock for logic synchronization
- rst: Reset signal
The main process triggers on the rising edge of SCLK when SS is low to shift in data bits and shift out response bits.
vhdl
entity spi_slave is
Port (
clk : in std_logic;
rst : in std_logic;
sclk : in std_logic;
mosi : in std_logic;
miso : out std_logic;
ss : in std_logic
);
end spi_slave;Example
This example shows a simple SPI slave that receives 8 bits from the master and sends back the same byte incremented by 1. It uses a shift register and a bit counter.
vhdl
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity spi_slave is
Port (
clk : in std_logic;
rst : in std_logic;
sclk : in std_logic;
mosi : in std_logic;
miso : out std_logic;
ss : in std_logic
);
end spi_slave;
architecture Behavioral of spi_slave is
signal bit_count : integer range 0 to 7 := 0;
signal shift_reg_in : std_logic_vector(7 downto 0) := (others => '0');
signal shift_reg_out : std_logic_vector(7 downto 0) := (others => '0');
signal sclk_prev : std_logic := '0';
begin
process(clk, rst)
begin
if rst = '1' then
bit_count <= 0;
shift_reg_in <= (others => '0');
shift_reg_out <= (others => '0');
miso <= '0';
sclk_prev <= '0';
elsif rising_edge(clk) then
sclk_prev <= sclk;
if ss = '0' then -- Active low slave select
-- Detect rising edge of SCLK
if sclk_prev = '0' and sclk = '1' then
-- Shift in MOSI bit
shift_reg_in <= shift_reg_in(6 downto 0) & mosi;
-- Shift out MSB bit on MISO
miso <= shift_reg_out(7);
-- Shift left output register
shift_reg_out <= shift_reg_out(6 downto 0) & '0';
if bit_count = 7 then
bit_count <= 0;
-- Prepare next output: increment received byte
shift_reg_out <= std_logic_vector(unsigned(shift_reg_in) + 1);
else
bit_count <= bit_count + 1;
end if;
end if;
else
bit_count <= 0;
miso <= '0';
end if;
end if;
end process;
end Behavioral;Output
No direct console output; the SPI slave shifts in 8 bits on SCLK rising edges when SS is low and outputs incremented data on MISO.
Common Pitfalls
Common mistakes when writing an SPI slave in VHDL include:
- Not synchronizing
SCLKto the internal clock domain, causing metastability. - Ignoring the
SSsignal, which disables the slave when high. - Shifting data on the wrong clock edge (SPI mode matters).
- Not resetting counters and registers properly.
Always detect clock edges carefully and handle SS to avoid data corruption.
vhdl
Wrong approach (shifting on internal clk without SCLK edge detection): process(clk) begin if rising_edge(clk) then shift_reg <= shift_reg(6 downto 0) & mosi; -- Incorrect: ignores SCLK end if; end process; Right approach (detect SCLK rising edge): process(clk) begin if rising_edge(clk) then if sclk_prev = '0' and sclk = '1' then shift_reg <= shift_reg(6 downto 0) & mosi; -- Correct end if; end if; end process;
Quick Reference
Tips for SPI slave in VHDL:
- Use a process synchronized to your system clock.
- Detect edges of
SCLKinside that process. - Use
SSto enable/disable shifting. - Shift data in on one clock edge and shift data out on the opposite edge if needed.
- Reset counters and registers on reset or when
SSgoes high.
Key Takeaways
Detect SCLK edges inside a clocked process to safely shift data in and out.
Use the SS signal to enable the SPI slave only when selected.
Shift registers hold incoming and outgoing data synchronized with SCLK.
Reset all counters and registers properly to avoid undefined states.
Test SPI modes carefully as clock polarity and phase affect data timing.