解决的疑问主要有一下几点:
(1)之前一直困惑于如何确定AD的采样频率,后来在朋友的提示下,在程序中加入了定时器,每50us读取一次数据,实现采样频率变为20K。
(2)对ad_reset信号,之前一直以为计数器记满之后,会自动复位,似的该信号会马上变为高电平,仿真后才发现并未如此,满量程的计数器将会一直保持在ff的状态,使得ad-reset信号保持为低,也就进入了循环采样的状态。cnt计数器只是对ad复位进行操作,这正决定采样频率的是cnt50us计数器。
(3)使用$random函数模拟采样信号,使得仿真结果更真实可观。
ad的采样程序如下:
`timescale 1ns / 1ns
//////////////////////////////////////////////////////////////////////////////////
// Module Name: ad7606
//////////////////////////////////////////////////////////////////////////////////
module ad7606(
input clk, //50mhz
input rst_n,
input [15:0] ad_data, //ad7606 采样数据
input ad_busy, //ad7606 忙标志位
input first_data, //ad7606 第一个数据标志位
output [2:0] ad_os, //ad7606 过采样倍率选择
output reg ad_cs, //ad7606 AD cs
output reg ad_rd, //ad7606 AD data read
output reg ad_reset, //ad7606 AD reset
output reg ad_convstab, //ad7606 AD convert start
output reg [15:0] ad_ch1, //AD第1通道的数据
output reg [15:0] ad_ch2, //AD第2通道的数据
output reg [15:0] ad_ch3, //AD第3通道的数据
output reg [15:0] ad_ch4, //AD第4通道的数据
output reg [15:0] ad_ch5, //AD第5通道的数据
output reg [15:0] ad_ch6, //AD第6通道的数据
output reg [15:0] ad_ch7, //AD第7通道的数据
output reg [15:0] ad_ch8, //AD第8通道的数据
output reg [3:0] state
//output reg [3:0] cnt
);
reg [7:0] cnt = 0 ;
reg [15:0] cnt50us = 0;
reg [5:0] i;
//reg [3:0] state;
parameter IDLE=4'd0;
parameter AD_CONV=4'd1;
parameter Wait_1=4'd2;
parameter Wait_busy=4'd3;
parameter READ_CH1=4'd4;
parameter READ_CH2=4'd5;
parameter READ_CH3=4'd6;
parameter READ_CH4=4'd7;
parameter READ_CH5=4'd8;
parameter READ_CH6=4'd9;
parameter READ_CH7=4'd10;
parameter READ_CH8=4'd11;
parameter READ_DONE=4'd12;
//parameter display=4'd13;
assign ad_os=3'b000; //无过采样
//ad复位
always@(posedge clk)
begin
if(cnt<8'hff) begin
cnt<=cnt+1;
ad_reset<=1'b1;
end
else
ad_reset<=1'b0; //计数器达到ff后停止,ad_reset恒为零
end
//使用定时器来设置采样频率
always @(posedge clk or negedge rst_n) //每50us读取一次数据,ad的采样率为20K
begin
if(rst_n == 0)
cnt50us <= 0;
else begin
if(cnt50us < 16'd2499)
begin
cnt50us <= cnt50us + 1;
end
else
cnt50us <= 0;
end
end
always @(posedge clk)
begin
if (ad_reset==1'b1) begin //初始化ad
state<=IDLE;
ad_ch1<=0;
ad_ch2<=0;
ad_ch3<=0;
ad_ch4<=0;
ad_ch5<=0;
ad_ch6<=0;
ad_ch7<=0;
ad_ch8<=0;
ad_cs<=1'b1;
ad_rd<=1'b1;
ad_convstab<=1'b1; //8通道同步采样
i<=0;
end
else begin
case(state) //need time:(20+2+5+1+3*8+1)*20ns=1060ns, fmax=1/1060ns=1MHZ
IDLE: begin
ad_cs<=1'b1;
ad_rd<=1'b1;
ad_convstab<=1'b1;
if(i==20) begin //延时20个时钟后开始转换
i<=0;
state<=AD_CONV;
end
else
i<=i+1'b1;
end
AD_CONV: begin
if(i==2) begin //等待2个lock,convstab的下降沿最少为25ns,故至少需要两个时钟
i<=0;
state<=Wait_1;
ad_convstab<=1'b1;
end
else begin
i<=i+1'b1;
ad_convstab<=1'b0; //启动AD转换
end
end
Wait_1: begin
if(i==5) begin //等待5个clock, 等待busy信号为高(tconv)
i<=0;
state<=Wait_busy;
end
else
i<=i+1'b1;
end
Wait_busy: begin
if(ad_busy==1'b0) begin //等待busy为低电平 即转换之后读取模式
i<=0;
state<=READ_CH1;
end
end
READ_CH1: begin
ad_cs<=1'b0; //cs信号有效 直到读取8通道结束
if(i==3) begin // 低电平持续3个时钟,完成通道1的读入
ad_rd<=1'b1;
i<=0;
ad_ch1<=ad_data; //读CH1
state<=READ_CH2;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_CH2: begin
if(i==3) begin
ad_rd<=1'b1;
i<=0;
ad_ch2<=ad_data; //读CH2
state<=READ_CH3;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_CH3: begin
if(i==3) begin
ad_rd<=1'b1;
i<=0;
ad_ch3<=ad_data; //读CH3
state<=READ_CH4;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_CH4: begin
if(i==3) begin
ad_rd<=1'b1;
i<=0;
ad_ch4<=ad_data; //读CH4
state<=READ_CH5;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_CH5: begin
if(i==3) begin
ad_rd<=1'b1;
i<=0;
ad_ch5<=ad_data; //读CH5
state<=READ_CH6;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_CH6: begin
if(i==3) begin
ad_rd<=1'b1;
i<=0;
ad_ch6<=ad_data; //读CH6
state<=READ_CH7;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_CH7: begin
if(i==3) begin
ad_rd<=1'b1;
i<=0;
ad_ch7<=ad_data; //读CH7
state<=READ_CH8;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_CH8: begin
if(i==3) begin
ad_rd<=1'b1;
i<=0;
ad_ch8<=ad_data; //读CH8
state<=READ_DONE;
end
else begin
ad_rd<=1'b0;
i<=i+1'b1;
end
end
READ_DONE:begin //完成读,回到idle状态
ad_rd<=1'b1;
ad_cs<=1'b1;
if(cnt50us == 16'd2499) //不加此条件,则ad完成一次读取需1280ns,采样频率781.25K,但需注意ad每通道的追高采样只能为200K
state<=IDLE;
else
state<=READ_DONE;
end
default: state<=IDLE;
endcase
end
end
endmodule
仿真测试程序如下:
`timescale 1 ns/ 1 ns
module ad7606_vlg_tst();
// constants
// general purpose registers
// test vector input registers
reg ad_busy;
reg [15:0] ad_data;
reg clk;
reg first_data;
reg rst_n;
// wires
wire [15:0] ad_ch1;
wire [15:0] ad_ch2;
wire [15:0] ad_ch3;
wire [15:0] ad_ch4;
wire [15:0] ad_ch5;
wire [15:0] ad_ch6;
wire [15:0] ad_ch7;
wire [15:0] ad_ch8;
wire ad_convstab;
wire ad_cs;
wire [2:0] ad_os;
wire ad_rd;
wire ad_reset;
wire [3:0] state;
// assign statements (if any)
ad7606 i1 (
// port map - connection between master ports and signals/registers
.ad_busy(ad_busy),
.ad_ch1(ad_ch1),
.ad_ch2(ad_ch2),
.ad_ch3(ad_ch3),
.ad_ch4(ad_ch4),
.ad_ch5(ad_ch5),
.ad_ch6(ad_ch6),
.ad_ch7(ad_ch7),
.ad_ch8(ad_ch8),
.ad_convstab(ad_convstab),
.ad_cs(ad_cs),
.ad_data(ad_data),
.ad_os(ad_os),
.ad_rd(ad_rd),
.ad_reset(ad_reset),
.clk(clk),
.first_data(first_data),
.rst_n(rst_n),
.state(state)
//.cnt(cnt)
);
initial
begin
ad_busy = 0;
first_data = 0;
clk = 0;
forever //50MHz
#10
clk = ~clk;
$display("Running testbench");
end
initial
begin
rst_n = 1;
#10;
rst_n = 0;
#20;
rst_n = 1;
end
always@(posedge clk)
begin
ad_data <= $random; //使用随机数模拟采样信号
end
endmodule
仿真结果如下: