ADS8515的verilog驱动(原创)
0赞ADS8515是一个16位,250kbps采样率,逐次比较型AD。
输入电压范围为正负10V,并行输出,具体描述如图1。
图 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相符。