Skip to content

Commit

Permalink
SPI MASTER: Added DIN_LAST input. Lot of optimalizations and small
Browse files Browse the repository at this point in the history
edits.
  • Loading branch information
jakubcabal committed Sep 28, 2017
1 parent 322384a commit 75245d6
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 49 deletions.
5 changes: 3 additions & 2 deletions example/spi_loopback.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,10 @@ begin
MISO => M_MISO,
-- USER INTERFACE
ADDR => (others => '0'),
READY => open,
DIN => m_din,
DIN_LAST => '1',
DIN_VLD => m_din_vld,
READY => open,
DOUT => m_dout,
DOUT_VLD => m_dout_vld
);
Expand All @@ -261,9 +262,9 @@ begin
MOSI => S_MOSI,
MISO => S_MISO,
-- USER INTERFACE
READY => open,
DIN => s_din,
DIN_VLD => s_din_vld,
READY => open,
DOUT => s_dout,
DOUT_VLD => s_dout_vld
);
Expand Down
118 changes: 73 additions & 45 deletions rtl/spi_master.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,18 @@ entity SPI_MASTER is
CLK : in std_logic; -- system clock
RST : in std_logic; -- high active synchronous reset
-- SPI MASTER INTERFACE
SCLK : out std_logic;
CS_N : out std_logic_vector(SLAVE_COUNT-1 downto 0);
MOSI : out std_logic;
MISO : in std_logic;
-- USER INTERFACE
ADDR : in std_logic_vector(integer(ceil(log2(real(SLAVE_COUNT))))-1 downto 0); -- slave address
READY : out std_logic; -- when READY = 1, SPI master is ready to accept input data
DIN : in std_logic_vector(7 downto 0); -- input data for slave
DIN_VLD : in std_logic; -- when DIN_VLD = 1, input data are valid and can be accept
DOUT : out std_logic_vector(7 downto 0); -- output data from slave
SCLK : out std_logic; -- SPI clock
CS_N : out std_logic_vector(SLAVE_COUNT-1 downto 0); -- SPI chip select, active in low
MOSI : out std_logic; -- SPI serial data from master to slave
MISO : in std_logic; -- SPI serial data from slave to master
-- INPUT USER INTERFACE
ADDR : in std_logic_vector(integer(ceil(log2(real(SLAVE_COUNT))))-1 downto 0); -- SPI slave address
DIN : in std_logic_vector(7 downto 0); -- input data for SPI slave
DIN_LAST : in std_logic; -- when DIN_LAST = 1, after transmit these input data is asserted CS_N
DIN_VLD : in std_logic; -- when DIN_VLD = 1, input data are valid
READY : out std_logic; -- when READY = 1, valid input data are accept
-- OUTPUT USER INTERFACE
DOUT : out std_logic_vector(7 downto 0); -- output data from SPI slave
DOUT_VLD : out std_logic -- when DOUT_VLD = 1, output data are valid
);
end SPI_MASTER;
Expand All @@ -68,6 +70,7 @@ architecture RTL of SPI_MASTER is
signal sys_clk_cnt_rst : std_logic;
signal spi_clk : std_logic;
signal spi_clk_en : std_logic;
signal din_last_reg_n : std_logic;
signal first_edge_en : std_logic;
signal second_edge_en : std_logic;
signal chip_select_n : std_logic;
Expand All @@ -80,7 +83,7 @@ architecture RTL of SPI_MASTER is
signal rx_data_vld : std_logic;
signal master_ready : std_logic;

type state is (idle, first_edge, second_edge, transmit_end, disable_cs);
type state is (idle, first_edge, second_edge, transmit_end, transmit_gap);
signal present_state, next_state : state;

begin
Expand All @@ -89,9 +92,7 @@ begin

load_data <= master_ready and DIN_VLD;
READY <= master_ready;
DOUT <= shreg;
DOUT_VLD <= rx_data_vld;


-- -------------------------------------------------------------------------
-- SYSTEM CLOCK COUNTER
-- -------------------------------------------------------------------------
Expand Down Expand Up @@ -127,6 +128,24 @@ begin

SCLK <= spi_clk;

-- -------------------------------------------------------------------------
-- BIT COUNTER
-- -------------------------------------------------------------------------

bit_cnt_max <= '1' when (bit_cnt = "111") else '0';
bit_cnt_rst <= RST or not spi_clk_en;

bit_cnt_p : process (CLK)
begin
if (rising_edge(CLK)) then
if (bit_cnt_rst = '1') then
bit_cnt <= (others => '0');
elsif (second_edge_en = '1') then
bit_cnt <= bit_cnt + 1;
end if;
end if;
end process;

-- -------------------------------------------------------------------------
-- SPI MASTER ADDRESSING
-- -------------------------------------------------------------------------
Expand All @@ -153,6 +172,21 @@ begin
end process;
end generate;

-- -------------------------------------------------------------------------
-- DIN LAST RESISTER
-- -------------------------------------------------------------------------

din_last_reg_n_p : process (CLK)
begin
if (rising_edge(CLK)) then
if (RST = '1') then
din_last_reg_n <= '0';
elsif (load_data = '1') then
din_last_reg_n <= not DIN_LAST;
end if;
end if;
end process;

-- -------------------------------------------------------------------------
-- MISO SAMPLE REGISTER
-- -------------------------------------------------------------------------
Expand Down Expand Up @@ -181,22 +215,20 @@ begin
end if;
end process;

