Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
14 years ago

Configuring ADC using FPGA

I am trying to configure an ADC using an FPGA. I can read the default values from the ADC register properly, but I'm unable to write to those registers.

The fpga clock is 48 MHz and serial clock for the ADC is 8 MHz. The VHDL code that I've written is given below.

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
USE IEEE.NUMERIC_STD.all;
ENTITY SPI_MASTER IS
    GENERIC
    (
        NUM : INTEGER := 24
    );
    PORT
    (    
        CLK_IN : IN STD_LOGIC;
        SPI_MASTER_SDIO : INOUT STD_LOGIC;
        SPI_MASTER_CLK : OUT STD_LOGIC;
        SPI_MASTER_CS : OUT STD_LOGIC;
        ADC_DATA_IN : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
    );
END ENTITY;
ARCHITECTURE BEHAV OF SPI_MASTER IS
    CONSTANT ADC_WRITE_REG : STD_LOGIC_VECTOR(12 DOWNTO 0) := '0' & x"008";             --WRITE REGISTER
    CONSTANT ADC_DATA : STD_LOGIC_VECTOR(7 DOWNTO 0) := x"10";                    --DATA TO WRITE
    
    CONSTANT ADC_READ_REG : STD_LOGIC_VECTOR(12 DOWNTO 0) := '0' & x"015";                --READ REGISTER
    
    SIGNAL DATA_TO_ADC : STD_LOGIC_VECTOR(NUM-1 DOWNTO 0) := '0' & "00" & ADC_WRITE_REG & ADC_DATA;
    
    SIGNAL DATA_FROM_ADC : STD_LOGIC_VECTOR(15 DOWNTO 0) := '1' & "00" & ADC_READ_REG; 
    
    SIGNAL OE : STD_LOGIC := '1';                                     --OUTPUT ENABLE FROM FPGA, WHEN HIGH: SEND DATA TO ADC, WHEN LOW: RECEIVE DATA FROM ADC
    SIGNAL DATA_IN : STD_LOGIC_VECTOR(7 DOWNTO 0) := "11111111";
    SIGNAL MASTER_RST : STD_LOGIC := '0';
    SIGNAL SENT : INTEGER := 0;            --NUM BITS SENT
    SIGNAL RCVD : INTEGER := 0;            --NUM BITS RECEIVED
    SIGNAL ADC_CLK : STD_LOGIC := '0';        --SERIAL CLOCK FOR ADC
    SIGNAL COUNT : INTEGER := 0;
    
    BEGIN
    
        PROCESS(CLK_IN)
        BEGIN
            IF(RISING_EDGE(CLK_IN)) THEN
                IF(COUNT = 2) THEN
                    ADC_CLK <= NOT ADC_CLK;
                    COUNT <= 0;
                ELSE
                    COUNT <= COUNT + 1;
                END IF;
            END IF;
        END PROCESS;
        
        PROCESS(ADC_CLK,MASTER_RST,OE)
        BEGIN
            IF(FALLING_EDGE(ADC_CLK) AND MASTER_RST = '0') THEN
                IF(OE = '1') THEN
                    IF(SENT < 23) THEN
                        --DATA_FROM_ADC <= DATA_FROM_ADC(14 DOWNTO 0) & '1';
                        DATA_TO_ADC <= DATA_TO_ADC(22 DOWNTO 0) & '1';
                        SENT <= SENT + 1;
                    ELSE
                        OE <= '0';
                    END IF;
                END IF;
            ELSIF(RISING_EDGE(ADC_CLK) AND MASTER_RST = '0') THEN
                IF(OE = '0') THEN
                    DATA_IN <= DATA_IN(6 DOWNTO 0) & SPI_MASTER_SDIO;
                    RCVD <= RCVD + 1;
                    IF(RCVD > 6) THEN
                        MASTER_RST <= '1';
                    END IF;
                END IF;
            END IF;
        END PROCESS;
        --SPI_MASTER_SDIO <= DATA_FROM_ADC(15) WHEN OE = '1' ELSE 'Z';
        SPI_MASTER_CS <= '0';
        SPI_MASTER_CLK <= ADC_CLK;
        ADC_DATA_IN <= DATA_IN;
        SPI_MASTER_SDIO <= DATA_TO_ADC(23) WHEN OE = '1' ELSE 'Z';
        
END BEHAV; 
The parts that are commented are used for reading from the ADC registers. Also when reading the "IF (sent < 23)" is changed to "IF (sent < 15)".

I used logic probes to see the output of the SCLK and SDIO pins (attached) and I don't see a problem.

I am not sure why writing to the registers does not work.

Here is the datasheet of the ADC since I couldn't upload the file:

http://www.analog.com/static/imported-files/data_sheets/ad9649.pdf (http://www.analog.com/static/imported-files/data_sheets/ad9649.pdf)

Any help/insight will be appreciated! Thanks.

14 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Yes I can control the chip select. I'll certainly give that a try, set CS high during power up and then set it low after a few clock cycles.

    --- Quote End ---

    Sounds like a good debug plan.

    --- Quote Start ---

    What bothers me is I never fail to read the correct default value of a register.

    --- Quote End ---

    Never try to interpret patterns, you'll never figure them out.

    --- Quote Start ---

    For now I have to change the address value in my VHDL code, re-compile the code, and re-program the FPGA. I would think a read would be more difficult to accomplish since the SDIO line has to change from an input to an output whereas for a write, it stays as an input line.

    --- Quote End ---

    You need to write an ADC interface controller, wrap it with a Avalon-MM registers interface, drop it into an SOPC or Qsys system, and then debug. That way you can generate reads or writes to whatever addresses you like.

    It may seem like a lot of extra work up front, but you'll benefit from it in the long run. Go through this tutorial:

    http://www.alterawiki.com/wiki/using_the_usb-blaster_as_an_sopc/qsys_avalon-mm_master_tutorial

    Cheers,

    Dave
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Even though the ADC has a mode where chip-select can be asserted low all the time, it might need it to be deasserted while being powered up.

    --- Quote End ---

    Yes, the chip misses a means to reset the SPI protocol without deasserting CS. I don't see a reliable way to operate the device without connecting CS.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    It turns out that writing to certain address requires an additional step (from the datasheet):

    transfer register map

    address 0x08 to address 0x18 are shadowed. writes to these addresses do not affect part operation until a transfer command is issued by writing 0x01 to address 0xff, setting the transfer bit. this allows these registers to be updated internally and simulta-neously when the transfer bit is set. the internal update takes place when the transfer bit is set, and then the bit autoclears.

    So now the write is working properly.

    Thanks for taking the time to look through this.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    So now the write is working properly.

    --- Quote End ---

    Great!

    However, make sure you follow Frank's and my advice; keep chip-select deasserted until your board powers up, to ensure the SPI device is initialized correctly.

    If you are developing a robust product, then you want to make sure that there are no 'hidden' issues that will show up in the future.

    Cheers,

    Dave