FPGA-基于SPI接口的ADC芯片功能和接口时序介绍
ADC: Analog-to-Digital Converter,模/数转换器。
通常是指一个将模拟信号转变为数字信号的电子元件。像我们生活中常见的温度、湿度、电压、电流这些能够用连续变化的物理量所表达的信息,都属于模拟信号;而数字信号,则是在模拟信号的基础上,经过采样、量化和编码而形成的,也就是由许多个0和1组成的信号。
ADC常见指标参数:
分辨率:指ADC能够分辨量化的最小信号的能力,用二进制位数表示。常见的有8位分辨率、12位分辨率、16位分辨率等等。例如, 8位分辨率,就是可以将模拟信号量化为一个8位的数据,数值范围就是0~255
采样范围: ADC作为模拟转数字的器件,其能够进行转换的模拟信号的范围总是有限的,而且一般不高。比如ADC0809,其能够进行转换的模拟电压范围就是0~5V,超出这个范围的模拟电压, ADC0809就不能将其转换为准确的数字信号。
采样速率:也就是这个ADC一秒钟内能够进行多少次模拟量到数字量的转换。高速ADC一秒钟内可以执行几十兆,甚至几百兆次的转换。但是这样的高速ADC,一般价格都非常贵,常用在雷达、无线通信,示波器等领域。普通的ADC,采样速率在几Hz~几Mhz之间。3
上述例子假设采样结果为x,则电压为 U=x*5/(2^8)
手册中的介绍
手册中数据量和模拟量的数据关系图(非线性)
ADC128S102时序图
ADC芯片连续不间断转换图
模块框图
实现单次转换时序
(至少34个时间段)
CS和SCLK的时间间隔(>=10ns)
SCLK : 8MHZ-16MHZ(16MHZ周期是61.5ns则半个周期就是31.25ns大于10ns)
进行一轮转换时刻表
设计思路
设计代码如下
module adc128s102(
Clk,
Reset_n,
Conv_Go,
Addr,
Conv_Done,
Data,
ADC_SCLK,
ADC_CS_N,
ADC_DIN,
ADC_DOUT
);
input Clk;
input Reset_n;
input Conv_Go;
input [2:0]Addr;
output reg Conv_Done;
output reg [11:0]Data;
output reg ADC_SCLK;
output reg ADC_CS_N;
output reg ADC_DIN;
input ADC_DOUT;
parameter CLOCK_FREQ = 50_000_000;
parameter SCLK_FREQ = 12_500_000;
parameter MCNT_DIV_CNT = CLOCK_FREQ /( SCLK_FREQ * 2) -1;
reg[7:0]DIV_CNT;
reg[5:0]LSM_CNT;
reg[11:0]Data_r;
reg[2:0]r_Addr;
always@(posedge Clk)
if(Conv_Go)
r_Addr <= Addr;
else
r_Addr <= r_Addr;
reg Conv_En;//转换使能
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Conv_En <= 1'b0;
else if(Conv_Go)
Conv_En <= 1'b1;
else if((LSM_CNT == 6'd34)&&(DIV_CNT == MCNT_DIV_CNT -1))
Conv_En <= 1'd0;
else
Conv_En <= Conv_En;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
DIV_CNT <=0;
else if(Conv_En) begin
if(DIV_CNT == MCNT_DIV_CNT)
DIV_CNT <= 0;
else
DIV_CNT <= DIV_CNT + 1'd1;
end
else
DIV_CNT <= 0;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
LSM_CNT <= 0;
else if(DIV_CNT == MCNT_DIV_CNT)begin
if(LSM_CNT == 6'd34)
LSM_CNT <= 0;
else
LSM_CNT <= LSM_CNT + 1'd1;
end
else
LSM_CNT <= LSM_CNT;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n) begin
Data_r <= 12'd0;
ADC_SCLK <= 1'd1;
ADC_CS_N <= 1'd1;
ADC_DIN <= 1'd1;
end
else if (DIV_CNT == MCNT_DIV_CNT) begin
case(LSM_CNT)
0 : begin ADC_CS_N <= 1'D1; ADC_SCLK <= 1'D1; end
1 : begin ADC_CS_N <= 1'D0; end
2 : begin ADC_SCLK <= 1'D0; end
3 : begin ADC_SCLK <= 1'D1; end
4 : begin ADC_SCLK <= 1'D0; end
5 : begin ADC_SCLK <= 1'D1; end
6 : begin ADC_SCLK <= 1'D0; ADC_DIN <= r_Addr[2];end
7 : begin ADC_SCLK <= 1'D1; end
8 : begin ADC_SCLK <= 1'D0; ADC_DIN <= r_Addr[1];end
9 : begin ADC_SCLK <= 1'D1; end
10 : begin ADC_SCLK <= 1'D0; ADC_DIN <= r_Addr[0];end
11 : begin ADC_SCLK <= 1'D1; Data_r[11] <= ADC_DOUT;end
12 : begin ADC_SCLK <= 1'D0; end
13 : begin ADC_SCLK <= 1'D1; Data_r[10] <= ADC_DOUT;end
14 : begin ADC_SCLK <= 1'D0; end
15 : begin ADC_SCLK <= 1'D1; Data_r[9] <= ADC_DOUT;end
16 : begin ADC_SCLK <= 1'D0; end
17 : begin ADC_SCLK <= 1'D1; Data_r[8] <= ADC_DOUT;end
18 : begin ADC_SCLK <= 1'D0; end
19 : begin ADC_SCLK <= 1'D1; Data_r[7] <= ADC_DOUT;end
20 : begin ADC_SCLK <= 1'D0; end
21 : begin ADC_SCLK <= 1'D1; Data_r[6] <= ADC_DOUT;end
22 : begin ADC_SCLK <= 1'D0; end
23 : begin ADC_SCLK <= 1'D1; Data_r[5] <= ADC_DOUT;end
24 : begin ADC_SCLK <= 1'D0; end
25 : begin ADC_SCLK <= 1'D1; Data_r[4] <= ADC_DOUT;end
26 : begin ADC_SCLK <= 1'D0; end
27 : begin ADC_SCLK <= 1'D1; Data_r[3] <= ADC_DOUT;end
28 : begin ADC_SCLK <= 1'D0; end
29 : begin ADC_SCLK <= 1'D1; Data_r[2] <= ADC_DOUT;end
30 : begin ADC_SCLK <= 1'D0; end
31 : begin ADC_SCLK <= 1'D1; Data_r[1] <= ADC_DOUT;end
32 : begin ADC_SCLK <= 1'D0; end
33 : begin ADC_SCLK <= 1'D1; Data_r[0] <= ADC_DOUT;end
34 : begin ADC_SCLK <= 1'D1; ADC_CS_N <= 1'D1; end
default : ADC_CS_N <= 1'D1;
endcase
end
always@(posedge Clk or negedge Reset_n)
if(!Reset_n) begin
Conv_Done <= 0;
Data <= 12'd0;
end
else if((LSM_CNT == 34)&&(DIV_CNT == MCNT_DIV_CNT))begin
Conv_Done <= 1'd1;
Data <= Data_r;
end
else begin
Conv_Done <= 1'd0;
Data <= Data;
end
endmodule
然后编写testbench测试文件
代码如下
`timescale 1ns / 1ns
module adc128s102_tb;
reg Clk;
reg Reset_n;
reg Conv_Go;
reg [2:0]Addr;
wire Conv_Done;
wire [11:0]Data;
wire ADC_SCLK;
wire ADC_CS_N;
wire ADC_DIN;
reg ADC_DOUT;
adc128s102 adc128s102(
.Clk(Clk),
.Reset_n(Reset_n),
.Conv_Go(Conv_Go),
.Addr(Addr),
.Conv_Done(Conv_Done),
.Data(Data),
.ADC_SCLK(ADC_SCLK),
.ADC_CS_N(ADC_CS_N),
.ADC_DIN(ADC_DIN),
.ADC_DOUT(ADC_DOUT)
);
initial Clk =1;
always #10 Clk = ~Clk;
initial begin
Reset_n = 0;
Conv_Go = 0;
Addr = 0;
#201;
Reset_n = 1;
#200;
Conv_Go = 1;
Addr = 3;
#20;
Conv_Go = 0;
wait(!ADC_CS_N );
//16'h0A58
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB15
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB14
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB13
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB12
@(negedge ADC_SCLK);
ADC_DOUT = 1; //DB11
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB10
@(negedge ADC_SCLK);
ADC_DOUT = 1; //DB9
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB8
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB7
@(negedge ADC_SCLK);
ADC_DOUT = 1; //DB6
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB5
@(negedge ADC_SCLK);
ADC_DOUT = 1; //DB4
@(negedge ADC_SCLK);
ADC_DOUT = 1; //DB3
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB2
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB1
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB0
wait (ADC_CS_N);
#20000;
Conv_Go = 1;
Addr = 7;
#20;
Conv_Go = 0;
wait(!ADC_CS_N );
//16'h0893
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB15
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB14
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB13
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB12
@(negedge ADC_SCLK);
ADC_DOUT = 1; //DB11
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB10
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB9
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB8
@(negedge ADC_SCLK);
ADC_DOUT = 1; //DB7
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB6
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB5
@(negedge ADC_SCLK);
ADC_DOUT = 1; //DB4
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB3
@(negedge ADC_SCLK);
ADC_DOUT = 0; //DB2
@(negedge ADC_SCLK);
ADC_DOUT = 1; //DB1
@(negedge ADC_SCLK);
ADC_DOUT = 1; //DB0
wait (ADC_CS_N);
#200;
#2000;
$stop;
end
endmodule