mrbigglio
Newbie
- Joined
- Jul 23, 2014
- Messages
- 5
- Helped
- 0
- Reputation
- 0
- Reaction score
- 0
- Trophy points
- 1,281
- Activity points
- 1,340
Hello everybody,
I am trying to design a SPI Master Module, I used a existing one in our folders at work. The SPI Module clock is 12.5 MHz (for a 25 MHz external clock). We want now a 1 MHz clock for the SPI Module. I changed the existing clock, put a counter to generate my 1MHz clock but the design doesnt work anymore. No errors detected during my compilation but i didnt find the good values in my data registers. The SPI module only works at 12.5 MHz, it's strange. I Can't put all the code here but i think the problem is somewhere
Does anyone please see sthg not right in those lines ?
This is my testbench :
In my testbench, I just put spi_miso at 1 and expecting to see my 12-bit data register at 111111111111. There is sthg wrong i guess.
Thank you for your help and excuse my english.
I am trying to design a SPI Master Module, I used a existing one in our folders at work. The SPI Module clock is 12.5 MHz (for a 25 MHz external clock). We want now a 1 MHz clock for the SPI Module. I changed the existing clock, put a counter to generate my 1MHz clock but the design doesnt work anymore. No errors detected during my compilation but i didnt find the good values in my data registers. The SPI module only works at 12.5 MHz, it's strange. I Can't put all the code here but i think the problem is somewhere
Code:
----------------------------------------------------------------------------
-- File : spi.vhd
--
-- Description : SPI Master for the HK ADC.
----------------------------------------------------------------------------
-- $Id$
----------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.tnr_hfr_pkg.all;
entity spi is
port(
-- M25
clk : in std_logic;
rst_n : in std_logic;
-- Control interface
ctrl_go : in std_logic; -- Sampling start pulse.
ctrl_avg : in std_logic_vector(1 downto 0); -- Select number of averages
ctrl_addr : in std_logic_vector(1 downto 0); -- HK registers address
ctrl_dat : out std_logic_vector(31 downto 0); -- data output
ctrl_eosmp : out std_logic; -- End of sampling
-- SPI interface
spi_cs_n : out std_logic; -- HK ADC chip select
spi_sclk : out std_logic; -- SPI clock
spi_mosi : out std_logic; -- SPI master out slave in
spi_miso : in std_logic -- SPI master in slave out
);
end entity spi;
architecture rtl of spi is
--====== Types and constants ===========================================
-- FSM state type
type StateType is (
IDLE_S, -- Idle/Reset state
INIT_S, -- First conversion sequence
SAMPLE_S, -- HK Sampling
LAST_S -- last HK sample
);
-- HK registers type for the 8 sampling channels of the HK ADC (IN0 to IN7)
type HKregs is array (0 to 7) of std_logic_vector(15 downto 0);
--====== Signals =======================================================
--.......... Internal registers ........................................
-- Output register aliases
alias mosi_r : std_logic is spi_mosi;
alias eosmp_r : std_logic is ctrl_eosmp;
-- Internal registers
signal state_r : StateType; -- Current state
signal spi_clk_r : std_logic; -- SPI clock
signal spi_clk_cnt : integer; -- SPI clock counter to generate a 1 MHz clock
signal spi_cs_r : std_logic; -- SPI chip select
signal average_r : unsigned(3 downto 0);
-- Average number of sampling register
signal input_r : unsigned(2 downto 0); -- Input selection register for the 8 ADC channels
signal count_r : unsigned(3 downto 0); -- SPI data frame counter
signal din_r : unsigned(11 downto 0); -- sampled data
signal ctrl_dat_r : HKregs; -- accumulated sampled datas
-------- Combinatorial -------------------------------------------------
-- FSM signals
signal next_state : StateType; -- next state
signal clk_on : std_logic; -- SPI clock enable
signal init : std_logic; -- Sampling initialization
signal avg_step : std_logic; -- Average step command
signal cnt_step : std_logic; -- Counter step command
signal input_step : std_logic; -- Input step command
signal data_ok : std_logic; -- Data valid
signal eosmp : std_logic; -- End of sampling
begin
--======== Processes ===================================================
-- SPI clock generation
pspiclk : process(clk, rst_n)
begin
if rst_n = '0' then
spi_clk_r <= '1';
spi_clk_cnt <= 0;
elsif rising_edge(clk) then
if clk_on = '1' then -- SPI clock enabled
if spi_clk_cnt > 12 then
spi_clk_r <= not (spi_clk_r);
spi_clk_cnt <= 0 ;
else
spi_clk_cnt <= spi_clk_cnt + 1;
end if;
end if;
end process pspiclk;
-- Registers process.
pregs : process(clk, rst_n)
-- Evaluate scaling counter mask (hence clock division)
-- from band setting
function scaleAverage (avg_sel : std_logic_vector) return unsigned is
variable result : unsigned(2 downto 0);
begin
case to_integer(unsigned(avg_sel)) is
when AVG_8 => result := "111"; -- 7
when AVG_4 => result := "011"; -- 3
when AVG_2 => result := "001"; -- 1
when others => -- including AVG_1
result := "000"; -- 0
end case;
return result;
end function scaleAverage;
begin
if rst_n = '0' then
state_r <= IDLE_S;
average_r <= (others => '0');
spi_cs_r <= '0'; -- the HK ADC is not selected
ctrl_dat_r <= (others => (others => '0'));
input_r <= (others => '0');
mosi_r <= '1'; -- no channel selection
count_r <= (others => '1');
eosmp_r <= '0';
din_r <= (others => '0');
elsif rising_edge(clk) then
-- Simple assignments/defaults
state_r <= next_state;
eosmp_r <= '0'; -- not at the end of sampling
-- Initialization of the registers with the sampling parameters
if init = '1' then
average_r <= scaleAverage(ctrl_avg);
spi_cs_r <= '1';
input_r <= (others => '1');
count_r <= (others => '1');
din_r <= (others => '0');
ctrl_dat_r <= (others => (others => '0'));
end if;
-- End of the sampling
if eosmp = '1' then
eosmp_r <= '1';
spi_cs_r <= '0';
end if;
------ various counters management ------
-- All 8 channels sampling has been done: decrement average down counter
if spi_clk_r = '1' and avg_step = '1' then
average_r <= average_r - 1;
ctrl_dat_r(to_integer(input_r+1))
<= std_logic_vector(unsigned(ctrl_dat_r(to_integer(input_r+1))) + din_r);
input_r <= (others => '1');
count_r <= (others => '1');
-- Sampling sequence completed for 1 of the 8 channels
elsif spi_clk_r = '1' and input_step = '1' then
input_r <= input_r - 1;
ctrl_dat_r(to_integer(input_r+1))
<= std_logic_vector(unsigned(ctrl_dat_r(to_integer(input_r+1))) + din_r);
count_r <= (others => '1');
-- Sampling sequence processing
elsif spi_clk_r = '1' and cnt_step = '1' then
count_r <= count_r - 1;
end if;
-------- sampling sequence -------------
if cnt_step = '1' then
-------- MOSI control ------------------
if spi_clk_r = '1' then -- falling edge of SCLK
case to_integer(count_r) is
when 12 to 14 => -- select the input channel
mosi_r <= std_logic(input_r(to_integer(count_r)-12));
when others =>
mosi_r <= '1'; -- no channel selection
end case;
-------- MISO control ------------------
else -- rising edge of SCLK
case to_integer(count_r) is
when 0 to 11 => -- get the data sample
if data_ok = '1' then -- genuine data
din_r(to_integer(count_r)) <= spi_miso;
end if;
when others =>
null;
end case;
end if;
end if;
end if;
end process pregs;
-- Finite state machine process.
pfsm : process (state_r, ctrl_go, count_r, average_r, input_r, spi_clk_r)
begin
-- Defaults
init <= '0'; -- no sampling initialization
avg_step <= '0'; -- not an average step
cnt_step <= '0'; -- not a counter step
input_step <= '0'; -- not an input step
data_ok <= '0'; -- no data valid
clk_on <= '1'; -- clock enabled
eosmp <= '0'; -- no end of sampling
next_state <= state_r; -- state unchanged
case state_r is
------------------------------------------------------------------
when IDLE_S => -- Idle/Reset state
if ctrl_go = '1' then
init <= '1';
next_state <= INIT_S;
else
clk_on <= '0'; -- SPI clock disabled
end if;
------------------------------------------------------------------
when INIT_S => -- First conversion sequence
cnt_step <= '1';
if count_r = "0000" and spi_clk_r = '1' then
-- First "blank" conversion done : proceed with the sampling
input_step <= '1';
next_state <= SAMPLE_S;
end if;
------------------------------------------------------------------
when SAMPLE_S => -- HK Sampling after first conversion sequence
data_ok <= '1';
cnt_step <= '1'; -- keep advancing in the sampling sequence
if count_r = "0000" and spi_clk_r = '1' then -- Sequence completed
input_step <= '1'; -- sample the next channel
if input_r = "0000" then -- All 8 channels have been sampled
if average_r = "00" then -- last HK sample to be done
next_state <= LAST_S;
else
avg_step <= '1'; -- Sampling of all 8 channels done
-- decrement the average counter
end if;
end if;
end if;
when LAST_S => -- last HK Sample processing
data_ok <= '1';
cnt_step <= '1';
if count_r = "0000" and spi_clk_r = '1' then
input_step <= '1';
next_state <= IDLE_S;
eosmp <= '1';
end if;
end case;
end process pfsm;
-- Registers bank output process.
pregso: process (ctrl_dat_r, ctrl_addr)
begin
ctrl_dat <= (others => '0');
case ctrl_addr is
--................................................................
when HK1_OFF => --IN0 & IN1
ctrl_dat(31 downto 16) <= ctrl_dat_r(0);
ctrl_dat(15 downto 0) <= ctrl_dat_r(1);
--................................................................
when HK2_OFF => --IN2 & IN3
ctrl_dat(31 downto 16) <= ctrl_dat_r(2);
ctrl_dat(15 downto 0) <= ctrl_dat_r(3);
--................................................................
when HK3_OFF => --IN4 & IN5
ctrl_dat(31 downto 16) <= ctrl_dat_r(4);
ctrl_dat(15 downto 0) <= ctrl_dat_r(5);
--................................................................
when HK4_OFF => --IN6 & IN7
ctrl_dat(31 downto 16) <= ctrl_dat_r(6);
ctrl_dat(15 downto 0) <= ctrl_dat_r(7);
--................................................................
when others => null;
end case;
end process pregso;
-- Outputs assignement
spi_sclk <= spi_clk_r;
spi_cs_n <= '0' when spi_cs_r = '1' else '1';
end architecture rtl;
Does anyone please see sthg not right in those lines ?
This is my testbench :
Code:
library ieee;
use ieee.std_logic_1164.all;
entity tb_spi is
end entity tb_spi;
architecture tb of tb_spi is
constant PERIOD : time := 40 ns; -- 25MHz
signal rst_n : std_logic;
signal clk : std_logic;
signal tick : integer := 0;
-- Control interface
signal ctrl_go : std_logic;
signal ctrl_avg : std_logic_vector(1 downto 0);
signal ctrl_addr : std_logic_vector(1 downto 0);
signal ctrl_dat : std_logic_vector(31 downto 0);
signal ctrl_eosmp : std_logic;
-- SPI interface
signal spi_cs_n : std_logic;
signal spi_sclk : std_logic;
signal spi_mosi : std_logic;
signal spi_miso : std_logic;
begin
spi0 : entity work.spi
port map(
rst_n => rst_n,
clk => clk,
-- Control interface
ctrl_go => ctrl_go,
ctrl_avg => ctrl_avg,
ctrl_addr => ctrl_addr,
ctrl_dat => ctrl_dat,
ctrl_eosmp => ctrl_eosmp,
-- SPI interface
spi_cs_n => spi_cs_n,
spi_sclk => spi_sclk,
spi_mosi => spi_mosi,
spi_miso => spi_miso
);
pclk : process
begin
clk <= '1';
wait for PERIOD/2;
clk <= '0';
wait for PERIOD/2;
tick <= tick + 1;
end process;
rst_n <= '1' when tick > 19 else '0';
pmain : process
procedure W (t : integer) is
begin
wait for PERIOD * t;
end procedure;
procedure write(data : std_logic_vector(11 downto 0)) is
begin
W(8);
wrloop : for i in 0 to 11 loop
spi_miso <= data(11-i);
W(2);
end loop;
spi_miso <= '0';
end procedure;
begin
ctrl_go <= '0';
ctrl_avg <= "00";
ctrl_addr <= "00";
spi_miso <= '0';
wait until rst_n = '1';
W(4);
ctrl_go <= '1';
W(1);
ctrl_go <= '0';
spi_miso <= '1';
ctrl_addr <= "01";
W(1);
ctrl_addr <= "10";
W(1);
ctrl_addr <= "11";
wait;
end process;
end architecture;
In my testbench, I just put spi_miso at 1 and expecting to see my 12-bit data register at 111111111111. There is sthg wrong i guess.
Thank you for your help and excuse my english.