Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Problem with the design of a SPI Master in VHDL

Status
Not open for further replies.

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


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.
 

I cannot simulate the design as you have left out the tnr_hfr_pkg.

I did notice though that your input data spi_miso will be set 1 delta before the clock changes, so in your code it may appear that the register doesnt exist. This is because you have put an absolute time delay in the input process, rather than making it relative to the clock.
 

Thank you TrickyDicky for your help, i removed the line spi_miso <= '1' and put it just after the 'wait until rst_n = 1 and the problem still exists. it is strange because the same testbench has worked for a 12.5 MHz SPI Clock.
Are you saying that instead of putting a time delay in my testbench, it would be better to wait a clk'event for example ?
I can upload the tnr_hfr_pkg if you want.
Thank again!
 
Last edited:

because the wait procedure uses the same time delay as the clock, it would be safer to wait for N * rising_edge(clk) or falling edge(clk). Using specified time delays that are the same as the clock period can cause apparently odd simulation behaviour.

If you want me to simulate the testbench and have a quick look, then yes, I need the package.
 

Here is the package.
Code:
----------------------------------------------------------------------------
--  This file is part of the TNR-HFR FPGA project VHDL library.
----------------------------------------------------------------------------

--  Description : package of common public definitions.

----------------------------------------------------------------------------
--  $Id$
----------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;

library techmap;
use techmap.gencomp.all;

-- This package contains public definitions:
--  - AMBA-related definitions.
--  - Memory maps.
--  - Other mappings.
--  - Registers/fields values symbolic constants.
--  - etc.

