Bless_Bigo

ADS8515的verilog驱动(原创)

0
阅读(2984)

        ADS8515是一个16位,250kbps采样率,逐次比较型AD。

        输入电压范围为正负10V,并行输出,具体描述如图1。

ADS8515器件特性.jpg

图  1  ADS8515描述 

        采用图2的接法进行操作,其中CS始终为低电平,RC作为fpga对ad的控制引脚,busy为判断ad的转换标志位。

转换过程为,当busy是高电平时,RC拉低至少40ns启动转换;

fpga通过对busy标志位的边缘检测接收数据,当busy由0到1,数据转换成功,接收数据。

        操作时序图如图3。

 

图 2 硬件电路

图 3 时序图

操作涉及到4个状态,//4 state of ad convert
AD_IDLE  = 2'd0;  //等待

AD_START  = 2'd1;  //启动转换

AD_COV = 2'd2;  //转换中
AD_RX  = 2'd3;  //转换完毕,进行数据接收。

编写verilog程序,其中边缘检测用到了bingo书上的程序,全局时钟为100Mhz。

(不得不说bingo的程序思维很棒!)

代码如下:

`timescale 1ns / 1ps
/*==============================================================================
Technology blogs    : http://blog.chinaaet.com/Bless_Bigo
Email Address       : 399287955@qq.com
Author              : Bless_Bigo
Create Date         : 1/22/2016
Module Hierarchy    : top function module
Design Name         : ADS_8515.v
Module Name         : ADS_8515
Project Name        : ADS_test_tb.qpf
Target Devices      : Altera
Tool versions       : QUARTUSII 12.0/Win7
Description         : 
Dependencies        :
Revision            : V1.0 - File Created
Additional Comments :
==============================================================================*/
/*
//----------------------------------------------
//the target component instantiation
reg ad_busy;
reg [15:0] ad_data;
wire ad_rc;
wire o_data_en;
wire [15:0] o_AD_out;

ADS_8515 ADS8515_U1
(
  //global clock
  .clk(clk),.i_rst_n(rst_n),  //100M clk
 
  //AD interface
  .i_ad_busy_n(ad_busy),
  .i_ADdata(ad_data),
  .o_AD_RC(ad_rc),
 
  //user interface
  .o_data_en(o_data_en),
  .o_AD_out(o_AD_out)
);
*/
module ADS_8515
(
  //global clock
  input clk,i_rst_n,  //100M clk
 
  //AD interface
  input i_ad_busy_n,
  input [15:0] i_ADdata,
  output reg o_AD_RC,
 
  //user interface
  output reg o_data_en,
  output reg [15:0] o_AD_out
);

//-------------------------------------
//AD data sync to fpga
reg ad_busy_r0,   ad_busy_r1;  
always@(posedge clk or negedge i_rst_n)
begin
 if(!i_rst_n)
  begin
  ad_busy_r0 <= 1;  ad_busy_r1 <= 1;  //AD wait for convert
  end
 else
  begin
  ad_busy_r0 <= i_ad_busy_n;  ad_busy_r1 <= ad_busy_r0;
  end
end
wire ad_wait_cov = ( ad_busy_r1 & ad_busy_r0) ? 1'b1 : 1'b0;  //always high of busy
wire ad_cov_rdy = (~ad_busy_r1 & ad_busy_r0) ? 1'b1 : 1'b0;  //posedge of busy

//---------------------------------------
//4 state of ad convert
localparam AD_IDLE  = 2'd0;  //detect if the ad data is begin
localparam AD_START  = 2'd1;  //ad convert start mark bit
localparam AD_COV = 2'd2;  //wait for ad convert
localparam AD_RX  = 2'd3;  //16 bits ad data receive
reg [1:0] ad_state;
reg [2:0] rc_40ns_cnt;
reg [15:0] ad_data_tmp;

localparam rc_top_40ns = 3'd4;
always@(posedge clk or negedge i_rst_n)
begin
 if(!i_rst_n)
  begin
  rc_40ns_cnt <= 0;
  o_AD_RC <= 1'b1;
  ad_state <= AD_IDLE;
  end
 else
  case(ad_state)
  AD_IDLE:  //Wait for start bit
   begin
   rc_40ns_cnt <= 0;
   if(ad_wait_cov == 1'b1)   //ad convert start bit
    begin ad_state <= AD_START; o_AD_RC <= 1'b0; end
   else
    ad_state <= AD_IDLE;
   end
  AD_START:   // wait for start RC keep low alest 40ns
   begin
     rc_40ns_cnt <= rc_40ns_cnt+1'b1;
   if(rc_40ns_cnt == rc_top_40ns)   // wait for start
      begin ad_state <= AD_COV; o_AD_RC <= 1'b1; end
   else
    ad_state <= AD_START;
   end
  AD_COV: //wait for busy puse high
    begin
      if(ad_cov_rdy == 1'b1)
        ad_state <= AD_RX;
      else
        ad_state <= AD_COV;
    end
  AD_RX:  //receive data to tmp
   begin
     ad_data_tmp = i_ADdata;
     ad_state <= AD_IDLE;
   end
  endcase
end

//----------------------------------
//reload data from ad to fpga and give a ready mark
always@(posedge clk or negedge i_rst_n)
begin
 if(!i_rst_n)
  begin o_AD_out <= 0; o_data_en <= 1'b0; end
 else if(ad_state == AD_RX)
   begin
       o_AD_out <= ad_data_tmp;
       o_data_en <= 1'b1;
   end
 else
   begin
       o_AD_out <= o_AD_out;
       o_data_en <= 1'b0;
   end
end

endmodule

 

modelsim仿真,产生一个250kbps的时钟用来模拟ad的输出,等待时busy为1,当rc=0时busy变为0,直到下一个250kbps时钟的上升沿到来表示转换完毕,busy变为1。

测试程序(tb)如下:

/*==============================================================================
Technology blogs    : http://blog.chinaaet.com/Bless_Bigo
Email Address       : 399287955@qq.com
Author              : Bless_Bigo
Create Date         : 1/22/2016
Module Hierarchy    : top function module
Design Name         : ADS_8515_test_tb.v
Module Name         : ADS_8515_test_tb
Project Name        : ADS_8515_test_tb.mpf
Target Devices      : Altera
Tool versions       : Modelsim 6.5 SE/Win7
Description         : 
Dependencies        :
Revision            : V1.0 - File Created
Additional Comments :
==============================================================================*/
`timescale 1ns/1ns
module ADS_8515_test_tb;  //----根据需要自己改!

