library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity SPI_controller is
generic(num_bits : positive := 8);
port(RESET_F : in std_logic;
CSF : out std_logic;
SYS_CLK : in std_logic;
CPHA : in std_logic;
CPOL : in std_logic;
MOSI : out std_logic;
MISO : in std_logic;
rd_data_out : out std_logic_vector(7 downto 0);
wr_data_out : out std_logic_vector(7 downto 0);
-- TEST_POINT : out std_logic;
START_XFR_F : in std_logic;
SCLK : out std_logic
);
end SPI_controller;
architecture arch of SPI_controller is
type state_type is (IDLE, XMIT, RCV);
signal state : state_type;
signal count_max : integer := 20;
signal count_half : integer := count_max/2;
signal clk_count : integer := 0;
signal spi_clk : std_logic;
signal i_spi_clk : std_logic;
signal i_csf : std_logic;
signal start_spi_clk : std_logic;
-- signal i_test_point : std_logic;
signal wr_shift_reg : std_logic_vector(7 downto 0);
signal rd_shift_reg : std_logic_vector(7 downto 0);
signal rd_data_buf : std_logic_vector(7 downto 0);
signal word_size : unsigned(2 downto 0) := "111";
signal data_count : unsigned(2 downto 0);
signal i_wr_data : std_logic_vector(num_bits - 1 downto 0);
signal spi_start : std_logic;
signal prev_spi_clk : std_logic;
signal i_busy : std_logic;
begin
--TEST_POINT <= i_test_point;
SCLK <= i_spi_clk;
CSF <= i_csf;
rd_data_out <= rd_shift_reg;
wr_data_out <= wr_shift_reg;
MOSI <= wr_shift_reg(0);
---==========================================
-- Generate SPI Clk (SCLK Freq)
---==========================================
CLK_DIV : process (SYS_CLK, RESET_F, i_csf)
begin
if RESET_F = '0' then
spi_clk <= '0';
clk_count <= 0;
elsif SYS_CLK'event and SYS_CLK = '1' then
clk_count <= 0;
spi_clk <= '0';
if i_csf = '0' then
if (clk_count < count_max - 1) then
clk_count <= clk_count + 1;
else
clk_count <= 0;
end if;
if (clk_count < count_half) then
spi_clk <= '0';
else
spi_clk <= '1';
end if;
end if;
end if;
end process;
---==========================================
-- State Machine
---==========================================
STATE_MACHINE : process (SYS_CLK, RESET_F, CPHA)
begin
if RESET_F = '0' then
i_csf <= '1';
-- i_test_point <= '0';
state <= IDLE;
rd_shift_reg <= (others => '0');
wr_shift_reg <= x"28";
data_count <= (others => '0');
i_busy <= '0';
elsif SYS_CLK'event and SYS_CLK = '1' then
prev_spi_clk <= spi_clk;
if prev_spi_clk = '0' and spi_clk = '1' then
-- i_test_point <= '1';
else
-- i_test_point <= '0';
end if;
case state is
when IDLE =>
i_csf <= '1';
if START_XFR_F = '0' and i_busy = '0' then
i_busy <= '1';
i_csf <= '0';
state <= XMIT;
end if;
when XMIT =>
if prev_spi_clk = '1' and spi_clk = '0' then
if (data_count < word_size) then
data_count <= data_count + 1;
else
data_count <= (others => '0');
rd_data_buf <= rd_shift_reg;
state <= IDLE;
end if;
end if;
-- CPHA Handler for SPI Clk
if CPHA = '0' and prev_spi_clk = '0' and spi_clk = '1' then
rd_shift_reg <= MISO & rd_shift_reg(7 downto 1);
elsif CPHA = '0' and prev_spi_clk = '1' and spi_clk = '0' then
wr_shift_reg <= '0' & wr_shift_reg(7 downto 1);
elsif CPHA = '1' and prev_spi_clk = '0' and spi_clk = '1' then -- Need to wait one clock first
wr_shift_reg <= '0' & wr_shift_reg(7 downto 1);
elsif CPHA = '1' and prev_spi_clk = '1' and spi_clk = '0' then
rd_shift_reg <= MISO & rd_shift_reg(7 downto 1);
end if;
when RCV =>
end case;
end if;
end process;
---==========================================
-- CPOL Handler for SPI Clk
---==========================================
OUTPUT_PROC : process (SYS_CLK, RESET_F, CPOL)
begin
if RESET_F = '0' then
elsif SYS_CLK'event and SYS_CLK = '1' then
if CPOL = '1' then
i_spi_clk <= not spi_clk;
else
i_spi_clk <= spi_clk;
end if;
end if;
end process;
end arch;