Browse Source

add synthesizable and configurable SPI master component and enhance unit test

pull/1/head
T. Meissner 10 years ago
parent
commit
5dd42b80a2
2 changed files with 234 additions and 2 deletions
  1. +232
    -0
      syn/SpiMasterE.vhd
  2. +2
    -2
      test/Makefile

+ 232
- 0
syn/SpiMasterE.vhd View File

@ -0,0 +1,232 @@
library ieee;
use ieee.std_logic_1164.all;
entity SpiMasterE is
generic (
G_DATA_WIDTH : positive := 8; --* data bus width
G_SPI_CPOL : natural range 0 to 1 := 0; --* SPI clock polarity
G_SPI_CPHA : natural range 0 to 1 := 0; --* SPI clock phase
G_SCLK_DIVIDER : positive := 10 --* SCLK divider related to system clock
);
port (
--+ system if
Reset_n_i : in std_logic;
Clk_i : in std_logic;
--+ SPI slave if
SpiSclk_o : out std_logic;
SpiSte_o : out std_logic;
SpiMosi_o : out std_logic;
SpiMiso_i : in std_logic;
--+ local VAI if
Data_i : in std_logic_vector(G_DATA_WIDTH-1 downto 0);
DataValid_i : in std_logic;
DataAccept_o : out std_logic;
Data_o : out std_logic_vector(G_DATA_WIDTH-1 downto 0);
DataValid_o : out std_logic;
DataAccept_i : in std_logic
);
end entity SpiMasterE;
architecture rtl of SpiMasterE is
type t_spi_state is (IDLE, WRITE, READ, CYCLE, STORE, SET_STE);
signal s_spi_state : t_spi_state;
signal s_send_register : std_logic_vector(G_DATA_WIDTH-1 downto 0);
signal s_recv_register : std_logic_vector(G_DATA_WIDTH-1 downto 0);
signal s_miso_d : std_logic_vector(1 downto 0);
signal s_mosi : std_logic;
signal s_sclk : std_logic;
signal s_ste : std_logic;
signal s_data_valid : std_logic;
signal s_data_accept : std_logic;
signal s_transfer_valid : boolean;
signal s_sclk_rising : boolean;
signal s_sclk_falling : boolean;
signal s_read_edge : boolean;
signal s_write_edge : boolean;
alias a_miso : std_logic is s_miso_d(s_miso_d'left);
begin
--* Sync asynchronous SPI inputs with 2 stage FF line
SpiSyncP : process (Reset_n_i, Clk_i) is
begin
if (Reset_n_i = '0') then
s_miso_d <= (others => '0');
elsif rising_edge(Clk_i) then
s_miso_d <= s_miso_d(0) & SpiMiso_i;
end if;
end process SpiSyncP;
--* Save local data input when new data is provided and
--* we're not inside a running SPI transmission
SendRegisterP : process (Reset_n_i, Clk_i) is
begin
if (Reset_n_i = '0') then
s_send_register <= (others => '0');
s_data_accept <= '0';
elsif rising_edge(Clk_i) then
s_data_accept <= '0';
if (DataValid_i = '1' and s_spi_state = IDLE) then
s_send_register <= Data_i;
s_data_accept <= '1';
end if;
end if;
end process SendRegisterP;
--* Spi master control FSM
SpiControlP : process (Reset_n_i, Clk_i) is
variable v_bit_counter : natural range 0 to G_DATA_WIDTH-1;
variable v_sclk_counter : natural range 0 to G_SCLK_DIVIDER-1;
begin
if (Reset_n_i = '0') then
s_recv_register <= (others => '0');
v_bit_counter := G_DATA_WIDTH-1;
v_sclk_counter := G_SCLK_DIVIDER-1;
s_transfer_valid <= false;
s_ste <= '1';
s_sclk <= std_logic'val(G_SPI_CPOL+2);
s_mosi <= '1';
s_spi_state <= IDLE;
elsif rising_edge(Clk_i) then
case s_spi_state is
when IDLE =>
s_ste <= '1';
s_sclk <= std_logic'val(G_SPI_CPOL+2);
s_mosi <= '0';
s_recv_register <= (others => '0');
v_bit_counter := G_DATA_WIDTH-1;
v_sclk_counter := G_SCLK_DIVIDER/2-1;
s_transfer_valid <= false;
if(DataValid_i = '1' and s_data_accept = '1') then
s_ste <= '0';
s_spi_state <= WRITE;
end if;
when WRITE =>
if (G_SPI_CPHA = 0 and v_bit_counter = G_DATA_WIDTH-1) then
s_mosi <= s_send_register(v_bit_counter);
s_spi_state <= READ;
else
if (v_sclk_counter = 0) then
v_sclk_counter := G_SCLK_DIVIDER/2-1;
s_sclk <= not(s_sclk);
s_mosi <= s_send_register(v_bit_counter);
s_spi_state <= READ;
else
v_sclk_counter := v_sclk_counter - 1;
end if;
end if;
when READ =>
if (v_sclk_counter = 0) then
s_sclk <= not(s_sclk);
s_recv_register(v_bit_counter) <= a_miso;
v_sclk_counter := G_SCLK_DIVIDER/2-1;
if (v_bit_counter = 0) then
if (G_SPI_CPHA = 0) then
s_spi_state <= CYCLE;
else
s_spi_state <= STORE;
end if;
else
v_bit_counter := v_bit_counter - 1;
s_spi_state <= WRITE;
end if;
else
v_sclk_counter := v_sclk_counter - 1;
end if;
when CYCLE =>
if (v_sclk_counter = 0) then
s_sclk <= not(s_sclk);
v_sclk_counter := G_SCLK_DIVIDER/2-1;
s_spi_state <= STORE;
else
v_sclk_counter := v_sclk_counter - 1;
end if;
when STORE =>
if (v_sclk_counter = 0) then
s_transfer_valid <= true;
v_sclk_counter := G_SCLK_DIVIDER/2-1;
s_spi_state <= SET_STE;
else
v_sclk_counter := v_sclk_counter - 1;
end if;
when SET_STE =>
s_transfer_valid <= false;
s_ste <= '1';
if (v_sclk_counter = 0) then
s_spi_state <= IDLE;
else
v_sclk_counter := v_sclk_counter - 1;
end if;
when others =>
s_spi_state <= IDLE;
end case;
end if;
end process SpiControlP;
--* Provide received SPI data to local interface
--* Output data is overwritten if it isn't fetched
--* until next finished SPI transmission
RecvRegisterP : process (Reset_n_i, Clk_i) is
begin
if (Reset_n_i = '0') then
Data_o <= (others => '0');
s_data_valid <= '0';
elsif rising_edge(Clk_i) then
if (s_transfer_valid) then
Data_o <= s_recv_register;
s_data_valid <= '1';
end if;
if (DataAccept_i = '1' and s_data_valid = '1') then
s_data_valid <= '0';
end if;
end if;
end process RecvRegisterP;
--+ Output port connections
DataValid_o <= s_data_valid;
DataAccept_o <= s_data_accept;
SpiSte_o <= s_ste;
SpiSclk_o <= s_sclk;
SpiMosi_o <= s_mosi;
assert G_SCLK_DIVIDER rem 2 = 0
report "WARNING: " & SpiMasterE'instance_name & LF & "G_SCLK_DIVIDER rounded down to next even value"
severity warning;
-- psl default clock is rising_edge(Clk_i);
--
-- psl assert always (s_spi_state = IDLE or s_spi_state = WRITE or s_spi_state = READ or
-- s_spi_state = CYCLE or s_spi_state = SET_STE or s_spi_state = STORE);
-- psl assert always (s_data_valid and DataAccept_i) -> next not(s_data_valid);
end architecture rtl;

+ 2
- 2
test/Makefile View File

@ -23,9 +23,9 @@ simt : SimT.vhd $(SIM_SRC)/StringP.vhd $(SIM_SRC)/AssertP.vhd $(SIM_SRC)/SimP.vh
ghdl -e --std=$(VHD_STD) SimT
ghdl -r --std=$(VHD_STD) SimT
spit : SpiT.vhd $(SIM_SRC)/StringP.vhd $(SIM_SRC)/AssertP.vhd $(SIM_SRC)/SimP.vhd $(SYN_SRC)/SpiSlaveE.vhd
spit : vhdl2008 SpiT.vhd $(SIM_SRC)/StringP.vhd $(SIM_SRC)/AssertP.vhd $(SIM_SRC)/SimP.vhd $(SYN_SRC)/SpiSlaveE.vhd $(SYN_SRC)/SpiMasterE.vhd
ghdl -a --std=$(VHD_STD) --work=libvhdl $(SIM_SRC)/StringP.vhd $(SIM_SRC)/AssertP.vhd $(SIM_SRC)/SimP.vhd
ghdl -a --std=$(VHD_STD) -fpsl $(SYN_SRC)/SpiSlaveE.vhd
ghdl -a --std=$(VHD_STD) -fpsl $(SYN_SRC)/SpiSlaveE.vhd $(SYN_SRC)/SpiMasterE.vhd
ghdl -a --std=$(VHD_STD) -fpsl SpiT.vhd
ghdl -e --std=$(VHD_STD) SpiT
ghdl -r --std=$(VHD_STD) SpiT --wave=spit.ghw


Loading…
Cancel
Save