package tnr_hfr_pkg is

    -- Keep some signal names for synthesis
    attribute syn_keep  : boolean;

    -- Synthetizer cut path: internal/external control link type
    type SynthCutPathType is record
        ctrl_on     : std_logic;    -- on/off switch
        ctrl_upd    : std_logic;    -- frequency update pulse
        ctrl_div    : std_logic_vector(9 downto 0);
                                    -- frequency division
    end record SynthCutPathType;

    --======== Leon3 configuration =========================================
    constant CFG_TECH           : integer   :=  apa3e;
    constant CFG_NWIN           : integer   :=  (8);
    constant CFG_FPU            : integer   :=  0 + 16*0 + 32*0;
    constant CFG_V8             : integer   :=  1;
    constant CFG_CP             : integer   :=  0;
    constant CFG_MAC            : integer   :=  1;
    constant CFG_PCLOW          : integer   :=  2;
    constant CFG_NOTAG          : integer   :=  0;
    constant CFG_NWP            : integer   :=  (2);
    constant CFG_ICEN           : integer   :=  1;
    constant CFG_IREPL          : integer   :=  0;
    constant CFG_ISETS          : integer   :=  2;
    constant CFG_ILINE          : integer   :=  4;
    constant CFG_ISETSZ         : integer   :=  2;
    constant CFG_ILOCK          : integer   :=  0;
    constant CFG_DCEN           : integer   :=  1;
    constant CFG_DREPL          : integer   :=  0;
    constant CFG_DSETS          : integer   :=  2;
    constant CFG_DLINE          : integer   :=  4;
    constant CFG_DSETSZ         : integer   :=  1;
    constant CFG_DLOCK          : integer   :=  0;
    constant CFG_DSNOOP         : integer   :=  1 + 0 + 4*0;
    constant CFG_ILRAMEN        : integer   :=  0;
    constant CFG_ILRAMSZ        : integer   :=  1;
    constant CFG_ILRAMADDR      : integer   :=  16#8E#;
    constant CFG_DLRAMEN        : integer   :=  0;
    constant CFG_DLRAMSZ        : integer   :=  1;
    constant CFG_DLRAMADDR      : integer   :=  16#8F#;
    constant CFG_MMUEN          : integer   :=  0;
    constant CFG_ITLBNUM        : integer   :=  2;
    constant CFG_DTLBNUM        : integer   :=  2;
    constant CFG_TLB_TYPE       : integer   :=  1 + 0*2;
    constant CFG_TLB_REP        : integer   :=  1;
    constant CFG_LDDEL          : integer   :=  (1);
    constant CFG_ITBSZ          : integer   :=  0;
    constant CFG_PWD            : integer   :=  1*2;
    constant CFG_SVT            : integer   :=  1;
    constant CFG_RSTADDR        : integer   :=  16#00000#;
    constant CFG_NCPU           : integer   :=  (1);
    constant CFG_IUFT_EN        : integer   :=  2;
    constant CFG_FPUFT_EN       : integer   :=  0;
    constant CFG_CACHE_FT_EN    : integer   :=  1;
    constant CFG_RF_ERRINJ      : integer   :=  0;
    constant CFG_CACHE_ERRINJ   : integer   :=  (0);
    constant CFG_DFIXED         : integer   :=  16#0#;
    constant CFG_LEON3_NETLIST  : integer   :=  0;
    constant CFG_SCANTEST       : integer   :=  0;
    constant CFG_MMU_PAGE       : integer   :=  0;
    constant CFG_BP             : integer   :=  1;    
    
    --======== Memory Controller ===========================================

    constant OEPOL : integer := padoen_polarity(CFG_TECH);

    --======== Spacewire configuration =====================================
    
    constant SPW_TX_FREQ_KHZ: integer   :=  50000;
    
    --======== GPTimer configuration =======================================
    constant GPT_SEPIRQ        : integer   :=  1;
    constant GPT_SW            : integer   :=  16;
    constant GPT_NTIM          : integer   :=  4;
    constant GPT_TW            : integer   :=  32; 

    --======== AMBA-related definitions ====================================

    -- AHB actual master/slave agents counts
    constant AHB_MST_COUNT      : integer   :=  4;  -- masters count
    constant AHB_SLV_COUNT      : integer   :=  3;  -- slaves count

    -- APB internal/external/total slaves counts;
    -- "internal" agents are placed in the "core" module.
    constant APB_SLV_INT_COUNT  : integer   :=  6;  -- internal slaves count
    constant APB_SLV_EXT_COUNT  : integer   :=  2;  -- external slaves count

    constant APB_SLV_COUNT      : integer   :=  APB_SLV_INT_COUNT
                                            +   APB_SLV_EXT_COUNT;

    -- AHB device definitions ..............................................

    -- Prefix named after generic parameters:
    --      *_HINDEX    AHB device index.
    --      *_HMASK     AHB address mask.
    --      *_HADDR     AHB base address.

    -- AHB master indices; higher HINDEX means higher priority - but MADC
    -- block has been designed to release the bus with short delay if at
    -- least one other master is requesting the AHB bus
    constant MADC_HINDEX        : integer   :=  3;  -- MAC/ADC DMA block
    constant SPW_HINDEX         : integer   :=  2;  -- Spacewire
    constant UART_HINDEX        : integer   :=  1;  -- UART (as AHB master!)
    constant CPU_HINDEX         : integer   :=  0;  -- Leon3 CPU

    -- Fault-tolerant memory controller (as *AHB* slave: memory space)
    constant MEMC_HINDEX        : integer   :=  0;
    constant MEMC_HADDR         : integer   :=  16#000#;
    constant MEMC_HMASK         : integer   :=  16#FF0#;

    -- APB controller (AHB <-> APB bridge, as *AHB* slave)
    constant APBC_HINDEX        : integer   :=  1;
    constant APBC_HADDR         : integer   :=  16#800#;
    constant APBC_HMASK         : integer   :=  16#FFF#;

    -- Debug Support Unit (AHB slave)
    constant DSU_HINDEX         : integer   :=  2;
    constant DSU_HADDR          : integer   :=  16#900#;
    constant DSU_HMASK          : integer   :=  16#F00#;

    -- APB devices definitions (internal ones) .............................

    -- Prefix named after generic parameters:
    --      *_PINDEX    APB device index.
    --      *_PMASK     APB address mask.
    --      *_PADDR     APB base address.

    -- Fault-tolerant memory controller (as *APB* slave: config space)
    constant MEMC_PINDEX        : integer   :=  0;
    constant MEMC_PADDR         : integer   :=  16#000#;
    constant MEMC_PMASK         : integer   :=  16#FFF#;

    -- UART (as APB slave!)
    constant UART_PINDEX        : integer   :=  1;
    constant UART_PADDR         : integer   :=  16#004#;
    constant UART_PMASK         : integer   :=  16#FFF#;

    -- Interrupt controller
    constant IRQC_PINDEX        : integer   :=  2;
    constant IRQC_PADDR         : integer   :=  16#002#;
    constant IRQC_PMASK         : integer   :=  16#FFF#;
    
    -- Spacewire controller
    constant SPW_PINDEX         : integer   :=  3;
    constant SPW_PADDR          : integer   :=  16#00c#;
    constant SPW_PMASK          : integer   :=  16#FFF#;    
   
    -- GPTimer
    constant GPT_PINDEX         : integer   :=  4;
    constant GPT_PADDR          : integer   :=  16#005#;
    constant GPT_PMASK          : integer   :=  16#FFF#;
    
    -- AHBSTAT
    constant STAT_PINDEX        : integer   :=  5;
    constant STAT_PADDR         : integer   :=  16#006#;
    constant STAT_PMASK         : integer   :=  16#FFF#;
    
    -- APB devices definitions (external ones) .............................
    
    -- MAC/ADC controller
    constant MADC_PINDEX        : integer   :=  6;
    constant MADC_PADDR         : integer   :=  16#001#;
    constant MADC_PMASK         : integer   :=  16#FFF#;
    
    -- TNR-HFR peripherals (system registers)
    constant PERI_PINDEX        : integer   :=  7;
    constant PERI_PADDR         : integer   :=  16#003#;
    constant PERI_PMASK         : integer   :=  16#FFF#;
    

    --======== Memory mappings =============================================

    -- APB device memory map extent granularity
    constant APB_EXTENT     : integer   :=  256;

    -- APB devices offsets
    constant MEMC_OFF   : integer   :=  APB_EXTENT * MEMC_PADDR;
    constant UART_OFF   : integer   :=  APB_EXTENT * UART_PADDR;
    constant IRQC_OFF   : integer   :=  APB_EXTENT * IRQC_PADDR;
    constant SPW_OFF    : integer   :=  APB_EXTENT * SPW_PADDR;
    constant GPT_OFF    : integer   :=  APB_EXTENT * GPT_PADDR;
    constant STAT_OFF   : integer   :=  APB_EXTENT * STAT_PADDR;
    constant MADC_OFF   : integer   :=  APB_EXTENT * MADC_PADDR;
    constant PERI_OFF   : integer   :=  APB_EXTENT * PERI_PADDR;

    -- FT memory controller memory map .....................................

    -- ROM and I/O timings configuration
    constant MEMC_MCFG1_REGOFF  : integer   :=  16#00#;
    -- SRAM and SDRAM timings configuration
    constant MEMC_MCFG2_REGOFF  : integer   :=  16#04#;
    -- (not used)
    constant MEMC_MCFG3_REGOFF  : integer   :=  16#08#;
    
    -- MAC/ADC controller memory map .......................................

    -- Register offsets: *NOTE* that there are aliases, since some
    -- write-only registers share address with read-only registers.

    -- Sampling control register
    constant MADC_SAMPC_REGOFF      : integer   :=  16#00#;

    -- Coefficients control register
    constant MADC_COEFC_REGOFF      : integer   :=  16#08#;
    -- Coefficients data register
    constant MADC_COEFD_REGOFF      : integer   :=  16#0C#;

    -- DMA count and control
    constant MADC_DMACNT_REGOFF     : integer   :=  16#10#;
    -- DMA source address
    constant MADC_DMASRC_REGOFF     : integer   :=  16#14#;

    -- Channel 1: sampling configuration register
    constant MADC_SAMP1_REGOFF      : integer   :=  16#20#;
    -- Channel 1: dumping control register
    constant MADC_DUMP1_REGOFF      : integer   :=  16#24#;
    -- Channel 1: data register
    constant MADC_DATA1_REGOFF      : integer   :=  16#28#;

    -- Channel 2: sampling configuration register
    constant MADC_SAMP2_REGOFF      : integer   :=  16#30#;
    -- Channel 2: dumping control register
    constant MADC_DUMP2_REGOFF      : integer   :=  16#34#;
    -- Channel 2: data register
    constant MADC_DATA2_REGOFF      : integer   :=  16#38#;

    -- Channel 1 MAC: sums register, high bits
    constant MADC_MACS1HI_REGOFF    : integer   :=  16#40#;
    -- Channel 1 MAC: sums register, low bits
    constant MADC_MACS1LO_REGOFF    : integer   :=  16#44#;
    -- Channel 1 MAC: differences register, high bits
    constant MADC_MACD1HI_REGOFF    : integer   :=  16#48#;
    -- Channel 1 MAC: differences register, low bits
    constant MADC_MACD1LO_REGOFF    : integer   :=  16#4C#;
    -- Channel 2 MAC: sums register, high bits
    constant MADC_MACS2HI_REGOFF    : integer   :=  16#50#;
    -- Channel 2 MAC: sums register, low bits
    constant MADC_MACS2LO_REGOFF    : integer   :=  16#54#;
    -- Channel 2 MAC: differences register, high bits
    constant MADC_MACD2HI_REGOFF    : integer   :=  16#58#;
    -- Channel 2 MAC: differences register, low bits
    constant MADC_MACD2LO_REGOFF    : integer   :=  16#5C#;
    
    -- 64bits accumulator input register, high bits
    constant MADC_ACCINHI_REGOFF    : integer   :=  16#60#;
    -- 64bits accumulator input register, low bits
    constant MADC_ACCINLO_REGOFF    : integer   :=  16#64#;
    -- 96bits accumulator input register, high bits
    constant MADC_ACCOUTHI_REGOFF   : integer   :=  16#70#;
    -- 96bits accumulator input register, middle bits
    constant MADC_ACCOUTMD_REGOFF   : integer   :=  16#74#;
    -- 96bits accumulator input register, low bits
    constant MADC_ACCOUTLO_REGOFF   : integer   :=  16#78#;

    -- Device memory footprint
    constant MADC_EXTENT    : integer   :=  256;

    -- Spacewire controller memory map .....................................

    -- Control configuration
    constant SPW_CONTROL_REGOFF       : integer   :=  16#00#;
    -- Status/Interrupt configuration
    constant SPW_STATINT_REGOFF       : integer   :=  16#04#;
    -- Node address configuration
    constant SPW_NODE_REGOFF          : integer   :=  16#08#;
    -- Clock divisor configuration
    constant SPW_CLKDIV_REGOFF        : integer   :=  16#0C#;
    -- Destination key configuration
    constant SPW_DESTKEY_REGOFF       : integer   :=  16#10#;
    -- TIME configuration
    constant SPW_TIME_REGOFF          : integer   :=  16#14#;
    -- DMA channel 1 control/status configuration
    constant SPW_DMA1CTRL_REGOFF      : integer   :=  16#20#;
    -- DMA channel 1 rx maximum length configuration
    constant SPW_DMA1RXLGTH_REGOFF    : integer   :=  16#24#;
    -- DMA channel 1 transmit descriptor table address configuration
    constant SPW_DMA1TXDESC_REGOFF    : integer   :=  16#28#;
    -- DMA channel 1 receive descriptor table address configuration
    constant SPW_DMA1RXDESC_REGOFF    : integer   :=  16#2C#;
    -- DMA channel 1 address register configuration
    constant SPW_DMA1ADDR_REGOFF      : integer   :=  16#30#;
    
    -- GPTimer memory map ...........................................
    
    -- Scaler value register
    constant GPT_SVAL_REGOFF          : integer   :=  16#00#;
    -- Scaler reload value register
    constant GPT_SRVAL_REGOFF         : integer   :=  16#04#;
    -- Configuration register
    constant GPT_CFG_REGOFF           : integer   :=  16#08#;
    -- Timer 1 counter value register
    constant GPT_T1VAL_REGOFF         : integer   :=  16#10#; 
    -- Timer 1 reload value register
    constant GPT_T1RVAL_REGOFF        : integer   :=  16#14#; 
    -- Timer 1 control register
    constant GPT_T1CTRL_REGOFF        : integer   :=  16#18#;
    -- Timer 2 counter value register
    constant GPT_T2VAL_REGOFF         : integer   :=  16#20#; 
    -- Timer 2 reload value register
    constant GPT_T2RVAL_REGOFF        : integer   :=  16#24#; 
    -- Timer 2 control register
    constant GPT_T2CTRL_REGOFF        : integer   :=  16#28#;
    -- Timer 3 counter value register
    constant GPT_T3VAL_REGOFF         : integer   :=  16#30#; 
    -- Timer 3 reload value register
    constant GPT_T3RVAL_REGOFF        : integer   :=  16#34#; 
    -- Timer 3 control register
    constant GPT_T3CTRL_REGOFF        : integer   :=  16#38#;
    -- Timer 4 counter value register
    constant GPT_T4VAL_REGOFF         : integer   :=  16#40#; 
    -- Timer 4 reload value register
    constant GPT_T4RVAL_REGOFF        : integer   :=  16#44#; 
    -- Timer 4 control register
    constant GPT_T4CTRL_REGOFF        : integer   :=  16#48#; 
    
    -- PERI registers memory map ..............................
    
    -- External control
    constant PERI_MISC_REGOFF     : integer   :=  16#00#;
    -- Synthetizer control
    constant PERI_SYNTH_REGOFF    : integer   :=  16#04#;
    -- HFR/LFa control
    constant PERI_HLF_REGOFF      : integer   :=  16#08#;
    -- TNR channels control
    constant PERI_TNR_REGOFF      : integer   :=  16#0C#;
    -- Calibration control
    constant PERI_CALIB_REGOFF    : integer   :=  16#10#;
    -- Freepins register
    constant PERI_SPRTEST_REGOFF  : integer   :=  16#14#;
    -- SPI control register
    constant PERI_SPIC_REGOFF     : integer   :=  16#18#;
    -- HK data register 1
    constant PERI_HK1_REGOFF      : integer   :=  16#20#;
    -- HK data register 2
    constant PERI_HK2_REGOFF      : integer   :=  16#24#;
    -- HK data register 3
    constant PERI_HK3_REGOFF      : integer   :=  16#28#;
    -- HK data register 4
    constant PERI_HK4_REGOFF      : integer   :=  16#2C#;
    

    -- memory map: register offsets ...................................

    -- MEMC registers offsets
    constant MCFG1_REGOFF       : integer   :=  MEMC_OFF + MEMC_MCFG1_REGOFF;
    constant MCFG2_REGOFF       : integer   :=  MEMC_OFF + MEMC_MCFG2_REGOFF;
    constant MCFG3_REGOFF       : integer   :=  MEMC_OFF + MEMC_MCFG3_REGOFF;
    
    -- PERI area: miscellaneous registers offsets.
    constant MISC_REGOFF        : integer   :=  PERI_OFF + PERI_MISC_REGOFF;
    constant SYNTH_REGOFF       : integer   :=  PERI_OFF + PERI_SYNTH_REGOFF;
    constant HLF_REGOFF         : integer   :=  PERI_OFF + PERI_HLF_REGOFF;
    constant TNR_REGOFF         : integer   :=  PERI_OFF + PERI_TNR_REGOFF;
    constant CALIB_REGOFF       : integer   :=  PERI_OFF + PERI_CALIB_REGOFF;
    constant SPRTEST_REGOFF     : integer   :=  PERI_OFF + PERI_SPRTEST_REGOFF;
    constant SPIC_REGOFF        : integer   :=  PERI_OFF + PERI_SPIC_REGOFF;
    constant HK1_REGOFF         : integer   :=  PERI_OFF + PERI_HK1_REGOFF;
    constant HK2_REGOFF         : integer   :=  PERI_OFF + PERI_HK2_REGOFF;
    constant HK3_REGOFF         : integer   :=  PERI_OFF + PERI_HK3_REGOFF;
    constant HK4_REGOFF         : integer   :=  PERI_OFF + PERI_HK4_REGOFF;
    
     -- MADC area: MAC/ADC controller offsets.
    constant SAMPC_REGOFF       : integer   :=  MADC_OFF + MADC_SAMPC_REGOFF;
    constant DMACNT_REGOFF      : integer   :=  MADC_OFF + MADC_DMACNT_REGOFF;
    constant DMASRC_REGOFF      : integer   :=  MADC_OFF + MADC_DMASRC_REGOFF;
    constant COEFC_REGOFF       : integer   :=  MADC_OFF + MADC_COEFC_REGOFF;
    constant COEFD_REGOFF       : integer   :=  MADC_OFF + MADC_COEFD_REGOFF;
    constant SAMP1_REGOFF       : integer   :=  MADC_OFF + MADC_SAMP1_REGOFF;
    constant DUMP1_REGOFF       : integer   :=  MADC_OFF + MADC_DUMP1_REGOFF;
    constant DATA1_REGOFF       : integer   :=  MADC_OFF + MADC_DATA1_REGOFF;
    constant SAMP2_REGOFF       : integer   :=  MADC_OFF + MADC_SAMP2_REGOFF;
    constant DUMP2_REGOFF       : integer   :=  MADC_OFF + MADC_DUMP2_REGOFF;
    constant DATA2_REGOFF       : integer   :=  MADC_OFF + MADC_DATA2_REGOFF;
    constant MACS1HI_REGOFF     : integer   :=  MADC_OFF + MADC_MACS1HI_REGOFF;
    constant MACS1LO_REGOFF     : integer   :=  MADC_OFF + MADC_MACS1LO_REGOFF;
    constant MACD1HI_REGOFF     : integer   :=  MADC_OFF + MADC_MACD1HI_REGOFF;
    constant MACD1LO_REGOFF     : integer   :=  MADC_OFF + MADC_MACD1LO_REGOFF;
    constant MACS2HI_REGOFF     : integer   :=  MADC_OFF + MADC_MACS2HI_REGOFF;
    constant MACS2LO_REGOFF     : integer   :=  MADC_OFF + MADC_MACS2LO_REGOFF;
    constant MACD2HI_REGOFF     : integer   :=  MADC_OFF + MADC_MACD2HI_REGOFF;
    constant MACD2LO_REGOFF     : integer   :=  MADC_OFF + MADC_MACD2LO_REGOFF;
    
    -- SPW registers offsets
    constant CONTROL_REGOFF     : integer   :=  SPW_OFF + SPW_CONTROL_REGOFF;
    constant STATINT_REGOFF     : integer   :=  SPW_OFF + SPW_STATINT_REGOFF;
    constant NODE_REGOFF        : integer   :=  SPW_OFF + SPW_NODE_REGOFF;
    constant CLKDIV_REGOFF      : integer   :=  SPW_OFF + SPW_CLKDIV_REGOFF;
    constant DESTKEY_REGOFF     : integer   :=  SPW_OFF + SPW_DESTKEY_REGOFF;
    constant TIME_REGOFF        : integer   :=  SPW_OFF + SPW_TIME_REGOFF;
    constant DMA1CTRL_REGOFF    : integer   :=  SPW_OFF + SPW_DMA1CTRL_REGOFF;
    constant DMA1RXLGTH_REGOFF  : integer   :=  SPW_OFF + SPW_DMA1RXLGTH_REGOFF;
    constant DMA1TXDESC_REGOFF  : integer   :=  SPW_OFF + SPW_DMA1TXDESC_REGOFF;
    constant DMA1RXDESC_REGOFF  : integer   :=  SPW_OFF + SPW_DMA1RXDESC_REGOFF;
    constant DMA1ADDR_REGOFF    : integer   :=  SPW_OFF + SPW_DMA1ADDR_REGOFF;

    -- Other mappings ......................................................

    -- Interrupts lines mapping
    constant STAT_IRQNUM        : integer   :=  1;    -- AHBSTAT
    constant SPI_IRQNUM         : integer   :=  5;    -- SPI
    constant GPT_IRQNUM         : integer   :=  6;    -- timer count end
    constant SAMP1_IRQNUM       : integer   :=  10;   -- ADC1 sampling end
    constant SAMP2_IRQNUM       : integer   :=  11;   -- ADC2 sampling end
    constant SPW_IRQNUM         : integer   :=  12;   -- SpaceWire
    constant DMA_IRQNUM         : integer   :=  13;   -- DMA last ack
    constant CBUF_IRQNUM        : integer   :=  14;   -- C-Buffer last ack

    --======== Device-specific definitions =================================

    -- Notation: "R.F"  designates field F of register R.

    -- CALIB register values
    --  CALIB_DIVn      divide 25 MHz clock by 'n'
    constant CALIB_DIV0         : integer   :=  0;
    constant CALIB_DIV1         : integer   :=  1;
    constant CALIB_DIV2         : integer   :=  2;
    constant CALIB_DIV4         : integer   :=  3;
    constant CALIB_DIV8         : integer   :=  4;
    constant CALIB_DIV32        : integer   :=  5;
    constant CALIB_DIV128       : integer   :=  6;
    constant CALIB_DIV512       : integer   :=  7;

    -- SAMPn.BAND field value / TNR.BANDn field values (n: 1|2)
    constant BAND_A             : integer   :=  0;
    constant BAND_B             : integer   :=  1;
    constant BAND_C             : integer   :=  2;
    constant BAND_D             : integer   :=  3;
    
    -- Number of average for the HK sampling
    constant AVG_16             : integer   :=  3;
    constant AVG_8              : integer   :=  2;
    constant AVG_4              : integer   :=  1;
    constant AVG_1              : integer   :=  0;

    -- COEFC.CHMUX field value
    --  Direct  use direct coefficients source (DMA).   --  ADC1    ADC2
    --  Buffer  use coefficients buffer source.         --  ======  ======
    constant CHMUX_DIR1BUF2     : integer   :=  0;      --  Direct  Buffer
    constant CHMUX_DIR2BUF1     : integer   :=  1;      --  Buffer  Direct
    constant CHMUX_DIR1BUF1     : integer   :=  2;      --  Buffer  Buffer
    constant CHMUX_DIR2BUF2     : integer   :=  3;      --  Direct  Direct

    -- DUMPn.MODE field values (dump mode)
    constant DUMPMODE_STD       : std_logic :=  '0';    -- standard
    constant DUMPMODE_MAC       : std_logic :=  '1';    -- MAC-optmized

    -------- Bit/bitfields positions ---------------------------------------

    -- SAMPC register
    constant SAMPC_CLKON1_BIT   : natural   :=  0;      -- clock on
    constant SAMPC_CLKON2_BIT   : natural   :=  1;      -- clock on
    constant SAMPC_OEN1_BIT     : natural   :=  2;      -- output enable
    constant SAMPC_OEN2_BIT     : natural   :=  3;      -- output enable
    constant SAMPC_PSUON1_BIT   : natural   :=  4;      -- power supply
    constant SAMPC_PSUON2_BIT   : natural   :=  5;      -- power supply
    constant SAMPC_MUXEN1_BIT   : natural   :=  6;      -- mux enable
    constant SAMPC_MUXEN2_BIT   : natural   :=  7;      -- mux enable
    constant SAMPC_GO1_BIT      : natural   :=  8;      -- channel 1 go
    constant SAMPC_GO2_BIT      : natural   :=  9;      -- channel 2 go
    constant SAMPC_ADCSEL_LSB   : natural   :=  10;     -- mux select
    constant SAMPC_ADCSEL_MSB   : natural   :=  11;     -- mux select
    constant SAMPC_CHMUX_LSB    : natural   :=  12;
    constant SAMPC_CHMUX_MSB    : natural   :=  13;

    -- COEFC register
    constant COEFC_EADDR_LSB    : natural   :=  0;      -- end address
    constant COEFC_CFILL_BIT    : natural   :=  14;     -- C-buffer fill
    constant COEFC_CDUMP_BIT    : natural   :=  15;     -- C-buffer dump
    constant COEFC_SADDR_LSB    : natural   :=  16;     -- start address
    -- [MSB: depends on generic]

    -- SAMP1/SAMP2 registers
    constant SAMPN_EADDR_LSB    : natural   :=  0;      -- end address
    -- [MSB: depends on generic]
    constant SAMPN_SADDR_LSB    : natural   :=  16;     -- start address
    constant SAMPN_BAND_MSB     : natural   :=  15;     -- band field
    constant SAMPN_BAND_LSB     : natural   :=  14;     -- =
    -- [MSB: depends on generic]

    -- Maximum value for SAMP_ADDR_LEN generic parameter
    constant SAMP_ADDR_LEN_MAX  : positive  :=  16 - 2 - 1;

    -- DUMP1/DUMP2 registers
    -- SADDR/PTR fields <=> SAMPN.EADDR field (size, position)
    constant DUMPN_MODE_BIT     : natural   :=  15;     -- dump mode

    -- CALIB register
    constant CALIB_DIV_LSB      : natural   :=  0;      -- clock divide
    constant CALIB_DIV_MSB      : natural   :=  2;      -- =
    constant CALIB_LVL_LSB      : natural   :=  3;      -- noise level
    constant CALIB_LVL_MSB      : natural   :=  5;      -- =
    constant CALIB_EN_BIT       : natural   :=  6;      -- calibration enable

    -- MISC register
    constant MISC_WDI_BIT       : natural   :=  0;      -- WDI output
    constant MISC_WDEN_BIT      : natural   :=  1;      -- watchdog enable
    constant MISC_REDSPW_EN_BIT : natural   :=  2;      -- Spacewire redundant link enable
    constant MISC_NOMSPW_EN_BIT : natural   :=  3;      -- Spacewire nominal link enable
    -- Other fields: variable position

    -- HLF register
    constant HLF_LFX_LSB        : natural   :=  0;      -- LFX mode
    constant HLF_LFX_MSB        : natural   :=  1;      -- "
    constant HLF_LFY_LSB        : natural   :=  2;      -- LFY mode
    constant HLF_LFY_MSB        : natural   :=  3;      -- "
    constant HLF_HFRMODE_LSB    : natural   :=  4;      -- HFR mode
    constant HLF_HFRMODE_MSB    : natural   :=  5;      -- "
    constant HLF_VCO_EN_BIT     : natural   :=  6;
    constant HLF_HFR_EN_BIT     : natural   :=  7;
    constant HLF_ANT_EN_BIT     : natural   :=  8;
    constant HLF_IN1SEL_BIT     : natural   :=  9;
    constant HLF_IN2SEL_BIT     : natural   :=  10;    
    constant HLF_IN3SEL_BIT     : natural   :=  11;     
    
    -- HLF register
    constant TNR_BAND1_LSB      : natural   :=  0;
    constant TNR_BAND1_MSB      : natural   :=  1;
    constant TNR_SENSOR1_LSB    : natural   :=  2;
    constant TNR_SENSOR1_MSB    : natural   :=  3;
    constant TNR_AGCWF1_BIT     : natural   :=  4;
    constant TNR_TNR1_EN_BIT    : natural   :=  5;
    constant TNR_BAND2_LSB      : natural   :=  6;
    constant TNR_BAND2_MSB      : natural   :=  7;
    constant TNR_SENSOR2_LSB    : natural   :=  8;
    constant TNR_SENSOR2_MSB    : natural   :=  9;
    constant TNR_AGCWF2_BIT     : natural   :=  10;    
    constant TNR_TNR2_EN_BIT    : natural   :=  11;     
    
    -- Spare & Test register
    constant SPRTEST_SPR_LSB    : natural   :=  0;      
    constant SPRTEST_SPR_MSB    : natural   :=  1;     
    constant SPRTEST_TEST_LSB   : natural   :=  2;     
    constant SPRTEST_TEST_MSB   : natural   :=  5;    
    
    -- SPI control register
    constant SPIC_GO_BIT        : natural   :=  0;      
    constant SPIC_AVG_LSB       : natural   :=  1;     
    constant SPIC_AVG_MSB       : natural   :=  2;     
    constant SPIC_INPUT_LSB     : natural   :=  3;  
    constant SPIC_INPUT_MSB     : natural   :=  5;  

    -- MAC/ADC controller: sub-block indices
    constant MADC_CHAN1_BLK     : natural   :=  0;      -- channel 1 ctrl
    constant MADC_CHAN2_BLK     : natural   :=  1;      -- channel 2 ctrl
    constant MADC_MAC1_BLK      : natural   :=  2;      -- MAC unit
    constant MADC_MAC2_BLK      : natural   :=  3;      -- MAC unit
    constant MADC_CBUF_BLK      : natural   :=  4;      -- C-buffer
    constant MADC_DMA_BLK       : natural   :=  5;      -- DMA block
    constant MADC_ACC_BLK       : natural   :=  6;      -- DMA block

    constant MADC_BLK_COUNT     : natural   :=  7;      -- sub-blocks count

    -------- Pin assignments definitions -----------------------------------

    -- MEM interface: output enable lines (mem_oe_n).
    constant MEM_OE_RAM         : integer   :=  0;
    constant MEM_OE_WRDATA      : integer   :=  1;

    -- ADC external configuration pins
    -- *CAUTION* keep in sync with SAMPC register fields assignments
    constant ADC_EXTCONF_OEN1   : integer   :=  0;
    constant ADC_EXTCONF_OEN2   : integer   :=  1;
    constant ADC_EXTCONF_PSUON  : integer   :=  2;
    constant ADC_EXTCONF_MUXEN  : integer   :=  3;
    constant ADC_EXTCONF_MUX0   : integer   :=  4;
    constant ADC_EXTCONF_MUX1   : integer   :=  5;
    constant ADC_EXTCONF_MSB    : integer   :=  5;

    -------- Other ---------------------------------------------------------

    -- Samples buffers address length
    constant SAMP_ADDR_LEN      : positive  :=  10;

    constant STAT_SLVN          : positive  :=  1;

    -------- Helper code ---------------------------------------------------

    -- [CSEL] Conditionnal value select (<=> C ternary operator "?:")
    -- @b:      boolean expression.
    -- @t_val:  value to return if condition is true.
    -- @f_val:  value to return if condition is false.
    function condSel (b     : boolean;
                      t_val : integer;
                      f_val : integer) return integer;

    -- [B2L] Convert boolean to logic value.
    -- @b:      boolean expression.
    function conv  (b   : boolean) return std_logic;

    -- [I2L] Convert integer to logic value (LSB of argument).
    -- @i:      an integer.
    function conv  (i   : integer) return std_logic;

