+ 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?

    Code VHDL - [expand]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    
    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;

    •   Alt15th August 2017, 10:22

      advertising

        
       

  2. #2
    Super Moderator
    Points: 52,149, Level: 55
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster

    Join Date
    Apr 2014
    Posts
    10,469
    Helped
    2490 / 2490
    Points
    52,149
    Level
    55

    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



  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.



    •   Alt15th August 2017, 11:42

      advertising

        
       

  4. #4
    Super Moderator
    Points: 52,149, Level: 55
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster

    Join Date
    Apr 2014
    Posts
    10,469
    Helped
    2490 / 2490
    Points
    52,149
    Level
    55

    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: 52,149, Level: 55
    Achievements:
    7 years registered
    Awards:
    Most Frequent Poster

    Join Date
    Apr 2014
    Posts
    10,469
    Helped
    2490 / 2490
    Points
    52,149
    Level
    55

    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,364, Level: 8

    Join Date
    May 2012
    Location
    Maryland, USA
    Posts
    63
    Helped
    23 / 23
    Points
    1,364
    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 :/

    Code VHDL - [expand]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    
    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;
     
     
    [ATTACH=CONFIG]140729[/ATTACH]



  9. #9
    Super Moderator
    Points: 27,697, Level: 40
    ads-ee's Avatar
    Join Date
    Sep 2013
    Location
    USA
    Posts
    6,323
    Helped
    1535 / 1535
    Points
    27,697
    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



--[[ ]]--