Question

Hello

I am using the Pmod AD5 to convert my analog signals from light sensor to be able to feed it into the fpga. Any one has an idea of how can i proceed? I tried by testing the AD5 by inputting an analog input but i cannot get to the digital output...any help would be highly appreciated..Thanks

Edited by Josh
Added Tags

Share this post


Link to post
Share on other sites

Recommended Posts

  • 0

Hi,

 

There are a few things that could potentially be the source of your problem, but I'm not sure quite yet what they might be. So, I have three questions.

 

Did you change/write to any of the registers of the Analog Devices ADC that is on the Pmod?

Did you use any external reference voltage?

Is it just a single analog signal that you are measuring?

 

Thanks,

JColvin

Share this post


Link to post
Share on other sites
  • 0

Hi i1116345,

 

From a quick read of the datasheet, it seems that you need to send a few register writes to switch ADC into continuous sample mode, and then you can just clock the data in every time DRDY is asserted.

 

You can take either the high road (with lots of levels of abstractions in your design) or the often-muddy low road (where you do all the work on paper, and then just make a design that achieves the desired result).

 

The high road most likely involves a soft CPU, with a SPI peripheral interface, and software that talks SPI that will configure the device and retrieve the samples.

 

The low road involves a long shift register to send out the SPI signals needed to configure the eight registers in the device, and then a simple FSM that clocks in the samples when they are available, storing the values into a flip-flops connected to the LEDs. So to me the low road looks to be something like two or three 128-bit shift registers (as it has to program up to eight 8-bit registers), a counter to act as a clock divider, and a small FSM that clocks in the samples . 

 

I know which road I would take - but that is just me.

 

Mike

Share this post


Link to post
Share on other sites
  • 0

To Mr JColvin,

I don't know how to write to the registers on the Pmod :/

I am just using a supply to feed my adc ( 5V) and to act as an input ( 1 V) and i wish to see the digital output of the input ?( I dnt know if am on the right track)

I am using an oscilloscope to view the output considering the fact that the output is a serial one. For the time being its just a single analog input but for the project i require 6 analog inputs to be converted to digital so that i can use the fpga to compare and drive my motors.

I am a little confused about the SYNC and the JP1 ( I think i am wronly connecting them).

Thanks.

 

Share this post


Link to post
Share on other sites
  • 0

To Mr Mike

I think the high road would be my choice but the problem is that I am stuck with the SPI interface and the software is the vhdl code used in the FPGA. I dnt know if i am right..plz guide Thanks :)

Share this post


Link to post
Share on other sites
  • 0

Hi 1116345,

 

So here is a quick hack at it, without any reference to the datasheet.

 

First off you need an idea of what the interface design for the AD5 will look like - here's my stab at it:

-    COMPONENT pmod_ad5
    PORT(
         clk50MHz  : IN  std_logic;
         pmod_sclk : OUT  std_logic;
         pmod_mosi : OUT  std_logic;
         pmod_miso : IN  std_logic;
         pmod_cs   : OUT  std_logic;
         samples   : OUT  std_logic_vector(23 downto 0)
        );
    END COMPONENT;

The 50 MHz system clock, the PMOD signals, and something to hold the sample.

 

And now here's the first file of VHDL - it does nothing but divide the system clock from 50 MHz down to 1 MHz, for use as the SPI clock:

 

----------------------------------------------------------------------------------
-- PMOD_AD5 - an attempt at configuring the Digilent PMOD_AD5 over SPI
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity pmod_ad5 is
    Port ( clk50MHz  : in  STD_LOGIC;
           pmod_sclk : out STD_LOGIC := '1';
           pmod_mosi : out STD_LOGIC := '1';
           pmod_miso : in  STD_LOGIC;
           pmod_cs   : out STD_LOGIC := '1';
           samples   : OUT  std_logic_vector(23 downto 0)
);
end pmod_ad5;
 
architecture Behavioral of pmod_ad5 is
   signal counter : unsigned(5 downto 0) := (others => '0');
begin
 
p: process(clk50Mhz)
   begin
      if rising_edge(clk50MHz) then
         -- First off, generate a 1MHz square wave for SCLK;
         -- I haven't checked how fast the SPI interface works, so check this on the datasheet.
         if counter = 49 then
            pmod_sclk <= '1';
            counter <= (others => '0');
         else
           if counter = 24 then
              pmod_sclk <= '0';
           end if;
           counter <= counter + 1;
         end if;
      end if;
   end process;
 
