一、ADC128S052时序图
1.时序图
ADC128S052为12 位、8通道的模数转换器 (ADC),转换速度高达 10 MSPS,采用SPI串行通信。
(1)工作时序图
应注意DIN中配置好的通道地址ADD在下一次采样时才生效。
从时序图中可得出,ADC芯片在上升沿时采样,读取DIN数据;DOUT在下降沿时改变数据。
(2)串行时序图
片选信号在SCLK第16个上升沿时被拉高。
2.设计要点
根据时序图和数据手册,得出以下设计要点:
(1)DIN在SCLK第3、4、5个下降沿改变,发送通道值ADD,先发高位,后发低位。
(2)FPGA在SCLK上升沿时读取DOUT数据,DOUT前4位为0,在SCLK第5个上升沿开始读取DB11。
(3)SCLK时钟为3.2-8Mhz,系统时钟为50Mhz,取8分频6.25Mhz。
(4)片选信号在SCLK第16个上升沿时被拉高。
二、ADC128S052代码设计
1.模块端口说明
端口名称 | 方向 | 说明 |
---|---|---|
Clk | input | 系统时钟 |
Rst_n | input | 系统复位 |
Channel[2:1] | input | 通道选择 |
Start | input | 采集开始标志位 |
Conv_done | output | 采集完成标志位 |
DATA[11:0] | output | 采集到的并行数字信号 |
ADC_CS_N | output | ADC片选 |
ADC_DIN | output | 串行数据输出至ADC芯片 |
ADC_SCLK | output | ADC工作时钟 |
ADC_OUT | input | 采集到的串行数字信号 |
ADC芯片将转换后的数字信号通过ADC_OUT串行传送给模块,模块将其变成并行信号data传输给FPGA,保存到FIFO存储器中。
2.代码设计
模块采用线性序列机编写SPI时序,代码逻辑与DAC类似,可分为以下5个部分:通道地址缓存、分频计数器、生成序列计数器、SPI线性序列机、标志位赋值及DATA输出。
(1)通道地址缓存
接收到Start开始转换信号时,开始AD转换,为避免在发送过程中由于干扰导致输入的数据变化,在Start为高电平时,将通道地址Channel缓存到r_Channel中。
reg [2:0] r_Channel; //通道地址寄存
always@(posedge Clk or negedge Rst_n)//数据缓存
if(!Rst_n)
r_Channel <= 3'd0;
else if(Start)
r_Channel <= Channel;
else
r_Channel <= r_Channel;
(2)分频计数器
前面提到SCLK频率范围为3.2-8Mhz,取系统时钟的八分频6.25Mhz为SCLK的时钟。由于数据在SCLK边沿变化和读取,需计算SCLK二倍频以区分上升沿和下降沿。
parameter DIV_PARAM = 8;//分频系数 50/8 = 6.25Mhz
reg [7:0] DIV_cnt; //分频计数器
reg SCLK2X; //SCLK二倍频
always@(posedge Clk or negedge Rst_n)//分频计数器
if(!Rst_n)
DIV_cnt <= 8'd0;
else if(ADC_State) begin
if(DIV_cnt == DIV_PARAM/2 - 1)
DIV_cnt <= 8'd0;
else
DIV_cnt <= DIV_cnt + 1'b1;
end
else
DIV_cnt <= 8'd0;
always@(posedge Clk or negedge Rst_n)//SCLK二倍频
if(!Rst_n)
SCLK2X <= 1'b0;
else if(ADC_State && (DIV_cnt == DIV_PARAM/2 - 1))
SCLK2X <= 1'b1;
else
SCLK2X <= 1'b0;
(3)生成序列计数器
线性序列机在写代码时,应根据时序图列出信号在不同时刻的状态,这里根据时序图将SPI划分为34个状态,故生成序列计数器SCLK_GEN_CNT计数到33,对SCLK的边沿进行计数。
always@(posedge Clk or negedge Rst_n)//生成序列计数器,对SCLK脉冲进行计数
if(!Rst_n)
SCLK_GEN_CNT <= 6'd0;
else if(ADC_State)
if(SCLK2X) begin
if(SCLK_GEN_CNT == 33)
SCLK_GEN_CNT <= 6'd0;
else
SCLK_GEN_CNT <= SCLK_GEN_CNT + 1'b1;
end
else
SCLK_GEN_CNT <= SCLK_GEN_CNT;
else
SCLK_GEN_CNT <= 6'd0;
(4)SPI线性序列机
根据时序图和前面总结的设计要点,DIN在SCLK第3、4、5个下降沿改变,发送通道值,先发高位,后发低位;在SCLK第5个上升沿开始读取DB11;片选信号在SCLK第16个上升沿时被拉高。
always@(posedge Clk or negedge Rst_n)//线性序列机发送数据
if(!Rst_n) begin
ADC_SCLK <= 1'b1;
ADC_CS_N <= 1'b1;
ADC_DIN <= 1'b1;
end
else if(SCLK2X)
case(SCLK_GEN_CNT)
0: begin ADC_CS_N <= 1'b0; ADC_SCLK <= 1'b1; end
1: ADC_SCLK <= 1'b0;
2: ADC_SCLK <= 1'b1;
3: ADC_SCLK <= 1'b0;
4: ADC_SCLK <= 1'b1;
5: begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[2]; end
6: ADC_SCLK <= 1'b1;
7: begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[1]; end
8: ADC_SCLK <= 1'b1;
9: begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[0]; end
11,13,15,17,19,21,23,25,27,29,31: ADC_SCLK <= 1'b0;
10:begin ADC_SCLK <= 1'b1; r_data[11] <= ADC_OUT; end
12:begin ADC_SCLK <= 1'b1; r_data[10] <= ADC_OUT; end
14:begin ADC_SCLK <= 1'b1; r_data[9] <= ADC_OUT; end
16:begin ADC_SCLK <= 1'b1; r_data[8] <= ADC_OUT; end
18:begin ADC_SCLK <= 1'b1; r_data[7] <= ADC_OUT; end
20:begin ADC_SCLK <= 1'b1; r_data[6] <= ADC_OUT; end
22:begin ADC_SCLK <= 1'b1; r_data[5] <= ADC_OUT; end
24:begin ADC_SCLK <= 1'b1; r_data[4] <= ADC_OUT; end
26:begin ADC_SCLK <= 1'b1; r_data[3] <= ADC_OUT; end
28:begin ADC_SCLK <= 1'b1; r_data[2] <= ADC_OUT; end
30:begin ADC_SCLK <= 1'b1; r_data[1] <= ADC_OUT; end
32:begin ADC_SCLK <= 1'b1; r_data[0] <= ADC_OUT; end
33:ADC_CS_N <= 1'b1;
default:ADC_CS_N <= 1'b1;
endcase
(5)标志位赋值及DATA输出
从ADC中读取的串行数据按位寄存在r_data中,在AD转换结束时,Conv_done置1,将寄存的r_data传给DATA一并输出。
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
ADC_State <= 1'b0;
else if(Start)
ADC_State <= 1'b1;
else if((SCLK_GEN_CNT == 33) && SCLK2X && ADC_State)
ADC_State <= 1'b0;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n) begin
Conv_done <= 1'b0;
DATA <= 12'd0;
end
else if((SCLK_GEN_CNT == 33) && SCLK2X && ADC_State)
begin
Conv_done <= 1'b1;
DATA <= r_data;
end
else begin
Conv_done <= 1'b0;
DATA <= DATA;
end
AD采集源代码
module adc128s052(
input Clk, //系统时钟
input Rst_n, //系统复位
input [2:0] Channel, //通道选择
input Start, //开始标志位
output reg Conv_done, //完成标志位
output reg [11:0] DATA, //并行数字信号
output reg ADC_CS_N, //片选
output reg ADC_DIN, //串行数据送给ADC芯片
output reg ADC_SCLK, //工作时钟
input ADC_OUT //串行数字信号
);
reg ADC_State; //AD采集状态标志
reg [2:0] r_Channel; //通道地址寄存
reg [11:0] r_data; //采集数据缓存,一次性输出
parameter DIV_PARAM = 8;//分频系数 50/8 = 6.25Mhz
reg [7:0] DIV_cnt; //分频计数器
reg SCLK2X; //SCLK二倍频
reg [5:0] SCLK_GEN_CNT; //SCLK序列生成计数器
always@(posedge Clk or negedge Rst_n)//数据缓存
if(!Rst_n)
r_Channel <= 3'd0;
else if(Start)
r_Channel <= Channel;
else
r_Channel <= r_Channel;
always@(posedge Clk or negedge Rst_n)//分频计数器
if(!Rst_n)
DIV_cnt <= 8'd0;
else if(ADC_State) begin
if(DIV_cnt == DIV_PARAM/2 - 1)
DIV_cnt <= 8'd0;
else
DIV_cnt <= DIV_cnt + 1'b1;
end
else
DIV_cnt <= 8'd0;
always@(posedge Clk or negedge Rst_n)//SCLK二倍频
if(!Rst_n)
SCLK2X <= 1'b0;
else if(ADC_State && (DIV_cnt == DIV_PARAM/2 - 1))
SCLK2X <= 1'b1;
else
SCLK2X <= 1'b0;
always@(posedge Clk or negedge Rst_n)//生成序列计数器,对SCLK脉冲进行计数
if(!Rst_n)
SCLK_GEN_CNT <= 6'd0;
else if(ADC_State)
if(SCLK2X) begin
if(SCLK_GEN_CNT == 33)
SCLK_GEN_CNT <= 6'd0;
else
SCLK_GEN_CNT <= SCLK_GEN_CNT + 1'b1;
end
else
SCLK_GEN_CNT <= SCLK_GEN_CNT;
else
SCLK_GEN_CNT <= 6'd0;
always@(posedge Clk or negedge Rst_n)//线性序列机发送数据
if(!Rst_n) begin
ADC_SCLK <= 1'b1;
ADC_CS_N <= 1'b1;
ADC_DIN <= 1'b1;
end
else if(SCLK2X)
case(SCLK_GEN_CNT)
0: begin ADC_CS_N <= 1'b0; ADC_SCLK <= 1'b1; end
1: ADC_SCLK <= 1'b0;
2: ADC_SCLK <= 1'b1;
3: ADC_SCLK <= 1'b0;
4: ADC_SCLK <= 1'b1;
5: begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[2]; end
6: ADC_SCLK <= 1'b1;
7: begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[1]; end
8: ADC_SCLK <= 1'b1;
9: begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[0]; end
11,13,15,17,19,21,23,25,27,29,31: ADC_SCLK <= 1'b0;
10:begin ADC_SCLK <= 1'b1; r_data[11] <= ADC_OUT; end
12:begin ADC_SCLK <= 1'b1; r_data[10] <= ADC_OUT; end
14:begin ADC_SCLK <= 1'b1; r_data[9] <= ADC_OUT; end
16:begin ADC_SCLK <= 1'b1; r_data[8] <= ADC_OUT; end
18:begin ADC_SCLK <= 1'b1; r_data[7] <= ADC_OUT; end
20:begin ADC_SCLK <= 1'b1; r_data[6] <= ADC_OUT; end
22:begin ADC_SCLK <= 1'b1; r_data[5] <= ADC_OUT; end
24:begin ADC_SCLK <= 1'b1; r_data[4] <= ADC_OUT; end
26:begin ADC_SCLK <= 1'b1; r_data[3] <= ADC_OUT; end
28:begin ADC_SCLK <= 1'b1; r_data[2] <= ADC_OUT; end
30:begin ADC_SCLK <= 1'b1; r_data[1] <= ADC_OUT; end
32:begin ADC_SCLK <= 1'b1; r_data[0] <= ADC_OUT; end
33:ADC_CS_N <= 1'b1;
default:ADC_CS_N <= 1'b1;
endcase
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
ADC_State <= 1'b0;
else if(Start)
ADC_State <= 1'b1;
else if((SCLK_GEN_CNT == 33) && SCLK2X && ADC_State)
ADC_State <= 1'b0;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n) begin
Conv_done <= 1'b0;
DATA <= 12'd0;
end
else if((SCLK_GEN_CNT == 33) && SCLK2X && ADC_State)
begin
Conv_done <= 1'b1;
DATA <= r_data;
end
else begin
Conv_done <= 1'b0;
DATA <= DATA;
end
endmodule
三、仿真
1.ADC芯片采集信号模拟
模拟ADC芯片采集过程,在SCLK下降沿时改变ADC_OUT的值,将这个过程封装成task任务。
task GENE_ADC_OUT;
input [15:0] v_data;
integer i;
begin
wait(!ADC_CS_N);//等待CS_N被拉低
for(i=0;i<16;i=i+1) begin
@(negedge ADC_SCLK)
ADC_OUT = v_data[15-i];
end
end
endtask
2.仿真文件
仿真时,调用ADC芯片采集信号模拟任务,模拟采集到的数字信号为12’h678和12’h9ab,等待AD采集完成,代码如下:文章来源:https://www.toymoban.com/news/detail-723811.html
`timescale 1ns/1ns
module adc128s052_tb();
reg Clk,Rst_n,Start,ADC_OUT;
reg [2:0]Channel;
wire ADC_CS_N,ADC_DIN,ADC_SCLK;
wire Conv_done;
wire [11:0] DATA;
adc128s052 adc128s052(
.Clk(Clk),
.Rst_n(Rst_n),
.DATA(DATA),
.Channel(Channel),
.Start(Start),
.Conv_done(Conv_done),
.ADC_CS_N(ADC_CS_N),
.ADC_DIN(ADC_DIN),
.ADC_SCLK(ADC_SCLK),
.ADC_OUT(ADC_OUT)
);
initial Clk = 1'b1;
always #10 Clk = ~Clk;
initial begin
Rst_n = 1'b0;
Start = 1'b0;
Channel = 3'd0;
#201;
Rst_n = 1'b1;
#20;
Channel = 3'd6;
Start = 1'b1;
#20;
Start = 1'b0;
GENE_ADC_OUT(16'h0678);
wait(Conv_done);
#2000;
Channel = 3'd3;
Start = 1'b1;
#20;
Start = 1'b0;
GENE_ADC_OUT(16'h09ab);
wait(Conv_done);
#2000;
$stop;
end
task GENE_ADC_OUT;
input [15:0] v_data;
integer i;
begin
wait(!ADC_CS_N);//等待CS_N被拉低
for(i=0;i<16;i=i+1) begin
@(negedge ADC_SCLK)
ADC_OUT = v_data[15-i];
end
end
endtask
endmodule
3.仿真结果
文章来源地址https://www.toymoban.com/news/detail-723811.html
到了这里,关于FPGA学习笔记:数据采集传输系统设计(三):AD采集驱动ADC128S052的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!