113 lines
3.2 KiB
VHDL
113 lines
3.2 KiB
VHDL
-------------------------------------------------------------------------------
|
|
-- Title : simple SPI slave
|
|
-- Project :
|
|
-------------------------------------------------------------------------------
|
|
-- File : spi_slave.vhd
|
|
-- Author : Mario Hüttel <mario.huettel@gmx.net>
|
|
-- Company :
|
|
-- Created : 2018-04-15
|
|
-- Last update: 2018-04-15
|
|
-- Platform :
|
|
-- Standard : VHDL'93/02
|
|
-------------------------------------------------------------------------------
|
|
-- Description: This SPI slaves samples the SPI's sck line
|
|
-- Therefore freq(clk) > 2.5 * freq(sck)
|
|
-------------------------------------------------------------------------------
|
|
-- Copyright (c) 2018
|
|
-------------------------------------------------------------------------------
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
entity spi_slave is
|
|
generic (
|
|
DAT_WIDTH : natural := 8);
|
|
port (
|
|
clk : in std_logic;
|
|
rst : in std_logic;
|
|
cs : in std_logic;
|
|
sck : in std_logic;
|
|
miso : out std_logic;
|
|
mosi : in std_logic;
|
|
dat_o : out std_logic_vector(DAT_WIDTH - 1 downto 0);
|
|
dat_i : in std_logic_vector(DAT_WIDTH - 1 downto 0);
|
|
dat_o_strb : out std_logic;
|
|
dat_i_ack : out std_logic);
|
|
|
|
end entity spi_slave;
|
|
|
|
|
|
architecture RTL of spi_slave is
|
|
signal sck_old : std_logic;
|
|
signal sck_sync : std_logic;
|
|
signal mosi_sync : std_logic;
|
|
signal cs_sync : std_logic;
|
|
signal pos_edge : std_logic;
|
|
signal neg_edge : std_logic;
|
|
signal miso_int : std_logic;
|
|
signal cnt : integer range 0 to DAT_WIDTH-1;
|
|
signal shift_reg : std_logic_vector(DAT_WIDTH -1 downto 0);
|
|
begin -- architecture RTL
|
|
|
|
sync : process (clk, rst) is
|
|
begin -- process sck_sync
|
|
if rst = '1' then -- asynchronous reset (active high)
|
|
sck_sync <= '0';
|
|
mosi_sync <= '0';
|
|
cs_sync <= '0';
|
|
elsif rising_edge(clk) then -- rising clock edge
|
|
cs_sync <= cs;
|
|
mosi_sync <= mosi;
|
|
sck_sync <= sck;
|
|
end if;
|
|
end process sync;
|
|
|
|
edge_detector : process (clk, rst) is
|
|
begin -- process edge_detector
|
|
if rst = '1' then -- asynchronous reset (active high)
|
|
pos_edge <= '0';
|
|
neg_edge <= '0';
|
|
elsif rising_edge(clk) then -- rising clock edge
|
|
neg_edge <= '0';
|
|
pos_edge <= '0';
|
|
sck_old <= sck_sync;
|
|
if sck_old = '1' and sck_sync = '0' then
|
|
neg_edge <= '1';
|
|
elsif sck_old = '0' and sck_sync = '1' then
|
|
pos_edge <= '1';
|
|
end if;
|
|
end if;
|
|
end process edge_detector;
|
|
|
|
shifter : process (clk, rst) is
|
|
begin -- process shifter
|
|
if rst = '1' then -- asynchronous reset (active high)
|
|
shift_reg <= (others => '0');
|
|
dat_i_ack <= '0';
|
|
dat_o <= (others => '0');
|
|
cnt <= 0;
|
|
elsif rising_edge(clk) then -- rising clock edge
|
|
dat_i_ack <= '0';
|
|
dat_o_strb <= '0';
|
|
if pos_edge = '1' and cs_sync = '0' then
|
|
shift_reg <= shift_reg(DAT_WIDTH-2 downto 0) & mosi_sync;
|
|
|
|
if cnt < DAT_WIDTH-1 then
|
|
cnt <= cnt + 1;
|
|
else
|
|
cnt <= 0;
|
|
end if;
|
|
if cnt = DAT_WIDTH - 1 then
|
|
dat_o <= shift_reg(DAT_WIDTH -2 downto 0) & mosi_sync;
|
|
dat_o_strb <= '1';
|
|
shift_reg <= dat_i;
|
|
dat_i_ack <= '1';
|
|
end if;
|
|
end if;
|
|
end if;
|
|
end process shifter;
|
|
miso_int <= shift_reg(7);
|
|
miso <= miso_int when cs = '0' else 'Z';
|
|
|
|
end architecture RTL;
|