end Behavioral;

 

You will also need to add a constraints file (.UCF file) to attach the external signals to the correct pins. For testing you might want to connect the highest 8 bits of 'samples' to the LEDs.
 
You will also need a test bench to allow you to simulate the design:
 

--------------------------------------------------------------------------------
-- TB_PMOD_AD5 - test bench for my attempt at using the PMODAD5
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
 
ENTITY tb_pmod_ad5 IS
END tb_pmod_ad5;
 
ARCHITECTURE behavior OF tb_pmod_ad5 IS 
    COMPONENT pmod_ad5
    PORT(
         clk50MHz  : IN  std_logic;
         pmod_sclk : OUT  std_logic;
         pmod_mosi : OUT  std_logic;
         pmod_miso : IN  std_logic;
         pmod_cs   : OUT  std_logic;
         samples   : OUT  std_logic_vector(23 downto 0)
        );
    END COMPONENT;
 
   signal clk50MHz : std_logic := '0';
   signal pmod_miso : std_logic := '0';
   signal pmod_sclk : std_logic;
   signal pmod_mosi : std_logic;
   signal pmod_cs   : std_logic;
   signal samples   : std_logic_vector(23 downto 0);
 
   -- Clock period definitions
   constant clk50MHz_period : time := 20 ns;
 
BEGIN
 
uut: pmod_ad5 PORT MAP (
          clk50MHz => clk50MHz,
          pmod_sclk => pmod_sclk,
          pmod_mosi => pmod_mosi,
          pmod_miso => pmod_miso,
          pmod_cs => pmod_cs
        );
 
clk50MHz_process :process
   begin
      clk50MHz <= '0';
      wait for clk50MHz_period/2;
      clk50MHz <= '1';
      wait for clk50MHz_period/2;
   end process;
 
END;

Share this post


Link to post
Share on other sites
  • 0

Great - if you get this far, you should be able to fire up the simulator and get a trace which shows CLK50MHz running at 50Mhz, and PMOD_SCLK running at 1MHz.

 

