Saturday, February 22, 2014

VHDL code for serial interface

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