I learned VHDL 5 years back, and never used after that as I was working on different domain. Now I'm working in a project that required some work in VHDL. I have to implement SPI to program a ADF4158 device. I opened a book for syntax and tried to program. I need to develop the below module, I coded as per my understanding and also a test bench but it doesnot work in the simulation like I need. Below is the module I want to develop and the over all block diagram.
Block diagram of process and vhdl module (clickable):
The following is the SPI timing diagram as follows (clickable):
The below is the VHDL code I wrote to acheive the above SPI communication:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.all;
entity sender is
Generic( DATA_WIDTH : INTEGER := 32); --32 bit registers to pogram (total 8 registers to program)
Port ( sys_clk : in STD_LOGIC; --clock from microblaze (32 MHz)
enable : in STD_LOGIC; --from microblaze to trigger start
reset : in STD_LOGIC; --reset spi clk generation
start_data_read : out STD_LOGIC; --to microblaze as flag so that microblaze starts sending register_select codes (pgogram data for target register) and the data to pogram - to buffer
start_data_write : out STD_LOGIC; --to microblaze as flag so that microblaze starts sending register_select codes (pgogram data for target register) and the data to pogram - to mosi port
data_in : in STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --program data (32bit data in 8 phases depending on register_select)
process_done : out STD_LOGIC; --flag bit to microblaze when complete process is complete
register_select : in STD_LOGIC_VECTOR(2 downto 0); --select code to identify which register to grogram, theorder can be manupulated from microblaze
sclk : buffer STD_LOGIC; --spi clock for ADC (3.2 MHz)
ss : out STD_LOGIC := '1'; --select line for ADF (slave)
mosi : out STD_LOGIC); --program data for ADF
end sender;
architecture Behavioral of sender is
type machine is(store, sending); --states of state-machine
signal state : machine := store;
signal clk_divide: STD_LOGIC_VECTOR(5 downto 0); --clock cycle ratio between system clock from microblaze and spi clock for ADF
signal tx_buffer_0 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 0)
signal tx_buffer_1 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 1)
signal tx_buffer_2 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 2)
signal tx_buffer_3 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 3)
signal tx_buffer_4 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 4)
signal tx_buffer_5 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 5)
signal tx_buffer_6 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 6)
signal tx_buffer_7 : STD_LOGIC_VECTOR(DATA_WIDTH-1 DOWNTO 0); --IO Buffer to hold program data to mosi (register 7)
begin
ClK_GEN: process(sys_clk)
begin --spi sclk 20:1 cycles of sys_clk(system runs at 32 MHz and SPI CLK required is 1.6 MHz)
if rising_edge(sys_clk) then
if reset = '1' then
clk_divide <= (others => '0');
mosi <= 'Z'; --send high impedence
else
if clk_divide < "001010" then --10
sclk <= '0';
clk_divide <= clk_divide + 1;
else
if clk_divide < "010100" then --20
sclk <= '1';
else
clk_divide <= (others => '0');
end if;
end if;
end if;
end if;
end process ClK_GEN;
SEND: process(sclk,enable,register_select)
begin
if rising_edge(sclk) then
if enable = '1' then
case state is
when store =>
start_data_read <= '1'; --ask microblaze to send register_selectcodes and data
case register_select is
when "000" =>
tx_buffer_7 <= data_in; --copy data to buffer
when "001" =>
tx_buffer_6 <= data_in;
when "010" =>
tx_buffer_5 <= data_in;
when "011" =>
tx_buffer_4 <= data_in;
when "100" =>
tx_buffer_3 <= data_in;
when "101" =>
tx_buffer_2 <= data_in;
when "110" =>
tx_buffer_1 <= data_in;
when "111" =>
tx_buffer_0 <= data_in;
when others =>
tx_buffer_1 <= (OTHERS => '0');
end case;
state <= sending; --change state to next
when sending =>
start_data_write <= '1'; --ask microblaze to send register_select codes to pgrogram a register
case register_select is
when "000" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_7 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "001" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_6 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "010" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
ss <= '1';
when "011" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_4 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "100" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_3 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "101" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_2 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "110" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_1 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when "111" =>
ss <= '0';
mosi <= tx_buffer_7(DATA_WIDTH-1);
tx_buffer_0 <= tx_buffer_7(DATA_WIDTH-2 downto 0) & '0';
ss <= '1';
when others =>
mosi <= '0';
end case;
end case;
end if;
end if;
end process SEND;
end Behavioral;
I also wrote a test bench code to send the above module, belowis the code:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY test_sender IS
END test_sender;
ARCHITECTURE behavior OF test_sender IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT sender
PORT(
sys_clk : IN std_logic;
enable : IN std_logic;
reset : IN std_logic;
start_data_read : OUT std_logic;
start_data_write : OUT std_logic;
data_in : IN std_logic_vector(31 downto 0);
process_done : OUT std_logic;
register_select : IN std_logic_vector(2 downto 0);
sclk : buffer std_logic;
ss : OUT std_logic;
mosi : OUT std_logic
);
END COMPONENT;
--Inputs
signal sys_clk : std_logic := '0';
signal enable : std_logic := '0';
signal reset : std_logic := '0';
signal data_in : std_logic_vector(31 downto 0) := (others => '0');
signal register_select : std_logic_vector(2 downto 0) := (others => '0');
--Outputs
signal start_data_read : std_logic;
signal start_data_write : std_logic;
signal process_done : std_logic;
signal sclk : std_logic;
signal ss : std_logic;
signal mosi : std_logic;
-- Clock period definitions
constant clk_sys_period : time := 31.25 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: sender PORT MAP (
sys_clk => sys_clk,
enable => enable,
reset => reset,
start_data_read => start_data_read,
start_data_write => start_data_write,
data_in => data_in,
process_done => process_done,
register_select => register_select,
sclk => sclk,
ss => ss,
mosi => mosi
);
-- Clock process definitions
clk_sys_process :process
begin
sys_clk <= '0';
wait for clk_sys_period/2;
sys_clk <= '1';
wait for clk_sys_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 1ns;
enable <= '1';
if start_data_read = '1' then
wait for 1ns;
register_select <= "000";
wait for 1 ns;
data_in <= "01001111001101010101010111100001";
wait for 5 ns;
register_select <= "001";
wait for 1 ns;
data_in <= "11001111001101010111011111100101";
wait for 5 ns;
register_select <= "010";
wait for 1 ns;
data_in <= "00000011001101010101011101100101";
wait for 5 ns;
register_select <= "011";
wait for 1 ns;
data_in <= "00011111001101010101010011100101";
wait for 5 ns;
register_select <= "100";
wait for 1 ns;
data_in <= "10001111001101010101011111100001";
wait for 5 ns;
register_select <= "101";
wait for 1 ns;
data_in <= "11001111001101010101011110000101";
wait for 5 ns;
register_select <= "110";
wait for 1 ns;
data_in <= "00101000001101010101011111100101";
wait for 5 ns;
register_select <= "111";
wait for 1 ns;
data_in <= "11111111001101010101011110100101";
wait for 5 ns;
end if;
if start_data_write = '1' then
wait for 1ns;
register_select <= "000";
wait for 5 ns;
register_select <= "001";
wait for 5 ns;
register_select <= "010";
wait for 5 ns;
register_select <= "011";
wait for 5 ns;
register_select <= "100";
wait for 5 ns;
register_select <= "101";
wait for 5 ns;
register_select <= "110";
wait for 5 ns;
register_select <= "111";
wait for 5 ns;
end if;
-- insert stimulus here
wait;
end process;
END;
The simulation is not working properly, and so the code is wrong, but I can't find out where is the mistake, it would be great if some one can help me and make me understand my mistake.