DOUT <= shreg;
MOSI <= shreg(7);

-- -------------------------------------------------------------------------
-- BIT COUNTER
-- DATA OUT VALID RESISTER
-- -------------------------------------------------------------------------

bit_cnt_max <= '1' when (bit_cnt = "111") else '0';
bit_cnt_rst <= RST or not spi_clk_en;

bit_cnt_p : process (CLK)
dout_vld_reg_p : process (CLK)
begin
if (rising_edge(CLK)) then
if (bit_cnt_rst = '1') then
bit_cnt <= (others => '0');
elsif (second_edge_en = '1') then
bit_cnt <= bit_cnt + 1;
if (RST = '1') then
DOUT_VLD <= '0';
else
DOUT_VLD <= rx_data_vld;
end if;
end if;
end process;
Expand All @@ -221,9 +253,7 @@ begin
fsm_next_state_p : process (present_state, DIN_VLD, sys_clk_cnt_max,
bit_cnt_max)
begin

case present_state is

when idle =>
if (DIN_VLD = '1') then
next_state <= first_edge;
Expand All @@ -239,43 +269,42 @@ begin
end if;

when second_edge =>
if (sys_clk_cnt_max = '1' and bit_cnt_max = '0') then
next_state <= first_edge;
elsif (sys_clk_cnt_max = '1' and bit_cnt_max = '1') then
next_state <= transmit_end;
if (sys_clk_cnt_max = '1') then
if (bit_cnt_max = '1') then
next_state <= transmit_end;
else
next_state <= first_edge;
end if;
else
next_state <= second_edge;
end if;

when transmit_end =>
if (DIN_VLD = '1') then
next_state <= first_edge;
if (sys_clk_cnt_max = '1') then
next_state <= transmit_gap;
else
next_state <= disable_cs;
next_state <= transmit_end;
end if;

when disable_cs =>
when transmit_gap =>
if (sys_clk_cnt_max = '1') then
next_state <= idle;
else
next_state <= disable_cs;
next_state <= transmit_gap;
end if;

when others =>
next_state <= idle;

end case;
end process;

-- OUTPUTS LOGIC
fsm_outputs_p : process (present_state, sys_clk_cnt_max)
fsm_outputs_p : process (present_state, din_last_reg_n, sys_clk_cnt_max)
begin

case present_state is

when idle =>
master_ready <= '1';
chip_select_n <= '1';
chip_select_n <= not din_last_reg_n;
spi_clk_en <= '0';
first_edge_en <= '0';
second_edge_en <= '0';
Expand All @@ -298,16 +327,16 @@ begin
rx_data_vld <= '0';

when transmit_end =>
master_ready <= '1';
master_ready <= '0';
chip_select_n <= '0';
spi_clk_en <= '0';
first_edge_en <= '0';
second_edge_en <= '0';
rx_data_vld <= '1';
rx_data_vld <= sys_clk_cnt_max;

when disable_cs =>
when transmit_gap =>
master_ready <= '0';
chip_select_n <= '0';
chip_select_n <= not din_last_reg_n;
spi_clk_en <= '0';
first_edge_en <= '0';
second_edge_en <= '0';
Expand All @@ -320,7 +349,6 @@ begin
first_edge_en <= '0';
second_edge_en <= '0';
rx_data_vld <= '0';

end case;
end process;

Expand Down
10 changes: 8 additions & 2 deletions sim/spi_tb.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ architecture SIM of SPI_TB is

signal m_addr : std_logic_vector(integer(ceil(log2(real(SLAVE_COUNT))))-1 downto 0);
signal m_din : std_logic_vector(7 downto 0);
signal m_din_last : std_logic;
signal m_din_vld : std_logic;
signal m_ready : std_logic;
signal m_dout : std_logic_vector(7 downto 0);
Expand Down Expand Up @@ -77,9 +78,10 @@ begin
MISO => miso,
-- USER INTERFACE
ADDR => m_addr,
READY => m_ready,
DIN => m_din,
DIN_LAST => m_din_last,
DIN_VLD => m_din_vld,
READY => m_ready,
DOUT => m_dout,
DOUT_VLD => m_dout_vld
);
Expand All @@ -94,9 +96,9 @@ begin
MOSI => mosi,
MISO => miso,
-- USER INTERFACE
READY => s_ready,
DIN => s_din,
DIN_VLD => s_din_vld,
READY => s_ready,
DOUT => s_dout,
DOUT_VLD => s_dout_vld
);
Expand All @@ -122,13 +124,15 @@ begin
m_addr <= (others => '0');
m_din <= (others => 'Z');
m_din_vld <= '0';
m_din_last <= '0';

wait until RST = '0';
wait for 30 ns;
wait until rising_edge(CLK);

m_din <= X"12";
m_din_vld <= '1';
m_din_last <= '0';
wait until m_ready = '0';

m_din <= (others => '0');
Expand All @@ -140,10 +144,12 @@ begin

m_din <= X"F4";
m_din_vld <= '1';
m_din_last <= '1';
wait until m_ready = '0';

m_din <= X"47";
m_din_vld <= '1';
m_din_last <= '1';
wait until m_ready = '0';

m_din <= (others => '0');
Expand Down

0 comments on commit 75245d6

Please sign in to comment.