本设计采用8通道adc7606b的硬件模式,并行输出模式。
ad7606b硬件电路图部分如下
adc并行模式时序图如下,截自datasheet,
根据硬件电路与时序图写出verilog代码,modelsim仿真后用quartus编译综合。
module design_8ad(
input clk,
input rst_n,
output [2:0] os,
output reg adc_cvt,
output adc_rst,
output reg rd,
output reg cs,
input busy,
input [15:0] ad_data,
output reg [2:0] state_c,
output reg flag ,
output watch,
output add
);
localparam IDLE =3'D0,
CVT =3'D1,
BUSY =3'D2,
RD_ST =3'D3,
GET_DATA=3'D4;
reg [15:0] ch1;
reg [15:0] ch2;
reg [15:0] ch3;
reg [15:0] ch4;
reg [15:0] ch5;
reg [15:0] ch6;
reg [15:0] ch7;
reg [15:0] ch8;
reg [2:0] state_n;
wire get_data_en;//dingyi
reg [7:0] cnt_mum;
reg [1:0] cnt_cvt;
reg [2:0] cnt_ch;
assign os=3'd0;
assign adc_rst=~rst_n;
assign get_data_en=(cnt_mum==8'd249);
integer i;
reg [3:0] cnt_watch;
always @ (posedge clk or negedge rst_n) begin
if(~rst_n)
cnt_watch<='d0;
else
cnt_watch<=cnt_watch+1'd1;
end
assign watch=cnt_watch[3];
always @ (posedge clk or negedge rst_n) begin
if(~rst_n)
cnt_mum<='d0;
else begin
if(cnt_mum==8'd249)
cnt_mum<='d0;
else
cnt_mum<=cnt_mum+1'd1;
end
end
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
state_c<=IDLE;
end
else begin
state_c<=state_n;
end
end
always @ (*) begin
state_n=state_c;
case (state_c)
IDLE :begin
if(get_data_en)
state_n=CVT;
end
CVT :begin
if(adc_cvt)
state_n=BUSY;
end
BUSY :begin
if(~busy)
state_n=RD_ST;
end
RD_ST : state_n=GET_DATA;
GET_DATA:begin
if(flag)
state_n=IDLE;
end
default: state_n=IDLE;
endcase
end
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
cs<=1'd1;
adc_cvt<='d0;
cnt_cvt<='d0;
rd<='d1;
flag<='d0;
ch1<='d0;
ch2<='d0;
ch3<='d0;
ch4<='d0;
ch5<='d0;
ch6<='d0;
ch7<='d0;
ch8<='d0;
end
else
begin
case(state_c)
IDLE :begin
cs<=1'd1;
cnt_cvt<='d0;
adc_cvt<='d0;
rd<=1'd1;
cnt_ch<='d0;
flag<='d0;
end //hou mian bu chong
CVT :begin
if(cnt_cvt<2)
cnt_cvt<=cnt_cvt+1'd1;
else begin
adc_cvt<=1'd1;
cnt_cvt<='d0;
end
end
RD_ST :
cs<='d0;
GET_DATA:begin
if(rd)
rd<='d0;
else begin
rd<='d1;
cnt_ch<=cnt_ch+1'd1;
case (cnt_ch)
3'd0:ch1<=ad_data;
3'd1:ch2<=ad_data;
3'd2:ch3<=ad_data;
3'd3:ch4<=ad_data;
3'd4:ch5<=ad_data;
3'd5:ch6<=ad_data;
3'd6:ch7<=ad_data;
3'd7:ch8<=ad_data;
endcase
end
if(cnt_ch==3'd7)//zhuyi
flag<=1'd1;
end
endcase
end
end
assign add=^ch1+^ch2+^ch3+^ch4+^ch5+^ch6+^ch7+^ch8;
endmodule
ps:因为使用quartus single tap 抓波形,所以附加了一部分逻辑,代码内部有部分逻辑可在实际应用时删除,大家可自行根据需要改动。
附上设计和tb代码(PS:下图设计模块代码与上图唯一区别是ch1~ch8放入output中,在fpga设计中不可综合因为输出引脚过多)
module design_8ad(
input clk,
input rst_n,
output [2:0] os,
output reg adc_cvt,
output adc_rst,
output reg rd,
output reg cs,
input busy,
input [15:0] ad_data,
output reg [15:0] ch1,
output reg [15:0] ch2,
output reg [15:0] ch3,
output reg [15:0] ch4,
output reg [15:0] ch5,
output reg [15:0] ch6,
output reg [15:0] ch7,
output reg [15:0] ch8,
output reg [2:0] state_c,
output reg flag ,
output watch,
output add
);
localparam IDLE =3'D0,
CVT =3'D1,
BUSY =3'D2,
RD_ST =3'D3,
GET_DATA=3'D4;
reg [2:0] state_n;
wire get_data_en;//dingyi
reg [7:0] cnt_mum;
reg [1:0] cnt_cvt;
reg [2:0] cnt_ch;
assign os=3'd0;
assign adc_rst=~rst_n;
assign get_data_en=(cnt_mum==8'd249);
integer i;
reg [3:0] cnt_watch;
always @ (posedge clk or negedge rst_n) begin
if(~rst_n)
cnt_watch<='d0;
else
cnt_watch<=cnt_watch+1'd1;
end
assign watch=cnt_watch[3];
always @ (posedge clk or negedge rst_n) begin
if(~rst_n)
cnt_mum<='d0;
else begin
if(cnt_mum==8'd249)
cnt_mum<='d0;
else
cnt_mum<=cnt_mum+1'd1;
end
end
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
state_c<=IDLE;
end
else begin
state_c<=state_n;
end
end
always @ (*) begin
state_n=state_c;
case (state_c)
IDLE :begin
if(get_data_en)
state_n=CVT;
end
CVT :begin
if(adc_cvt)
state_n=BUSY;
end
BUSY :begin
if(~busy)
state_n=RD_ST;
end
RD_ST : state_n=GET_DATA;
GET_DATA:begin
if(flag)
state_n=IDLE;
end
default: state_n=IDLE;
endcase
end
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
cs<=1'd1;
adc_cvt<='d0;
cnt_cvt<='d0;
rd<='d1;
flag<='d0;
ch1<='d0;
ch2<='d0;
ch3<='d0;
ch4<='d0;
ch5<='d0;
ch6<='d0;
ch7<='d0;
ch8<='d0;
end
else
begin
case(state_c)
IDLE :begin
cs<=1'd1;
cnt_cvt<='d0;
adc_cvt<='d0;
rd<=1'd1;
cnt_ch<='d0;
flag<='d0;
end //hou mian bu chong
CVT :begin
if(cnt_cvt<2)
cnt_cvt<=cnt_cvt+1'd1;
else begin
adc_cvt<=1'd1;
cnt_cvt<='d0;
end
end
RD_ST :
cs<='d0;
GET_DATA:begin
if(rd)
rd<='d0;
else begin
rd<='d1;
cnt_ch<=cnt_ch+1'd1;
case (cnt_ch)
3'd0:ch1<=ad_data;
3'd1:ch2<=ad_data;
3'd2:ch3<=ad_data;
3'd3:ch4<=ad_data;
3'd4:ch5<=ad_data;
3'd5:ch6<=ad_data;
3'd6:ch7<=ad_data;
3'd7:ch8<=ad_data;
endcase
end
if(cnt_ch==3'd7)//zhuyi
flag<=1'd1;
end
endcase
end
end
assign add=^ch1+^ch2+^ch3+^ch4+^ch5+^ch6+^ch7+^ch8;
endmodule
module my_8ad_tb ();
reg clk ;
reg rst_n ;
wire adc_cvt;
wire rd ;
wire cs ;
reg busy ;
reg [15:0] ad_data;
wire [15:0] ch1 ;
wire [15:0] ch2 ;
wire [15:0] ch3 ;
wire [15:0] ch4 ;
wire [15:0] ch5 ;
wire [15:0] ch6 ;
wire [15:0] ch7 ;
wire [15:0] ch8 ;
wire flag ;
wire [2:0] state_c;
design_8ad tb(
.clk (clk ),
.rst_n (rst_n ),
.adc_cvt (adc_cvt),
.rd (rd ),
.cs (cs ),
.busy (busy ),
.ad_data (ad_data),
.ch1 (ch1 ),
.ch2 (ch2 ),
.ch3 (ch3 ),
.ch4 (ch4 ),
.ch5 (ch5 ),
.ch6 (ch6 ),
.ch7 (ch7 ),
.ch8 (ch8 ),
.flag (flag ),
.state_c (state_c)
);
initial begin
clk=1'd1;
rst_n='d0;
ad_data='d0;
busy='d0;
#100;
rst_n=1'd1;
#250000;
$stop;
end
always #10 clk=~clk;
always @ (posedge adc_cvt)
begin
#1 busy <=1'd1;
#800 busy <=1'd0;
end
always @ (negedge rd)
#5 ad_data<=ad_data+1'd1;
endmodule
仿真波形
modelsim验证无误后我用的是max10系列fpga 用quartus综合,也用过spartan6使用ise,具体用哪个软件看自己选择的芯片:
用quartus,建立工程,命名顶层模块,选择芯片,建立工程完成。addfiles,把设计添加进去,编译一遍,分配引脚,再编译。导入fpga,用示波器测adc输出引脚就能看到有规律波形,则表明编译没有问题,adc已经可以工作。打开single tap 设置采样时钟和采样信号,完成后再编译导入fpga,可以捕捉到波形
可以设置多比特数组的进制,我设置的是有符号十进制源码,系统默认是十六进制。
综合后我用的quartus singletap 抓波形,用信号发生器给正弦波和方波,抓到数后导出数据,用excle折线图绘制,成功还原出原波形。
示波器波形
还原出波形
ps:信号发生器产生的波形频率应符合设计的采样频率范围
/*******************************************************************************/
这是本人第一次在csdn发文章,水平尚且有限,目前尚处于学习阶段,希望我的经验能够给后来的同学们起到一个指导的作用。大家有什么意见和建议欢迎评论指出。大家的鼓励会是我以后发文的动力,谢谢大家。