Interfacing an ADC to an FPGA through 3-wire SPI

Thread Starter

Obanion

Joined Nov 26, 2009
24
Edit: solved. Count == 13 should be changed to count == 14 for proper operation. The guys at the Altera forum helped me out, so if you're curious the code can be found there.

Hi guys,

I'm writing some Verilog code to interface a simple 12-bit serial ADC to an FPGA and I have some questions about my methodology. The ADC that I'm using is the ADS7818 (http://focus.ti.com/lit/ds/symlink/ads7818.pdf)

I think the code should be very simple, but I just want to get a second opinion so I don't end up in the wrong direction. Basically, here's what I think should be done.

1. Since the ADC is going to be operating at its full 500 KSPS, my input clock needs to be 8 MHz. This is going to be fed into the ADC at all time. For this reason, I think I should be using the DSP Interface Timing style on page 12 of the datasheet.

2. Make a simple counter than counts up to 16 and then resets after that. This counter is operating at 8 MHz. This will allow me to keep track of all the current clock cycle, so I can grab the data and know when to assert the CONV.

3. CONV will be asserted 0 when the falling edge of the CLK = 15 is present. At the falling edge CLK = 16, the CONV is asserted 1.

4. At the falling edge of CLK = 1, I will grab the data and place them into the register. I will stop at CLK = 13, and at CLK = 13, I will put them into a another register.

5. I will assert a ready signal (RDY) at the rising edge of CLK = 14 and make it low at the rising edge of CLK = 1. This RDY signal will tell my other modules that the data is ready and valid. My other modules, however, will be operating at 200 MHz, but the clock should be synchronized

6. Everything will now repeat.

Does this seem like it would work? I've never worked with SPI or external devices, nor have I ever written code from a timing diagram.

In case you're interested, my code can be seen below.

Thanks!

Rich (BB code):
//register declarations
    reg conv;
    reg rdy;
    reg [3:0] count;
    reg [11:0] data_temp;
    reg [11:0] tmp;
    
    //The clock counter. Starts at 0, so clock is from 0-15 instead of 1-16.
    always @ (posedge CLOCK_8)
        begin
            count <= count + 1;
        end
    
    //Assert the CONV signal
    always @ (negedge CLOCK_8)
        begin
            if ((count == 14) || (count == 15))
                conv = 1'b0;
            else 
                conv = 1'b1;
        end                
    
    //Read the serial data into a 12-bit register. Afterwards, convert it to parallel if the count is 13 (end of data stream)
    always @ (negedge CLOCK_8)
        begin
            if (count == 13)
                tmp <= data_temp;
            case (count)
                1: data_temp[11] <= serial_data;
                2: data_temp[10] <= serial_data;
                3: data_temp[9] <= serial_data;
                4: data_temp[8] <= serial_data;
                5: data_temp[7] <= serial_data;
                6: data_temp[6] <= serial_data;
                7: data_temp[5] <= serial_data;
                8: data_temp[4] <= serial_data;
                9: data_temp[3] <= serial_data;
                10: data_temp[2] <= serial_data;
                11: data_temp[1] <= serial_data;
                12: data_temp[0] <= serial_data;
            endcase
            
        end
 
Last edited:
Top