end package tnr_hfr_pkg;


package body tnr_hfr_pkg is

    -- [CSEL] --------------------------------------------------------------
    function condSel (b     : boolean;
                      t_val : integer;
                      f_val : integer) return integer is
    begin
        if b then
            return t_val;
        else
            return f_val;
        end if;
    end function condSel;

    -- [B2L] ---------------------------------------------------------------
    function conv  (b   : boolean) return std_logic is
    begin
        if b then
            return '1';
        else
            return '0';
        end if;
    end function conv;

    -- [I2L] ---------------------------------------------------------------
    function conv  (i   : integer) return std_logic is
    begin
        if (i mod 2) = 0 then
            return '0';
        else
            return '1';
        end if;
    end function conv;

end package body tnr_hfr_pkg;

-- end tnr_hfr_pkg.vhd

Let me change the SPI tb and take a look. Thanks !
 

There are no declarations for AVG_2, AVG_4, AVG_8, HK*_OFF.

You also cut and pasted the code incorrectly the closing end if for if clk_on = '1' then is missing.

Also some of the lines in the package file need to be removed for it to compile cleanly.
 

Hi Ads-ee,

Oups ! My bad !

This is the correct code.

Code:
----------------------------------------------------------------------------          
--  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 ===========================================
  
  -- Register offsets (/!\ keep in sync with 'tnr_hfr_pkg'!)
  constant HK1_OFF   : std_logic_vector  :=  "00";
  constant HK2_OFF   : std_logic_vector  :=  "01";
  constant HK3_OFF   : std_logic_vector  :=  "10";
  constant HK4_OFF   : std_logic_vector  :=  "11";
  
  -- 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_cs_r     : std_logic;                    -- SPI chip select
  signal average_r    : unsigned((f_log2(HK_AVG_MAX)-1) downto 0);         
                                                      -- Average number of sampling register
  signal spi_clk_cnt  : integer;		      -- counter to generate a 1 MHz SPI clock
  
  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_cnt <= 0;
                      spi_clk_r <= not (spi_clk_r);
	      else
		      spi_clk_cnt <= spi_clk_cnt + 1;
	      end if;

      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(3 downto 0);
    begin
      case to_integer(unsigned(avg_sel)) is
        when AVG_16   =>  result  :=  "1111";   -- 15
        when AVG_4   =>    result  :=  "0111";   -- 7
        when AVG__   =>    result  :=  "0011";   -- 3
        when others  =>  -- including AVG_1
                         result  :=  "0000";   -- 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;