However, I've run out of space to upload images, so can't show you :-(.

 

So trust me - you now have a 1MHz SCK.

 

Next is to start sending data out. I2S send in MSB first. so source reads best if we send bits from high to low. To do this we need a shift register, and to output the highest bit from it at the correct time:

----------------------------------------------------------------------------------
-- PMOD_AD5 - an attempt at configuring the Digilent PMOD_AD5 over SPI
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity pmod_ad5 is
    Port ( clk50MHz  : in  STD_LOGIC;
           pmod_sclk : out STD_LOGIC := '1';
           pmod_mosi : out STD_LOGIC := '1';
           pmod_miso : in  STD_LOGIC;
           pmod_cs   : out STD_LOGIC := '1';
           samples   : OUT  std_logic_vector(23 downto 0)
);
end pmod_ad5;
 
architecture Behavioral of pmod_ad5 is
   signal counter : unsigned(5 downto 0) := (others => '0');
   signal cs_shift_reg : std_logic_vector(63 downto 0) := x"FF007FFFFFFFFFFF";
   
begin
 
p: process(clk50Mhz)
   begin
      if rising_edge(clk50MHz) then
         -- First off, generate a 1MHz square wave for SCLK;
         -- I haven't checked how fast the SPI interface works, so check this on the datasheet.
         if counter = 49 then
            pmod_sclk <= '1';
            counter <= (others => '0');
         else
           -- change the CS signal when SCLK is high
           if counter = 12 then
              -- Output the highest bit and advance the shift register
              pmod_cs <= cs_shift_reg(cs_shift_reg'high);
              cs_shift_reg <= cs_shift_reg(cs_shift_reg'high-1 downto 0) & '1';
           end if;
           if counter = 24 then
              pmod_sclk <= '0';
           end if;
           counter <= counter + 1;
         end if;
      end if;
   end process;
 
end Behavioral;
 

In simulation  I now get a PMOD_CS that drops when the SCLK signal is high, and stays low for 9us (or 9 clock cycles) due to the data in the cs_shift_reg. Now to the the same to the data line, but this time the data has to change in the middle of the low part of the clock cycle

----------------------------------------------------------------------------------
-- PMOD_AD5 - an attempt at configuring the Digilent PMOD_AD5 over SPI
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity pmod_ad5 is
    Port ( clk50MHz  : in  STD_LOGIC;
           pmod_sclk : out STD_LOGIC := '1';
           pmod_mosi : out STD_LOGIC := '1';
           pmod_miso : in  STD_LOGIC;
           pmod_cs   : out STD_LOGIC := '1';
           samples   : OUT  std_logic_vector(23 downto 0)
);
end pmod_ad5;
 
architecture Behavioral of pmod_ad5 is
   signal counter : unsigned(5 downto 0) := (others => '0');
   signal cs_shift_reg   : std_logic_vector(63 downto 0) := x"FF00FFFFFFFFFFFF";
   signal mosi_shift_reg : std_logic_vector(63 downto 0) := x"00A5000000000000";
begin
 
p: process(clk50Mhz)
   begin
      if rising_edge(clk50MHz) then
         -- First off, generate a 1MHz square wave for SCLK;
         -- I haven't checked how fast the SPI interface works, so check this on the datasheet.
         if counter = 49 then
            pmod_sclk <= '1';
            counter <= (others => '0');
         else
           -- change the CS signal when SCLK is high
           if counter = 12 then
              -- Output the highest bit and advance the shift register
              pmod_cs <= cs_shift_reg(cs_shift_reg'high);
              cs_shift_reg <= cs_shift_reg(cs_shift_reg'high-1 downto 0) & '1';
           end if;
           if counter = 24 then
              pmod_sclk <= '0';
           end if;
 
           if counter = 37 then
              -- Output the highest bit and advance the shift register
              pmod_mosi <= mosi_shift_reg(mosi_shift_reg_shift_reg'high);
              mosi_shift_reg_shift_reg <= mosi_shift_reg_shift_reg(mosi_shift_reg_shift_reg'high-1 downto 0) & '1';
           end if;
           counter <= counter + 1;
         end if;
      end if;
   end process;
 
end Behavioral;

When you simulate that you should get something that looks like the SPI transfer on page 9 of the datasheet.

 

(I just picked 'A5' as a pleasing bit pattern to send out, so I can see where the transitions are relative to the other signals)

 

Time for me to read some more of the data sheet....

Share this post


Link to post
Share on other sites
  • 0

So here's my first error, readying page 34, SCLK should be high when idle, as this lowers the noise and power. So here are some minor tweaks to get it all looking correct in the simulation

 

----------------------------------------------------------------------------------
-- PMOD_AD5 - an attempt at configuring the Digilent PMOD_AD5 over SPI
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity pmod_ad5 is
    Port ( clk50MHz  : in  STD_LOGIC;
           pmod_sclk : out STD_LOGIC := '1';
           pmod_mosi : out STD_LOGIC := '1';
           pmod_miso : in  STD_LOGIC;
           pmod_cs   : out STD_LOGIC := '1';
           samples   : OUT  std_logic_vector(23 downto 0)
);
end pmod_ad5;
 
architecture Behavioral of pmod_ad5 is
   signal counter : unsigned(5 downto 0) := (others => '0');
   signal cs_shift_reg   : std_logic_vector(63 downto 0) := x"FF007FFFFFFFFFFF";
   signal mosi_shift_reg : std_logic_vector(63 downto 0) := x"00A5000000000000";
begin
 
p: process(clk50Mhz)
   begin
      if rising_edge(clk50MHz) then
         -- First off, generate a 1MHz square wave for SCLK;
         -- I haven't checked how fast the SPI interface works, so check this on the datasheet.
         if counter = 49 then
            pmod_sclk <= '1';
            counter <= (others => '0');
         else
           -- change the CS signal when SCLK is high
           if counter = 12 then
              -- Output the highest bit and advance the shift register
              pmod_cs <= cs_shift_reg(cs_shift_reg'high-1);
              cs_shift_reg <= cs_shift_reg(cs_shift_reg'high-1 downto 0) & '1';
           end if;
           if counter = 24 then
              pmod_sclk <= cs_shift_reg(cs_shift_reg'high);
           end if;
           if counter = 37 then
              -- Output the highest bit and advance the shift register
              pmod_mosi <= mosi_shift_reg(mosi_shift_reg'high-1);
              mosi_shift_reg <= mosi_shift_reg(mosi_shift_reg'high-1 downto 0) & '1';
           end if;
 
           counter <= counter + 1;
         end if;
      end if;
   end process;
 
end Behavioral;

Share this post


Link to post
Share on other sites
  • 0

Next minor detail - the AD7193 needs to have 40 '1's written to it to trigger a reset, then wait 500us after reset to become active. It needs a bit of a major refactor of the code, into "startup" and the normal function. It also requires simulating now for 700us.

 

As a bonus I've also implemented the first half of the transaction in figure 35.

 

 

----------------------------------------------------------------------------------
-- PMOD_AD5 - an attempt at configuring the Digilent PMOD_AD5 over SPI
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity pmod_ad5 is
    Port ( clk50MHz  : in  STD_LOGIC;
           pmod_sclk : out STD_LOGIC := '1';
           pmod_mosi : out STD_LOGIC := '1';
           pmod_miso : in  STD_LOGIC;
           pmod_cs   : out STD_LOGIC := '1';
           samples   : OUT  std_logic_vector(23 downto 0)
);
end pmod_ad5;
 
architecture Behavioral of pmod_ad5 is
   signal counter : unsigned(5 downto 0) := (others => '0');
   signal cs_shift_reg   : std_logic_vector(63 downto 0) := x"FF000000007FFFFF";
   signal mosi_shift_reg : std_logic_vector(63 downto 0) := x"0008280060000000";
   signal startup_timer  : unsigned(9 downto 0) := to_unsigned(600,10); -- 500us at 50Mhz;
begin
 
p: process(clk50Mhz)
   begin
      if rising_edge(clk50MHz) then
         if startup_timer = 0 then
            case counter is 
               when to_unsigned(0,6) =>
                  pmod_sclk <= '1';
               when to_unsigned(12,6) => 
                  -- change the CS signal when SCLK is high
                  -- Output the highest bit and advance the shift register
                  pmod_cs <= cs_shift_reg(cs_shift_reg'high-1);
                  cs_shift_reg <= cs_shift_reg(cs_shift_reg'high-1 downto 0) & '1';
               when to_unsigned(24,6) =>
                  pmod_sclk <= cs_shift_reg(cs_shift_reg'high);
               when to_unsigned(37,6) =>
                  -- Output the highest bit and advance the shift register
                  pmod_mosi <= mosi_shift_reg(mosi_shift_reg'high-1);
                  mosi_shift_reg <= mosi_shift_reg(mosi_shift_reg'high-1 downto 0) & '1';
               when others =>
                  NULL;
            end case;
         else
            -- Just during startup, output > 40 '1' bits to reset the ADC, then wait for at least 500us.
            pmod_mosi <= '1';
            case counter is 
               when to_unsigned(0,6) =>
                  pmod_sclk <= '1';
               when to_unsigned(12,6) => 
                  if startup_timer >= 512 then
                     pmod_cs <= '0';
                  end if;
               when to_unsigned(24,6) =>
                  if startup_timer >= 512 then
                     pmod_sclk <= '0';
                  end if;
               when to_unsigned(49,6) =>
                  startup_timer <= startup_timer - 1;
               when others =>
                  NULL;
            end case;
         end if;
         
         -- Generate the 1MHz for the SPI interface
         -- I haven't checked how fast the SPI interface works, so check this on the datasheet.
         if counter = 49 then
             counter <= (others => '0');
         else   
            counter <= counter + 1;
         end if;      
            
 
      end if;
   end process;
 
end Behavioral;

Share this post


Link to post
Share on other sites
  • 0

So, almost there. 

 

Now we need the second half of the transaction.

 

When cs_shift_reg is all ones, we know we have sent the request for data to the DAC. MOSI should be high until the data is ready. When MOSI drops, we need to send a "read" command (0x58) to the ADC, and then capture the output...

 

Humm... first things first - make it flip between requesting a conversion, and then request data: 

 

----------------------------------------------------------------------------------
-- PMOD_AD5 - an attempt at configuring the Digilent PMOD_AD5 over SPI
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity pmod_ad5 is
    Port ( clk50MHz  : in  STD_LOGIC;
           pmod_sclk : out STD_LOGIC := '1';
           pmod_mosi : out STD_LOGIC := '1';
           pmod_miso : in  STD_LOGIC;
           pmod_cs   : out STD_LOGIC := '1';
           samples   : OUT  std_logic_vector(23 downto 0)
);
end pmod_ad5;
 
architecture Behavioral of pmod_ad5 is
   signal counter : unsigned(5 downto 0) := (others => '0');
   signal cs_shift_reg   : std_logic_vector(63 downto 0) := (others => '1'); -- You can put init commands here if you want
   signal mosi_shift_reg : std_logic_vector(63 downto 0) := (others => '1'); -- You can put init commands here if you want
   signal startup_timer  : unsigned(9 downto 0) := to_unsigned(600,10); -- 500us at 50Mhz;
   signal sent_command    : std_logic := '0';
begin
 
p: process(clk50Mhz)
   begin
      if rising_edge(clk50MHz) then
         if startup_timer = 0 then
            case counter is 
               when to_unsigned(0,6) =>
                  pmod_sclk <= '1';
               when to_unsigned(12,6) => 
                  -- change the CS signal when SCLK is high
                  -- Output the highest bit and advance the shift register
                  pmod_cs <= cs_shift_reg(cs_shift_reg'high-1);
                  cs_shift_reg <= cs_shift_reg(cs_shift_reg'high-1 downto 0) & '1';
               when to_unsigned(24,6) =>
                  pmod_sclk <= cs_shift_reg(cs_shift_reg'high);
               when to_unsigned(37,6) =>
                  -- Output the highest bit and advance the shift register
                  pmod_mosi <= mosi_shift_reg(mosi_shift_reg'high-1);
                  mosi_shift_reg <= mosi_shift_reg(mosi_shift_reg'high-1 downto 0) & '0';
               when to_unsigned(49,6) =>
                  if cs_shift_reg = x"FFFFFFFFFFFFFFFF" then
                     if sent_command = '0' then
                        -- send the start conversion command
                        cs_shift_reg   <= x"FF000000007FFFFF";
                        mosi_shift_reg <= x"0008280060000000";
                        sent_command  <= '1';
                     elsif pmod_miso = '0' then     
                        -- Send the read data command
                        cs_shift_reg   <= x"FF000000007FFFFF";
                        mosi_shift_reg <= x"0058000000000000";
                        sent_command  <= '0';
                     end if;
                  end if;
               when others =>
                  NULL;
            end case;
         else
            -- Just during startup, output > 40 '1' bits to reset the ADC, then wait for at least 500us.
            pmod_mosi <= '1';
            case counter is 
               when to_unsigned(0,6) =>
                  pmod_sclk <= '1';
               when to_unsigned(12,6) => 
                  if startup_timer >= 512 then
                     pmod_cs <= '0';
                  end if;
               when to_unsigned(24,6) =>
                  if startup_timer >= 512 then
                     pmod_sclk <= '0';
                  end if;
               when to_unsigned(49,6) =>
                  startup_timer <= startup_timer - 1;
               when others =>
                  NULL;
            end case;
         end if;
         
         -- Generate the 1MHz for the SPI interface
         -- I haven't checked how fast the SPI interface works, so check this on the datasheet.
         if counter = 49 then
             counter <= (others => '0');
         else   
            counter <= counter + 1;
         end if;      
            
 
      end if;
   end process;
 
end Behavioral;

 

Next step is to capture the bits from the ADC, and move them to 'sample' at the correct time....

Share this post


Link to post
Share on other sites
  • 0

The easy way is to capture the MISO signal when the sclk signal is raised, and then sample the caputured bits in this register when we start the next conversion. And that should be it - now would be the time to re-read the datasheet closely, paying special attention to the registers, timing and clock speeds, verifying everything against the simulation traces, and then hit boards & logic analyzer to debug it.

----------------------------------------------------------------------------------
-- PMOD_AD5 - an attempt at configuring the Digilent PMOD_AD5 over SPI
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity pmod_ad5 is
    Port ( clk50MHz  : in  STD_LOGIC;
           pmod_sclk : out STD_LOGIC := '1';
           pmod_mosi : out STD_LOGIC := '1';
           pmod_miso : in  STD_LOGIC;
           pmod_cs   : out STD_LOGIC := '1';
           samples   : OUT  std_logic_vector(23 downto 0)
);
end pmod_ad5;
 
architecture Behavioral of pmod_ad5 is
   signal counter : unsigned(5 downto 0) := (others => '0');
   signal cs_shift_reg   : std_logic_vector(63 downto 0) := (others => '1'); -- You can put init commands here if you want
   signal mosi_shift_reg : std_logic_vector(63 downto 0) := (others => '1'); -- You can put init commands here if you want
   signal miso_shift_reg : std_logic_vector(63 downto 0) := (others => '0'); 
   signal startup_timer  : unsigned(9 downto 0) := to_unsigned(600,10); -- 500us at 50Mhz;
   signal sent_command    : std_logic := '0';
begin
 
p: process(clk50Mhz)
   begin
      if rising_edge(clk50MHz) then
         if startup_timer = 0 then
            case counter is 
               when to_unsigned(0,6) =>
                  pmod_sclk <= '1';
                  -- Correct time to capture data ison the rising edge.
                   miso_shift_reg <= miso_shift_reg(miso_shift_reg'high-1 downto 0) & pmod_miso;
               when to_unsigned(12,6) => 
                  -- change the CS signal when SCLK is high
                  -- Output the highest bit and advance the shift register
                  pmod_cs <= cs_shift_reg(cs_shift_reg'high-1);
                  cs_shift_reg <= cs_shift_reg(cs_shift_reg'high-1 downto 0) & '1';
               when to_unsigned(24,6) =>
                  pmod_sclk <= cs_shift_reg(cs_shift_reg'high);
               when to_unsigned(37,6) =>
                  -- Output the highest bit and advance the shift register
                  pmod_mosi <= mosi_shift_reg(mosi_shift_reg'high-1);
                  mosi_shift_reg <= mosi_shift_reg(mosi_shift_reg'high-1 downto 0) & '0';
               when to_unsigned(49,6) =>
                  if cs_shift_reg = x"FFFFFFFFFFFFFFFF" then
                     if sent_command = '0' then
                        -- we should have all the data bits in mosi_shift_reg, so latch it
                        samples <= mosi_shift_reg(23 downto 0);
                        -- send the start conversion command
                        cs_shift_reg   <= x"FF000000007FFFFF";
                        mosi_shift_reg <= x"0008280060000000";
                        sent_command  <= '1';
                     elsif pmod_miso = '0' then     
                        -- Send the read data command
                        cs_shift_reg   <= x"FF000000007FFFFF";
                        mosi_shift_reg <= x"0058000000000000";
                        sent_command  <= '0';
                     end if;
                  end if;
               when others =>
                  NULL;
            end case;
         else
            -- Just during startup, output > 40 '1' bits to reset the ADC, then wait for at least 500us.
            pmod_mosi <= '1';
            case counter is 
               when to_unsigned(0,6) =>
                  pmod_sclk <= '1';
               when to_unsigned(12,6) => 
                  if startup_timer >= 512 then
                     pmod_cs <= '0';
                  end if;
               when to_unsigned(24,6) =>
                  if startup_timer >= 512 then
                     pmod_sclk <= '0';
                  end if;
               when to_unsigned(49,6) =>
                  startup_timer <= startup_timer - 1;
               when others =>
                  NULL;
            end case;
         end if;
         
         -- Generate the 1MHz for the SPI interface
         -- I haven't checked how fast the SPI interface works, so check this on the datasheet.
         if counter = 49 then
             counter <= (others => '0');
         else   
            counter <= counter + 1;
         end if;      
 
      end if;
   end process;
 
end Behavioral;

Share this post


Link to post
Share on other sites
  • 0

Hi Mr Mike,

Thanks a lot for this explanation..Since I am just a beginner most of the codes pass over my head though i understood what you intended to do..So basically I need to activate the clock of the ADC using the clock divider ( from datasheet 2.4KHz)...then the ADC converts the input analog data at this rate...then how will I know conversion is over?? am still confused :/

Share this post


Link to post
Share on other sites
  • 0

Oh, sorry - they are none-standard acronyms that a lot of people use.

 

MISO is "Master In, Slave Out" (i.e. serial data from the ADC to the FPGA), MOSI is "Master Out Slave In" (i.e data from the FPGA to the ADC).  So connect MOSI to the ADC's data in pin, and MISO to the ADC's data out.

 

For me they are far more intuitive to use than "data_in" and "data_out", which depend on your frame of reference.

 

From the details in the datasheet, we know that data is ready when the ADC's DOUT signal goes from high to low.

Share this post


Link to post
Share on other sites
  • 0

As per page 11 of the data sheet:

 

CS - Chip Select Input. This is an active low logic input used to select the ADC. CS can be used to select the ADC in
systems with more than one device on the serial bus or as a frame synchronization signal in communicating
with the device. CS can be hardwired low, allowing the ADC to operate in 3-wire mode with SCLK, DIN, and
DOUT used to interface with the device.
 
As per page 12 of the data sheet:
 
SYNC - Logic input that allows for synchronization of the digital filters and analog modulators when using a number
of AD7193 devices. While SYNC is low, the nodes of the digital filter, the filter control logic, and the calibration
control logic are reset, and the analog modulator is also held in its reset state. SYNC does  not affect the digital
interface but does reset RDY to a high state if it is low. SYNC has a pull-up resistor internally to DVDD.
 
As per page 12 of the datasheet:
 
DOUT/RDY operates as a data ready pin, going low to indicate
the completion of a conversion
 
It's all in there!
 
Oh, and why 49? Well it takes 50 cycles to count from 0 to 49. So when using a 50 MHz system clock counting to 49 is a good way to generate a 1 MHz SPI clock.
 
 

Share this post


Link to post
Share on other sites
  • 0

Hi,

Yea its all in there...but I realised that the datasheet is 56 pages long so I was just going over it quickly...thus i missed almost all the relevant parts...Now I can see a clear picture..I hope the programming is ok :) Thanks a lot for your guidance :) and keep up the good work (Y)

Share this post


Link to post
Share on other sites
  • 0

Hi 1116345,

 
Hamster has given a great explanation (as he always does) on how to get the code for your FPGA up and running, but there are a couple more external hardware things that you'll need to do.
 
The PmodAD5 uses Analog Devices AD7193 to do all of the analog-to-digital conversion. However, this particular chip only takes analog inputs as a differential pair. By default, it expects that you would be pairing AIN1 (A1 on the 6x2 female header) with AIN2 (A2 on the 6x2 female header).  
 
It also expects that you supply a reference voltage on the AVDD pin (something between 3V and 5.25V) and a ground reference voltage on the ground pin (0V) that are on header J4.
 
Since you are using a light sensor, you will likely want to change the gain from the default of 128 to a gain of 1 in order to allow your analog input to have a wider range with respect to the analog voltage reference. To do this, you would need to write to the last three bits in the configuration register (pg 27) to 000 in order to have a gain of 1. If your reference voltage (AVDD on header J4) is 5V, this will allow you to have an maximum input voltage of up to 3.75V (from page 32 under Programmable Gain Array).
 
Please let me know if you have any more questions.
 
Thanks,
JColvin

Share this post


Link to post
Share on other sites
  • 0

Hi Mr JColvin,

Thanks for the precious information but one thing bothering me is the analog input, can't I use it as 8 different inputs??? Because I need to convert 6 values to digital  values.

Share this post


Link to post
Share on other sites
  • 0

Hi,

The datasheet says if i want to use the 8 analog inputs, pseudo bit must be set to 1...I have no idea how to do so??? Do I have to send a control word to the AD5??

Share this post


Link to post
Share on other sites
  • 0

The Pseudo bit is in the Configuration Register (register '010' ), bit 18 (page 27 of the datasheet). The power-on-reset value for the register is 0x000117. We want it set to 0x040117 (well, if we only want to set the Pseudo bit), or 0x040110 if the gain of 1x is desired, as per Mr Colvin's post.

 

To do this, we need to write over the SPI interface. Whenever a new write to the ADC occurs, the first byte goes to the Communications Register (see page 22). These are the bits that need to be sent:

 

0 - active low write enable for the Communication Register

0 - active low write command

0 - REN(2),- The address of the register to write to

1 - REN(1) - The address of the register to write to

0 - REN(0) - The address of the register to write to

0 - continuous read off.

0 0 - must be 0.

 

This is then followed up with the data that will be written to the Configuration Register ( in this case - 0x040110)

 

So the stream of bits we want to send out are:

0001 0000 0000 0100 0000 0001 0001 0000

 

In the FPGA design code above,this can be done by setting the initial values of the shift registers:

 

   signal cs_shift_reg   : std_logic_vector(63 downto 0) :=   x"FF000000007FFFFF";
   signal mosi_shift_reg : std_logic_vector(63 downto 0) := x"0010040110000000";

[code=auto:0]

 

So here what it looks like in simulation, as these registers are written while the design starts up:

 

post-35-0-73711500-1417770637_thumb.gif

 

Just to reiterate, I don't have access to the PMOD, so all of this code has not been tested other than by me eyeballing that the simulation waveforms match what I think they should look like. You will need to do a lot of checking against the datasheet - you will need to read it very closely, and double check everything! 

 

Also, my initial understanding was that you only needed to read only one channel. To read many channels the design will get a lot more complex and may need to be structured differently, to include a more complex FSM to switch to different channels.

 

Mike

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now