Search code examples
vhdlspiintel-fpga

Synthesizable wait statement in VHDL


I am writing a VHDL code to control AD7193 via SPI communication. ADC is controlled and configured via number of con-chip registers, DOUT/RDY (SPI_miso) goes low to indicate the completion of conversion. These are the code and timing characteristics (Please see Here) of AD7193.

library ieee;
use ieee.std_logic_1164.all; 
use ieee.std_logic_unsigned.all; 
use ieee.numeric_std.all;

entity MainADC is port (
        clk     : in  std_logic;                       -- OSC 50MHz
        rst     : in  std_logic;                       -- Reset clock
        sclk    : out std_logic;                       -- out clock
        cs      : out std_logic;                       -- Chip select
        spi_mosi: out std_logic;                       -- Write register
        start   : in std_logic;                        -- Start Conversion
        spi_miso: in  std_logic);                      --  Read register/Single channel, 24 bits
end MainADC;

architecture Behavior of MainADC is


    signal outclk  : std_logic;
    signal clk_sel : std_logic; -- Clock Control
    signal CommMode: std_logic_vector(7 downto 0) :="00001000"; -- Communications register==> next stage: Mode Register
    signal Mode    : std_logic_vector(23 downto 0) := "001010000000000001100000"; -- Single conversion mode     
    signal CommRead: std_logic_vector(7 downto 0) := "01011000"; -- Communications register==> next stage: Read Data

begin
    cs <= '0'; -- Hardwired low

    process(clk, rst) -- Clock_gen 500KHz
    variable cnt : integer range 0  to 500 :=1;
        begin
            if (rst='1') then
                cnt := 0;
                outclk   <= '0';
            elsif (clk = '1' and clk'event) then
                cnt := cnt + 1;
                if (cnt = 50) then
                    cnt := 0;
                    outclk   <= not outclk;
                end if; 
            end if;     
    end process; 

    process(clk_sel)
    begin
        if (clk_sel='0') then
            sclk <= '1'; --Clock Idle High
        else
            sclk <= outclk; --Provide Clock Cycles
        end if; 
    end process;    


    process (outclk) -- SPI Comm

    variable i        : integer :=0;
    variable data_temp: std_logic_vector(23 downto 0) :=(others=>'0');

    begin

        if (start = '0') then
            clk_sel <= '0';
            i:=0;
        else

            if falling_edge(outclk) then                
            i:=i+1; 

                if (i>=0 and i<=7) then -- Communications register==> next stage: Mode Register (8 bits)
                    clk_sel <= '1';
                    CommMode(7 downto 1) <= CommMode(6 downto 0);
                    CommMode(0)          <= CommMode(7);
                    spi_mosi             <= CommMode(7);

                elsif (i=8) then
                    clk_sel <= '0'; --Clock Idle High

                elsif (i>=9 and i<=32) then -- Single conversion mode (24 bits)
                    clk_sel <= '1';
                    Mode(23 downto 1) <= Mode(22 downto 0);
                    Mode(0)           <= Mode(23);
                    spi_mosi          <= Mode(23);

                elsif (i=33) then
                    clk_sel <= '0'; --Clock Idle High
                    wait until (spi_miso'event and spi_miso='0'); --Wait for Ready Read Signal (DOUT/DRY)

                elsif (i>=34 and i<= 41) then -- Communications register==> next stage: Read Data
                    clk_sel <= '1';
                    CommRead(7 downto 1) <= CommRead(6 downto 0);
                    CommRead(0)          <= CommRead(7);
                    spi_mosi             <= CommRead(7);

                elsif (i=42) then
                    clk_sel <= '0'; --Clock Idle High                       

                elsif (i>=43 and i<= 66) then 
                    clk_sel <= '1';
                    data_temp(23 downto 0) := data_temp(22 downto 0) & spi_miso; --Read Data


                elsif (i>=66 and i<=566) then  -- Waiting for ADC Power Up after Conversion (~1ms)
                    clk_sel <= '0'; --Clock Idle High

                elsif (i=567) then
                i:=0;

                end if;     
            end if; 
        end if;                                                 
    end process;    

end Behavior; 

As far as I know Wait Until statement supports for vhdl synthesis, but I received this error: "Error (10441): VHDL Process Statement error at Main ADC.vhd(53): Process Statement cannot contain both a sensitivity list and a Wait Statement". How can I solve this error? Is there any other way to hold counter and waiting for DOUT/RDY event to know when conversion is complete for read data? Any opinions are appreciated! Thank you.


Solution

  • The error message is due to a VHDL language semantic restriction.

    The wait until implies you're using spi_miso as a clock, and it looks like you're requiring a flip flop to toggle as a result of i counter reaching 33, before progressing to 34.

    The error about the sensititvity list item (outclock) and the wait statement is telling you you can't use two different clocks in this process.

    If there is no metastability issue with outclk, instead of waiting don't increment i unless spio_miso = 0 when i = 33. You could also evaluate i before incrementing it (the equivalent of making i a signal).

    This may deserve simulation before synthesis. There may be other issues lurking in there.

    Your VHDL analyzes with a couple of changes:

            if falling_edge(outclk) then 
    
                if ( i /= 33 or spi_miso = '0' ) then
                    i:= i + 1; 
                end if;
    
                if (i>=0 and i<=7) then -- Communications register==> next stage: Mode Register (8 bits)
                    clk_sel <= '1';
                    CommMode(7 downto 1) <= CommMode(6 downto 0);
                    CommMode(0)          <= CommMode(7);
                    spi_mosi             <= CommMode(7);
    
                elsif (i=8) then
                    clk_sel <= '0'; --Clock Idle High
    
                elsif (i>=9 and i<=32) then -- Single conversion mode (24 bits)
                    clk_sel <= '1';
                    Mode(23 downto 1) <= Mode(22 downto 0);
                    Mode(0)           <= Mode(23);
                    spi_mosi          <= Mode(23);
    
                -- elsif (i=33) then
                --     clk_sel <= '0'; --Clock Idle High
                --     wait until (spi_miso'event and spi_miso='0'); --Wait for Ready Read Signal (DOUT/DRY)
    
                elsif (i>=34 and i<= 41) then -- Communications register==>
    

    (And I normally wouldn't put parentheses around an if statement expression.)