Sorry for my mistakes, yesterday I sent the file from my personnal computer and the file wasnt updated ! and my copy/paste was bad :( The package and the tb seem good.

@TrickyDicky, i replaced all the wait PERIOD*t by t*rising_edge(clk) but the problems are still here !
 

AVG_* constants are still undefined in the spi file.
also f_log isn't defined in any of your files.

maybe you should try compiling what you plan on posting before you post.

- - - Updated - - -

@TrickyDicky, i replaced all the wait PERIOD*t by t*rising_edge(clk) but the problems are still here !

What did you do here? Are you attempting to multiply the clock edge by t!?

Uh, that's not what Tricky suggested.

You should delay by counting up "t" clock cycles. As I'm more familiar with Verilog...
Code:
repeat (t) @ (posedge clk);
would repeatedly wait for the positive edge of the clock "t" times.

Regards
 

Hi ads-ee,

I compiled this time and it succeded... :D

Code:
----------------------------------------------------------------------------
--  This file is part of the TNR-HFR FPGA project VHDL library.
----------------------------------------------------------------------------
--  File        : spi.vhd
----------------------------------------------------------------------------
--  $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;
    ctrl_avg      : in std_logic_vector(1 downto 0);
    ctrl_addr     : in std_logic_vector(1 downto 0);
    ctrl_dat      : out std_logic_vector(31 downto 0);
    ctrl_eosmp    : out std_logic;
    
    -- SPI interface
    spi_cs_n      : out std_logic;
    spi_sclk      : out std_logic;
    spi_mosi      : out std_logic;
    spi_miso      : in std_logic  
    
  );
