1) Design requirement:
This lab is to test your understanding of
Serial Port Interface (SPI). Your design
shall accept a 50 megahertz clock signal, an asynchronous active low reset signal,
an asynchronous 1-bit Load signal, an asynchronous 2-bit slave selection signal , an asynchronous 5-bit data signal. Your design shall have a master
SPI controller which will accept the signals describe above and shall
communicate with 3 slaves over a 3 wire SPI bus. Each slave shall drive 5 LEDs
correspond to the 5-bit data received from the master as described in the table
below.
slave selection [1:0]
|
Load
|
Definition
|
01
|
Rising edge
|
The master shall capture the data and send it to
slave #1 and slave # 1 shall drive the LEDs with the data
|
10
|
Rising edge
|
The master shall capture the data and send it to
slave #2 and slave # 2 shall drive the LEDs with the data
|
11
|
Rising edge
|
The master shall capture the data and send it to
slave #3 and slave # 3 shall drive the LEDs with the data
|
SPI
Timing Diagram
2) VHDL code:
library ieee;
use ieee.std_logic_1164.all;
--spi master
entity spi_m is
port (
clk : in std_logic;
rst_n : in std_logic;
load : in std_logic;
slv_sel : in std_logic_vector(1 downto 0);
din : in std_logic_vector(4 downto 0);
sclk : out std_logic;
cs_n : out std_logic_vector(2 downto 0);
sdio : inout std_logic
);
end entity spi_m;
--begin of architecture
architecture behavioral of spi_m is
type spi_status is (IDLE, LOADDATA, SENDDATA, DONE);
signal clk_en : std_logic ;
signal load_ff1 : std_logic ;
signal load_ff2 : std_logic ;
signal load_ff3 : std_logic ;
signal load_trig : std_logic ;
signal slv_sel_ff1 : std_logic_vector(1 downto 0) ;
signal slv_sel_ff2 : std_logic_vector(1 downto 0) ;
signal spi_stat : spi_status ;
signal spi_stat_nxt : spi_status ;
signal data : std_logic_vector(4 downto 0) ;
signal index : integer range 0 to 10 ;
signal sdi : std_logic ;
signal sdo_en : std_logic ;
begin
--generate sclk
sclk <= clk when clk_en = '1' else '0';
--generate sdio
sdio <= data(4) when sdo_en = '1' else 'Z';
--get sdi
sdi <= sdio;
--solve the metastability of async input
process(clk, rst_n)
begin
if(rst_n = '0') then
load_ff1 <= '0';
load_ff2 <= '0';
load_ff3 <= '0';
slv_sel_ff1 <= "00";
slv_sel_ff2 <= "00";
elsif(rising_edge(clk)) then
load_ff1 <= load;
load_ff2 <= load_ff1;
load_ff3 <= load_ff2;
slv_sel_ff1 <= slv_sel;
slv_sel_ff2 <= slv_sel_ff1;
end if;
end process;
--get the change of load
load_trig <= load_ff2 and (not load_ff3);
--generate cs_n
process(clk, rst_n)
begin
if(rst_n = '0') then
cs_n <= "111";
elsif(rising_edge(clk)) then
if(spi_stat = IDLE) then
case slv_sel_ff2 is
when "01" =>
cs_n <= "110";
when "10" =>
cs_n <= "101";
when "11" =>
cs_n <= "011";
when others =>
cs_n <= "111";
end case;
end if;
end if;
end process;
--generate clk_en
process(clk, rst_n)
begin
if(rst_n = '0') then
clk_en <= '0';
elsif(falling_edge(clk)) then
if((spi_stat = SENDDATA) or (spi_stat = DONE)) then
clk_en <= '1';
else
clk_en <= '0';
end if;
end if;
end process;
--generate data
process(clk, rst_n)
begin
if(rst_n = '0') then
data <= (others => '0');
elsif(rising_edge(clk)) then
if(spi_stat = LOADDATA) then
data <= din;
elsif(spi_stat = SENDDATA) then
data <= data(3 downto 0) & '0';
end if;
end if;
end process;
--count index
process(clk, rst_n)
begin
if(rst_n = '0') then
index <= 0;
elsif(rising_edge(clk)) then
if(spi_stat = SENDDATA) then
index <= index + 1;
else
index <= 0;
end if;
end if;
end process;
--generate sdo_en
process(clk, rst_n)
begin
if(rst_n = '0') then
sdo_en <= '0';
elsif(rising_edge(clk)) then
if((spi_stat = LOADDATA) or (spi_stat = SENDDATA)) then
sdo_en <= '1';
else
sdo_en <= '0';
end if;
end if;
end process;
--spi master state machine
process(spi_stat, load_trig, index)
begin
case spi_stat is
when IDLE =>
if(load_trig = '1') then
spi_stat_nxt <= LOADDATA;
else
spi_stat_nxt <= IDLE;
end if;
when LOADDATA =>
spi_stat_nxt <= SENDDATA;
when SENDDATA =>
if(index <= 2) then
spi_stat_nxt <= SENDDATA;
else
spi_stat_nxt <= DONE;
end if;
when DONE =>
spi_stat_nxt <= IDLE;
when others =>
spi_stat_nxt <= IDLE;
end case;
end process;
--flip-flop spi_stat
process(clk, rst_n)
begin
if(rst_n = '0') then
spi_stat <= IDLE;
elsif(rising_edge(clk)) then
spi_stat <= spi_stat_nxt;
end if;
end process;
--end of architecture
end behavioral;
library ieee;
use ieee.std_logic_1164.all;
--spi slave
entity spi_s is
port (
sclk : in std_logic;
rst_n : in std_logic;
cs_n : in std_logic;
sdio : inout std_logic;
led : out std_logic_vector(4 downto 0)
);
end entity spi_s;
--begin of architecture
architecture behavioral of spi_s is
signal sdi : std_logic;
signal sdo : std_logic;
signal sdo_en : std_logic;
signal data : std_logic_vector(4 downto 0);
begin
sdi <= sdio;
sdio <= sdo when sdo_en = '1' else 'Z';
sdo_en <= '0';
sdo <= '0';
process(sclk, rst_n)
begin
if(rst_n = '0') then
data <= "00000";
elsif(rising_edge(sclk)) then
if(cs_n = '0') then
data <= data(3 downto 0) & sdi;
end if;
end if;
end process;
led <= data;
--end of architecture
end behavioral;
library ieee;
use ieee.std_logic_1164.all;
entity top is
port (
clk : in std_logic;
rst_n : in std_logic;
load : in std_logic;
slv_sel : in std_logic_vector(1 downto 0);
din : in std_logic_vector(4 downto 0);
led0 : out std_logic_vector(4 downto 0);
led1 : out std_logic_vector(4 downto 0);
led2 : out std_logic_vector(4 downto 0)
);
end entity top;
architecture behavioral of top is
component spi_m is
port (
clk : in std_logic;
rst_n : in std_logic;
load : in std_logic;
slv_sel : in std_logic_vector(1 downto 0);
din : in std_logic_vector(4 downto 0);
sclk : out std_logic;
cs_n : out std_logic_vector(2 downto 0);
sdio : inout std_logic
);
end component;
component spi_s is
port (
sclk : in std_logic;
rst_n : in std_logic;
cs_n : in std_logic;
sdio : inout std_logic;
led : out std_logic_vector(4 downto 0)
);
end component;
signal sclk: std_logic;
signal cs_n: std_logic_vector(2 downto 0);
signal sdio: std_logic;
begin
u_spi_m: spi_m port map (
clk => clk ,
rst_n => rst_n ,
load => load ,
slv_sel => slv_sel ,
din => din ,
sclk => sclk ,
cs_n => cs_n ,
sdio => sdio
);
u_spi0: spi_s port map (
sclk => sclk,
rst_n => rst_n,
cs_n => cs_n(0),
sdio => sdio,
led => led0
);
u_spi1: spi_s port map (
sclk => sclk,
rst_n => rst_n,
cs_n => cs_n(1),
sdio => sdio,
led => led1
);
u_spi2: spi_s port map (
sclk => sclk,
rst_n => rst_n,
cs_n => cs_n(2),
sdio => sdio,
led => led2
);
end behavioral;
No comments:
Post a Comment