+ Post New Thread
Results 1 to 9 of 9
  1. #1
    Newbie level 5
    Points: 89, Level: 1

    Join Date
    Jul 2017
    Posts
    9
    Helped
    0 / 0
    Points
    89
    Level
    1

    Spartan - 3A ADC and DAC interface not working

    Hello!

    I am working on ADC and DAC interface for Spartan - 3A board and I have checked the output of the amplifier which works. But I am having issues with ADC and DAC. I am displaying the 8 MSBs of the ADC on the LEDs, but all the LEDs are always lit.

    I had set the clock the frequency to 1.5MHz from 1MHz and finally 1KHz, yet there is no change in the output. The code is given below. Can someone help me figure out the problem?

    [syntax=vhdl]library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.STD_LOGIC_ARITH.ALL;
    use IEEE.STD_LOGIC_UNSIGNED.ALL;

    entity ADC is
    port ( enable : in std_logic; --switch enable for start preamp and adc
    clk_div : in std_logic;
    start_AD_CONV : in std_logic; --switch enable for start adc
    SPI_MISO : in std_logic;
    AD_CONV : out std_logic; --SPI-bus for ADC
    ADC1 : inout std_logic_vector(13 downto 0); --VINA
    ADC2 : out std_logic_vector(13 downto 0); --VINB
    AMP_CS : out std_logic; --SPI-bus for preamp
    SPI_MOSI : out std_logic;
    SPI_SCK : out std_logic;
    DAC_CS : out std_logic;
    AMP_SHDN : out std_logic; --preamp
    DAC_CLR : out std_logic --dac
    );
    end ADC;

    architecture Behavioral of ADC is

    type state_type is (amp_state, adc_state, dac_state);
    type amp_state_type is (IDLE, START, HI, LO);
    type adc_state_type is (IDLE_AD, START_AD,LO_AD,HI_AD,FINE_AD);
    type dac_state_type is (da_idle, da_send, da_sck1, da_loop, da_end);
    type state_type_clock is (clock_on, clock_off);
    signal state: state_type := amp_state;
    signal amp_state_reg: amp_state_type := IDLE;
    signal adc_state_reg: adc_state_type := IDLE_AD;
    signal dac_state_reg: dac_state_type := da_idle;
    signal state_clock : state_type_clock := clock_off; -- Clock state set to clock_off
    signal sck_reg: std_logic:='0';
    signal da_data_reg: std_logic_vector (31 downto 0) := "00000000001100000000000000000000"; -- signal for the DAC
    signal da_bit_reg : natural range 0 to 32;
    signal ADC_COPY: std_logic_vector (13 downto 0) := (others => '0'); -- a copy of the ADC-value to use for the DAC
    signal clk_sample : STD_LOGIC := '0'; -- Clock Sample is initalized to zero
    signal counter1 : integer range 0 to 34; -- Counter up to 34
    signal risingedge : std_logic := '1'; -- For clock of rising edge
    signal count1:integer:=1;
    signal tmp : std_logic := '0';


    begin

    -- 1.5MHz clock
    process(clk_div, enable)
    begin
    if(enable='0') then
    count1<=1;
    tmp<='0';
    elsif(clk_div'event and clk_div='1') then
    count1<=count1+1;
    if (count1= 25000) then -- 1KHz frequency --25 for 1MHz
    tmp <= NOT tmp;
    count1<= 1;
    end if;
    end if;
    end process;

    sclk_clock : process(clk_div) -- Process for state of clock
    begin
    if(rising_edge(clk_div)) then -- When rising edge, clock state is set to on
    case state_clock is
    when clock_on => -- When clock is on, set SPI_SCK = clk_sample
    SPI_SCK <= tmp;
    when clock_off => -- When clock is off, set SPI_SCK = 0
    SPI_SCK <= '0';
    end case;
    end if;
    end process;

    --START PROCESS PREAMP - ADC - DAC
    process(clk_div)
    variable count: integer range 0 to 16; -- 14 bits for 1 ADC channel+2 for zero
    variable counter : integer range 0 to 34; -- 34 SPI_SCK clockchanges for an entire ADC-loop
    variable gaincount: integer range 0 to 7; -- 8 bits preampsignal
    constant gain_temp: std_logic_vector (7 downto 0):= "00010001"; -- biggest range of preamp
    begin
    if clk_div'event and clk_div ='1' then
    case state is
    --START AMP CYCLE
    when amp_state =>
    DAC_CS <= '1'; --non active SPI-bus for DAC
    case amp_state_reg is
    when IDLE =>
    gaincount:=7;
    if enable = '1' then
    amp_state_reg <= START;
    else
    AMP_SHDN <= '1';
    AMP_CS <= '1';
    amp_state_reg <= IDLE;
    end if;

    when START =>
    AMP_SHDN <= '0';
    state_clock <= clock_off;
    SPI_MOSI <= '0';
    counter := 0;
    AMP_CS <= '0';
    amp_state_reg <= HI;

    when HI =>
    state_clock <= clock_on;
    counter := counter+1; -- The counter was set to 0
    SPI_MOSI <= gain_temp(gaincount); -- gaincount is set to be 7
    amp_state_reg <= LO;

    when LO =>
    if counter = 8 then -- When 8 bit transferred
    AMP_SHDN <= '1'; -- Shut the amp
    AMP_state_reg <= IDLE; -- Go to IDLE state
    SPI_MOSI <= '0'; -- Set all the outgoing data to zero
    AMP_CS <= '1'; -- Basically, do the tasks assigned by the state IDLE
    gaincount := 7;
    state_clock <= clock_off;
    state <= adc_state; -- When done communication, go to ADC
    else
    state_clock <= clock_off; -- If counter less than 8
    gaincount := gaincount-1; -- Decrease the gain count (from 7 to 6 and so on)
    amp_state_reg <= HI; -- Go to HI to do the serial transfer
    end if;

    when others => -- Any other situation - Go to IDLE
    amp_state_reg <= IDLE;

    end case;

    --START ADC CYCLE
    when adc_state =>
    DAC_CS <= '1';
    case adc_state_reg is
    when IDLE_AD =>
    counter := 0;
    state_clock <= clock_off;
    AD_CONV <= '0';
    if enable = '0' then
    state <= amp_state;
    else
    if start_AD_CONV = '1' then
    AD_CONV <= '1';
    adc_state_reg <= START_AD;
    else
    adc_state_reg <= IDLE_AD;
    end if;
    end if;

    when START_AD =>
    state_clock <= clock_off;
    AD_CONV <= '0' after 5 ns;
    count := 16;
    adc_state_reg <=LO_AD;

    when LO_AD =>
    state_clock <= clock_off;
    if count > 0 then -- Count is initialized to 16
    count := count-1;
    end if;
    counter := counter+1; -- Counter was set to 0
    adc_state_reg <= HI_AD;

    when HI_AD =>
    state_clock <= clock_on;
    if counter <= 2 then
    adc_state_reg <= LO_AD;
    elsif counter > 2 and counter <= 16 then
    ADC1(count) <= SPI_MISO;
    adc_state_reg <= LO_AD;
    elsif counter > 16 and counter <= 18 then
    count:=14;
    adc_state_reg <= LO_AD;
    elsif counter > 18 and counter <=32 then
    ADC2(count) <= SPI_MISO;
    adc_state_reg <= LO_AD;
    elsif counter = 33 then
    adc_state_reg <= LO_AD;
    else
    adc_state_reg <= FINE_AD;
    end if;

    when FINE_AD =>
    counter := 0;
    count := 16;
    state_clock <= clock_off;
    ADC_COPY <= ADC1;
    AD_CONV <= '0';
    adc_state_reg <= IDLE_AD;
    state <= dac_state;

    when others =>
    adc_state_reg <= IDLE_AD;

    end case;

    --START DAC CYCLE
    when dac_state =>
    case dac_state_reg is
    when da_idle =>
    AMP_CS <= '1';
    AD_CONV <= '0';
    DAC_CS <= '0';
    DAC_CLR <= '0';
    state_clock <= clock_off;
    da_bit_reg <= 32;
    da_data_reg <= "00000000"&"0011"&"0000"&ADC_COPY(13 downto 2)&"0000";
    dac_state_reg <= da_send;

    when da_send =>
    DAC_CLR<='1';
    SPI_MOSI <= da_data_reg(da_bit_reg); -- da_bit_reg <= 32;
    dac_state_reg <= da_sck1;

    when da_sck1 =>
    state_clock <= clock_on;
    da_bit_reg <= da_bit_reg-1; -- Reduce the da_bit_reg by 1 every time the state
    dac_state_reg <= da_loop;

    when da_loop =>
    state_clock <= clock_off;
    if da_bit_reg > 0 then
    dac_state_reg <= da_send;
    else
    dac_state_reg <= da_end;
    end if;

    when da_end =>
    dac_cs <= '1';
    state_clock <= clock_off;
    dac_state_reg <= da_idle;
    state <= amp_state;

    when others =>
    dac_state_reg <= da_idle;

    end case;

    when others =>
    state <= amp_state;
    end case;
    end if;
    end process;

    --SPI_SCK <= sck_reg;
    end Behavioral;[/syntax]

  2. #2
    Super Moderator
    Points: 54,942, Level: 57
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster 3rd Helpful Member

    Join Date
    Apr 2014
    Posts
    11,126
    Helped
    2615 / 2615
    Points
    54,942
    Level
    57

    Re: Spartan - 3A ADC and DAC interface not working

    Hi,

    Let´s focus on the ADC first.
    You need to provide a schematic of the circuit: supply, FPGA, ADC, amplifier, analog input
    You need to provide a scope pictur of a complete data frame. From CS activate to CS inactivate of CS, SCK, MOSI, MISO (if used)

    Klaus



    •   Alt15th August 2017, 11:29

      advertising

        
       

  3. #3
    Newbie level 5
    Points: 89, Level: 1

    Join Date
    Jul 2017
    Posts
    9
    Helped
    0 / 0
    Points
    89
    Level
    1

    Re: Spartan - 3A ADC and DAC interface not working

    Thank you for your reply!

    For the supply, I am supplying from a function generator a voltage of around 0.5-0.8V for test. The Amplifier and the ADC are connected as shown in the datasheet, page 77: https://www.xilinx.com/support/docum...kits/ug330.pdf

    I have checked the working of the amplifier by using an oscilloscope probe directly at the chip output.
    The schematic and the timing for ADC is given on page 82 of the same datasheet.

    Thanks in advance.



  4. #4
    Super Moderator
    Points: 54,942, Level: 57
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster 3rd Helpful Member

    Join Date
    Apr 2014
    Posts
    11,126
    Helped
    2615 / 2615
    Points
    54,942
    Level
    57

    Re: Spartan - 3A ADC and DAC interface not working

    Hi,



    you are using the starter kit? Not one build on oyur own?
    Then the schematic should be OK.

    I meant power supply. But this is on the starter kit and should be OK.

    But the timing: do you use a ready to use IP, or you build it on your own?
    If your own: Then the datasheet timing only tells how it should be, but it doesn´t tell your real timing. --> scope picture.

    0.5..0.8V input signal.
    For sure with this variable input .. then outbut will be variable, too. Not useful to debug with LEDs.
    --> use a known, clean DC source

    From the formula it seems that your input range is: 0.4V (-8192 LSB) ...1.65V (0 LSB) ... 2.9V (+8191 LSB).
    (BTW: 0.5V..0.8V gives -7537 ... -5571, in binary: 10 xxxx xxxx xxxx, means only the upper two bits are stable.)

    Klaus



    •   Alt15th August 2017, 13:05

      advertising

        
       

  5. #5
    Newbie level 5
    Points: 89, Level: 1

    Join Date
    Jul 2017
    Posts
    9
    Helped
    0 / 0
    Points
    89
    Level
    1

    Re: Spartan - 3A ADC and DAC interface not working

    Hello! Thanks for your reply, again!

    Yes, I am using the starter kit with reference to the timings given in the datasheet.

    I am using a DC supply with a constant DC output and I have checked multiply values by changing the values. However, the problem remains that all of the LEDs are either all lit together, or just the MSB is off and the rest all lit, whenever I toggle the start_AD_CONV switch.

    Since the gain is -1, the voltages between 0.4-1.65V should be positive and voltage sin the range of 1.65-2.9V should be negative. However, for both the ranges I am getting a similar output wherein, either all the LEDs are lit or all are lit and only the MSB varies or that all are off when I toggle start_AD_CONV switch.

    I don't quite get what you mean by this:
    "But the timing: do you use a ready to use IP, or you build it on your own?
    If your own: Then the datasheet timing only tells how it should be, but it doesn´t tell your real timing. --> scope picture."



  6. #6
    Super Moderator
    Points: 54,942, Level: 57
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster 3rd Helpful Member

    Join Date
    Apr 2014
    Posts
    11,126
    Helped
    2615 / 2615
    Points
    54,942
    Level
    57

    Re: Spartan - 3A ADC and DAC interface not working

    Hi,

    If you wrote the code on your own, then we need a scope picture.

    Klaus

    - - - Updated - - -

    added

    AD_CONV <= '0' after 5 ns;
    I dont think it´s a good idea to use some fixed timing here.
    I recommend to run a simple state machine with fixed SCK clock frequency. It runs:
    0 (idle, SPI_CLK = 0),
    1 (AD_Conv = 1, SPI_CLK=0), (ensures 4ns min and 3ns min timing)
    2 to 3 (delay),
    4 to 17 (ch 0 data)
    18 to 19 (delay),
    20 to 33 (ch 1 data)
    34 to 36 (delay), (ensures 45ns timing)
    then stops with 0
    ...and can be activated anew

    mind: data input = on falling SCK edge.

    Klaus



  7. #7
    Member level 3
    Points: 1,406, Level: 8

    Join Date
    May 2012
    Location
    Maryland, USA
    Posts
    63
    Helped
    23 / 23
    Points
    1,406
    Level
    8

    Re: Spartan - 3A ADC and DAC interface not working

    Line 181: AD_CONV <= '0' after 5 ns;
    Don't think it's your problem, but that's not going to synthesize a delay.

    You might also look at your use of variables. A quick scan through and I can't see any place where you need the new value that was assigned immediately. That is probably a habit you want to break. Again, that's not causing you a problem here.



    •   Alt15th August 2017, 15:16

      advertising

        
       

  8. #8
    Newbie level 5
    Points: 89, Level: 1

    Join Date
    Jul 2017
    Posts
    9
    Helped
    0 / 0
    Points
    89
    Level
    1

    DAC Code for Spartan 3A

    Hello!

    I am trying to interface the DAC of the Spartan-3A board with the FPGA. I have written a VHDL program for the same but it doesn't seem to be working. Can anyone please help me out?

    I have used a logic analyzer to display the signals:

    Channel 0 : DAC_CLR1
    Channel 1 : DAC_CS1
    Channel 2 : DAC_OUT1
    Channel 3 : SPI_MOSI1
    Channel 4 : SPI_SCK1

    Can someone please tell me what I am doing wrong as I am not able to figure out. The signal DAC_CS amd DAC_CLR should vary once in the whole cycle, but they don't :/

    [syntax=vhdl]
    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;

    entity DAC is
    Port ( DAC_CS : inout STD_LOGIC;
    SPI_MOSI : inout STD_LOGIC;
    SPI_SCK : inout STD_LOGIC;
    Clk : in STD_LOGIC;
    Enable : in STD_LOGIC;
    Reset : in STD_LOGIC;
    DAC_CLR : inout STD_LOGIC;
    DAC_OUT : in STD_LOGIC;
    DAC_CS1 : out STD_LOGIC;
    SPI_MOSI1: out STD_LOGIC;
    SPI_SCK1: out STD_LOGIC;
    DAC_CLR1: out STD_LOGIC;
    DAC_OUT1: out STD_LOGIC;
    DEBUG : out STD_LOGIC_VECTOR (1 downto 0)
    );
    end DAC;

    architecture Behavioral of DAC is

    type state_type_clock is (clock_on, clock_off);
    signal state_clock : state_type_clock := clock_on; -- Clock state set to clock_on
    type dac_state_type is (da_idle, dac_send, da_end);
    signal dac_state_reg: dac_state_type := da_idle;
    signal da_data_reg: std_logic_vector (31 downto 0) := "00000000001100000000000000000000"; -- signal for the DAC
    signal count : natural range 0 to 32;
    signal ADC_COPY: std_logic_vector (13 downto 0) := "1000"&"0000"&"000000"; -- a copy of the ADC-value to use for the DAC
    signal cnt: integer:=1;
    signal tmp : std_logic := '0';


    begin

    DAC_CS1 <= DAC_CS;
    DAC_CLR1 <= DAC_CLR;
    DAC_OUT1 <= DAC_OUT;
    SPI_SCK1 <= SPI_SCK;
    SPI_MOSI1 <= SPI_MOSI;


    process(clk, enable)
    begin
    if(enable='0') then
    cnt<=1;
    tmp<='0';
    elsif(clk'event and clk='1') then
    cnt <=cnt+1;
    if (cnt = 25000) then -- 1 KHz Frequency
    tmp <= NOT tmp;
    cnt <= 1;
    end if;
    end if;
    SPI_SCK <= tmp;
    end process;


    process (tmp)

    begin
    if tmp'event and tmp='1' then

    if (reset = '1') then
    state_clock <= clock_off;
    DAC_CS <= '1';
    DAC_CLR <= '0';
    count <=32;
    da_data_reg <= "00000000"&"0011"&"0000"&"000000000000"&"0000" ;
    end if;

    case dac_state_reg is

    when da_idle =>
    DEBUG <= "01";
    DAC_CS <= '0';
    DAC_CLR <= '1';
    state_clock <= clock_off;
    count <= 32;
    da_data_reg <= "00000000"&"0011"&"0000"&ADC_COPY(13 downto 2)&"0000";
    dac_state_reg <= dac_send;

    when dac_send =>
    DEBUG <= "10";
    state_clock <= clock_on;
    if count = 0 then
    count <= 32;
    else
    if count >0 then
    count <= count - 1;
    end if;
    SPI_MOSI <= da_data_reg(count);
    if count > 0 then
    dac_state_reg <= dac_send;
    else
    dac_state_reg <= da_end;
    end if;
    end if;

    when da_end =>
    DEBUG <= "11";
    DAC_CS <= '1';
    state_clock <= clock_off;
    DAC_CLR <= '0';
    dac_state_reg <= da_idle;

    when others =>
    dac_state_reg <= da_idle;


    end case;
    end if;
    end process;
    end Behavioral;


    Click image for larger version. 

Name:	Image.PNG 
Views:	1 
Size:	99.0 KB 
ID:	140729
    [/syntax]



  9. #9
    Super Moderator
    Points: 28,163, Level: 40
    ads-ee's Avatar
    Join Date
    Sep 2013
    Location
    USA
    Posts
    6,440
    Helped
    1558 / 1558
    Points
    28,163
    Level
    40

    Re: Spartan - 3A ADC and DAC interface not working

    You should not write VHDL thinking like a software programmer...

    This:
    Code:
    SPI_MOSI <= da_data_reg(count);
    is how a software programmer thinks of a shift register. Hardware engineers think of VHDL (VHISIC Hardware Description Language) hardware shift registers as:
    Code:
    da_data_reg <= da_data_reg(30 downto 0) & "0"; -- MSB first
    
    -- after the process assign the SPI_MOSI as the MSB
    SPI_MOSI <= da_data_reg(31);
    That creates a shift register instead of a register with a huge multiplexer on the output.

    You also have an issue with the indexing as you count from 32 down to 0. There is no index #32 in the da_data_reg, what do you expect the synthesis to implement for that?

    You should also run a simulations in modelsim or Vivado instead of "simulating" your design via synthesis-implementation-download-hook_up_logic_analyzer).

    Also the reason you never get the DAC_CS going high is because it never reaches the state da_end, because you have logical issues with the following code.

    Code:
                        state_clock <= clock_on;
                        if count = 0 then
                            count <= 31;
                        else
                            if count >0 then 
                                count <= count - 1;
                            end if;
                            SPI_MOSI <= da_data_reg(count);
                            if count > 0 then
                                dac_state_reg <= dac_send;
                            else
                                dac_state_reg <= da_end;
                            end if;
                        end if;
    Once count is 0 it never reaches the else condition where you set the state.

    - - - Updated - - -

    This is a good reason to stick to only a single signal assignment in any given if statement. I'd rather have a bunch of separate if statements with repeated comparisons than have logical faults like this.

    Pull the dac_state_reg if-else outside of the other if-else.

    - - - Updated - - -

    Maybe you should look at a more professionally done SPI master...or at least some code that has documentation and comments in the code to explain what is being done and why.
    https://eewiki.net/pages/viewpage.action?pageId=4096096



--[[ ]]--