end entity spi;

architecture rtl of spi is
  
  --====== Types and constants ===========================================
  
  -- Register offsets (/!\ keep in sync with 'tnr_hfr_pkg'!)
  constant HK1_OFF   : std_logic_vector  :=  "00"; 
  constant HK2_OFF   : std_logic_vector  :=  "01";
  constant HK3_OFF   : std_logic_vector  :=  "10";
  constant HK4_OFF   : std_logic_vector  :=  "11";
  
  -- 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
  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_r_old  : std_logic;       
  signal average_r      : unsigned(3 downto 0);         -- Average number register
  signal input_r        : unsigned(2 downto 0);         -- Input selection register
  signal count_r        : unsigned(3 downto 0);         -- Internal counter
  signal spi_cs_r       : std_logic;                    -- SPI chip select
  signal din_r          : unsigned(11 downto 0);        -- sampled data
  signal ctrl_dat_r     : HKregs;                       -- accumulated sampled data
  signal spi_clk_cnt    : integer;                      -- counter to generate a 1 MHz SPI clock
  
  -------- 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 ;
      spi_clk_r_old <= '0';
    elsif rising_edge(clk) then     
      if clk_on = '1' then                -- SPI clock enabled
        if spi_clk_cnt > 12 then
          spi_clk_cnt <= 0;
          spi_clk_r <= not (spi_clk_r) ;
        else
          spi_clk_cnt <= spi_clk_cnt + 1;
        end if;
        
      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(3 downto 0);
    begin
      case to_integer(unsigned(avg_sel)) is
        when AVG_16   =>  result  :=  "1111";   -- 15
        when AVG_4   =>   result  :=  "0111";   -- 7
        when AVG_8   =>   result  :=  "0011";   -- 3 
        when others  =>  -- including AVG_1
                          result  :=  "0000";   -- 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 avg_step = '1' and spi_clk_r ='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 input_step = '1' and spi_clk_r ='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 cnt_step = '1' and spi_clk_r ='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';     -- 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';     -- data valid
    clk_on      <= '1';     -- clock enabled
    eosmp       <= '0';     -- 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';
        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       
        data_ok <= '1';
        cnt_step <= '1';        
        if count_r = "0000" and spi_clk_r = '1' then
          input_step <= '1';
          if input_r = "00000" then
            if average_r = "00" then
              next_state <= LAST_S;
            else
              avg_step <= '1';
            end if;
          end if;
        end if;
      
      when LAST_S => -- last HK Sample
        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
      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;

