2
\$\begingroup\$

I have an ADC (ADS1672 datasheet) (20MHz) with serial interface and xilinx spartan 3 XC3S400-208 (50MHz)

In its datasheet to data retrieval comes this:

data retrieval from ads1672

for that I implemented this code:

inputs and outputs:

input wire DRDY;
input DOUT;
input OTRD;
input wire SCLK;
output CS_ADS;
output reg START;
output [1:0]DRATE;
output FPATH;
output LL_CONFIG;
output LVDS;
output SCLK_SEL;
output PDWN;

reg DRDY1=0,DRDY0=0;
reg [4:0] ADS_bit=0;
reg [23:0] ADS_buff=24'b0000_0000_0000_0000_0000_0000;
reg [23:0] ADS_buff_last=24'b0000_0000_0000_0000_0000_0000;
reg onetime =1'b1;

parameters:

parameter PWRDWN=1'b0, PWRUP=1'b1 , FPATH_LowLatency=1'b1 , FPATH_WideBand=1'b0 , LL_CONFIG_SingleCycle=1'b0 , LL_CONFIG_FastResponse=1'b1;
parameter DRATE_00=2'b00 ,DRATE_01=2'b01 , DRATE_10=2'b10 , DRATE_11=2'b11, SCLK_SEL_Internal=1'b0 , SCLK_SEL_External=1'b1 , LVDS_LVDS=1'b0 ,LVDS_CMOS=1'b1;

Configuration:

assign DRATE            = DRATE_00;
assign FPATH            = FPATH_LowLatency;
assign LL_CONFIG        = LL_CONFIG_SingleCycle;
assign LVDS             = CMOS;
assign SCLK_SEL         = SCLK_SEL_Internal;
assign PDWN             = PWRUP;
assign CS_ADS           = 1'b0;
assign START            = 1'b1;

Data Retrieval segment:

always @(posedge SCLK)
begin
    START<=1'b1;     //hold start hi

    DRDY1   <=  DRDY;
    DRDY0   <=  DRDY1;

    if((DRDY1==1) && (DRDY0==0))     //rising edge of DRDY to start retrieval
        begin
            ADS_buff[23]<=DOUT;    //First bit is comes with posedge DRDY
            ADS_bit<=5'd23;    //bit index Counter
            onetime<=1'b0;
        end
    else if(ADS_bit==5'b00000 && onetime==1'b0)
        begin
            ADS_buff_last<=ADS_buff[23:0];    //Update last final buffer value
            ADS_buff<=24'b0;     //flush buffer
            onetime<=1'b1;     // to prevent run this again
        end
    
    if(ADS_bit!=5'b00000)
        begin
            ADS_buff[ADS_bit-1]<=DOUT;     //get data
            ADS_bit<=ADS_bit-1'b1;     //count down (MSB to LSB)
        end
end

when i set SCLK internally (i means by SCLK_SEL=0,make ads1672 to generate it), i never get right value(values are not zero)

but when i set it externally (and generate SCLK from FPGA) by same Data Retrieval some times i get right value and some times zero!!

just difference is frequency, when it is externally it is 12.5 MHz. and when it's internally it is 19.9 MHz.

SCLK Generator (for when it is externally):

always @(posedge main_clk)
begin
    SCLK_cnt <= SCLK_cnt + 8'd1;
    if(SCLK_cnt>=(8'd4-1))       //divide per 4(50MHz/4=12.5MHz)
        SCLK_cnt <= 8'd0;
end
assign SCLK = (SCLK_cnt<8'4/2)?1'b0:1'b1;

any body have idea why this happen?

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

You have three clocks, your FPGA (50MHz) clock your ADS1672 clock and your shift clock. In a case like this where your system clock is much higher the best approach is to run a fully synchronous system and use a sort of 'oversampling'.

If you make your SCLK identical to you ADS1672 clock, you have only two clocks to cope with: FPGA and 12.5MHz.

You still generate the ADS1672 12.5MHz clock, but you don't use that signal in your FPGA as clock. Instead you sample all the inputs just before you set the ADS1672 clock high. That gives the ADS1672 the maximum time to get the signals out en into your FPGA.

I can't write all the code but it comes down to this: (Not tested!)

reg [1:0] clk_div;            // Divide by four
wire      ADC_clk=clk_div[1]; // FPGA clock/4 
reg       ADC_sclk;

always @(posedge clk or <your reset>)
begin
    if ( <your reset>)
      ... clear all your registers
    else
    begin
       clk_div <= clk_div+1;
       if (clk_div==2'b01)
       begin
          // Next cycle ADC clock goes high
          // At this moment we can read the inputs
          // They have had maximum time to get stable
          // ALL code to do with the interface (except shift clock) comes here.
          ........
       end

       // Here is you shift clock
       if (sclk_on)
       begin
          if (clk_div==2'b01)
             ADC_sclk<= 1'b1;
          if (clk_div==2'b11)
             ADC_sclk<= 1'b0;
       else
          ADC_sclk<= 1'b0;
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.