------------------------------------------------------------------------------- -- Title : simple SPI slave -- Project : ------------------------------------------------------------------------------- -- File : spi_slave.vhd -- Author : Mario Hüttel -- 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'); miso_int <= '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; miso_int <= shift_reg(7); 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 <= miso_int when cs = '0' else 'Z'; end architecture RTL;