I didn't write t*rising_edge in my tb, don't worry. I used a counter that waits t rising_edge(clk). :D
 

I took a look at the file, but I still don't see any definition for AVG_# in the new file, and it's not defined in any of your other files you've posted up till now.

Regards
 

I didn't write t*rising_edge in my tb, don't worry. I used a counter that waits t rising_edge(clk). :D

Instead of using a counter, much easier to write:

Code:
procedure wait_for_clks(        n   :    positive;
                            signal clk : in std_logic) is
    begin
        for i in 1 to n loop
                wait until rising_edge(clk);
        end loop;    
    end procedure wait_for_clks;

- - - Updated - - -

Its the kind of procedure you have in a testbench tools package, and you connect any signal to "clk"

- - - Updated - - -

There is STILL code missing - the gencomp package.

PS. if it's not working, it's really your job to debug it.
 

Code:
      -------- sampling sequence -------------            
      if cnt_step = '1' then
      -------- MOSI control ------------------
        [COLOR="#FF0000"]if spi_clk_r = '1' then     -- falling edge of SCLK[/COLOR]
          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 ------------------
        [COLOR="#FF0000"]else -- rising edge of SCLK[/COLOR]
          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;
Did you really run a simulation and look at the waveforms? The problem is pretty obvious when you look at the waveforms and compare it with the code.

This code doesn't work as a SPI data input shift register. You've made the spi_clk_r an enable but it's not the falling edge or rising edge you are checking it's a level signal so everything is being assigned every clk instead of only on spi_clk_r transitions. You can see that happening on the count_r signal. If you didn't have a complete understanding of the spi module you should have run a simulation on the original design to see how it operates before making your changes. At least then you would have had a baseline to compare to.

Also this isn't a great way to perform a shift operation. What is implemented is a bit demultiplexer that has gating to assign each bit based on the count_r. A shift register would have been both simpler and would use less resources.

You need to learn how to debug a simulation. It took me more time to get a simulation to run using your incomplete files than it took to debug the main problem in the design. You also don't have a 1 MHz SPI clock it's actually 892.9 KHz. 1.12 us period. You have some counter problem for generating it that I didn't debug, I'll leave that up to you.

Regards
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top