//------------------------------------------
//clock generate module
reg clk; 
reg rst_n;
localparam PERIOD = 10; //100MHz
initial 
begin
 clk = 0;
 forever #(PERIOD/2) 
 clk = ~clk;
end

task task_reset;
begin
 rst_n = 0;
 repeat(2) @(negedge clk);
 rst_n = 1;
end
endtask

//----------------------------------------------
//the target component instantiation
reg ad_busy;
reg [15:0] ad_data;
wire ad_rc;
wire o_data_en;
wire [15:0] o_AD_out;

ADS_8515 ADS8515_U1
(
  //global clock
  .clk(clk),.i_rst_n(rst_n),  //100M clk
 
  //AD interface
  .i_ad_busy_n(ad_busy),
  .i_ADdata(ad_data),
  .o_AD_RC(ad_rc),
 
  //user interface
  .o_data_en(o_data_en),
  .o_AD_out(o_AD_out)
);

//------------------------------------------
//ad clock generate module
reg ad_clk; 
localparam ad_PERIOD = 4000; //250kHz
initial 
begin
 ad_clk = 0;
 forever #(ad_PERIOD/2) 
 ad_clk = ~ad_clk;
end

//---------------------------------------
//system initialization
task task_sysinit;
begin
  ad_busy = 1;
  ad_data = 0;
end
endtask

//ad data simulate
task  task_ad_data;
input [15:0] i_data;
begin
  ad_data=i_data;
end
endtask

//-------------------------------------
// detect posedge fo ad clk
reg ad_clk_r0,   ad_clk_r1;  
always@(posedge clk or negedge rst_n)
begin
 if(!rst_n)
  begin
  ad_clk_r0 <= 1;  ad_clk_r1 <= 1;  //AD wait for convert
  end
 else
  begin
  ad_clk_r0 <= ad_clk;  ad_clk_r1 <= ad_clk_r0;
  end
end
wire ad_clk_tmp = (~ad_clk_r1 & ad_clk_r0) ? 1'b1 : 1'b0;  //posedge of busy

always @(posedge clk)
begin
  if (ad_rc == 0)
    ad_busy <= 0;
else if (ad_clk_tmp == 1)
  ad_busy <=1 ;
else ad_busy <= ad_busy;
end

//----------------------------------------
//testbench of the RTL
initial
begin
 task_sysinit;
 task_reset;
 task_ad_data(16'h3456);
 #3000;
 task_ad_data(16'habcd);
 #5000;
 task_ad_data(16'd8888);

end

endmodule

 

run 20 000ns 仿真结果如图4。

图 4 ads8515功能仿真

从图4中可以看到当ad_busy为高电平时,ad_rc由1到0启动转换。

ad_rc低电平维持时间50ns,符合至少40ns启动时间的要求。

转换结束,ad_busy变为高电平,输出转换数据o_AD_out,并且输出接收完毕的使能标志位o_data_en给后续模块使用。

仿真结果同图3相符。