赞
踩
前记:师夷长技以自强
P285
ADC:Analog to Digital Conver,是将模拟信号转变为数字信号的电子元件。分为间接ADC和直接ADC两种,实验中使用的ADC128S022是逐次逼近型属于直接ADC。
ADC128S022:主要特性是8通道12位转换速度为50Ksps~200Ksps,输出的数据兼容SPI,QSPI,等接口的二进制数据。
实验中的ADC芯片共16管脚,采用双排直插式封装,
了解它内部的结构有助于更好地掌握芯片的使用方式,基本上分为三大块:多路选择子模块、逐次逼近转换子模块和逻辑控制模块
可以看出,与FPGA有关的只有SCLK、\CS、DIN、DOUT。
首先一次采样有16个SCLK时钟,前3个时钟ADC处于采用模式,后13个为保持模式。其中DIN的输入发生在SCLK的上升沿,DOUT的输出发生在SCLK的下降沿,上图中的DOUT应该往右移半拍。
DIN的8个控制寄存器只用了其中的3位:
Bit7 | Bit6 | Bit5 | Bit4 | Bit3 | Bit2 | Bit1 | Bit0 |
DONTC | DONTC | ADD2 | ADD1 | ADD0 | DONTC | DONTC | DONTC |
其中的ADD2,ADD1,ADD0组成的3位二进制数代表了IN的通道号。
由于SCLK的工作频率是0.8~3.2MHz,系统频率为50MHz,这里定义ADC的工作频率为1.92MHz,为了完成线性序列机的设计,需要一个两倍的时钟SCLK2X=3.84MHz,大概经过系统时钟13分频得到。下面先列出信号随时间的操作表:
计数值 | 对应信号操作 |
0 | \CS = 0; |
1 | SCLK = 0; |
2 | SCLK = 1; |
3 | SCLK = 0; |
4 | SCLK = 1; |
5 | SCLK = 0;DIN = ADD2; |
6 | SCLK = 1; |
7 | SCLK =0,DIN = ADD1; |
8 | SCLK = 1; |
9 | SCLK = 0;DIN = ADD0; |
10 | SCLK = 1;r_data[11] = DOUT; |
11 | SCLK = 0; |
12 | SCLK = 1;r_data[10] = DOUT; |
13 | SCLK = 0; |
14 | SCLK = 1;r_data[9] = DOUT; |
15 | SCLK = 0; |
16 | SCLK = 1;r_data[8] = DOUT; |
17 | SCLK = 0; |
18 | SCLK = 1;r_data[7] = DOUT; |
19 | SCLK = 0; |
20 | SCLK = 1;r_data[6] = DOUT; |
21 | SCLK = 0; |
22 | SCLK = 1;r_data[5] = DOUT; |
23 | SCLK = 0; |
24 | SCLK = 1;r_data[4] = DOUT; |
25 | SCLK = 0; |
26 | SCLK = 1;r_data[3] = DOUT; |
27 | SCLK = 0; |
28 | SCLK = 1;r_data[2] = DOUT; |
29 | SCLK = 0; |
30 | SCLK = 1;r_data[1] = DOUT; |
31 | SCLK = 0; |
32 | SCLK = 1;r_data[0] = DOUT; |
33 | CS_N = 1; |
基本的信号应该包含:
1.基本时序信号:Clk,Rst_n,SCLK,CS_N,DIN,DOUT
2.数据输入输出信号:Div_PARAM[7:0],Channel[3:0] ,Start ,Data[11:0]
3.芯片标志信号:ADC_STATE,Conv_Done
ADC128S022在FPGA中的驱动模块应如下图所示:
同样在代码中加了一个表示ADC在工作的变量en,对输入的数据Channel暂存的变量r_Channel,对输出的数据Data暂存的变量r_data。为了对Clk分频需要一个时钟信号SCLK2X,为了对Clk和SCLK2X时钟计数,需要Clk_CNT和SCLK2X_CNT变量。ADC模块的驱动代码如下:
module ADC(
input Clk,
input Rst_n,
input [7:0]DIV_PARAM,
input [2:0]Channel,
input Start,
input DOUT,
output reg Conv_Done,
output ADC_STATE, //0-idle,1-busy
output reg [11:0]Data,
output reg SCLK,
output reg DIN,
output reg CS_N
);
reg SCLK2X;
reg en;
reg [7:0]Clk_CNT;
reg [2:0]r_Channel;
reg [5:0]SCLK2X_CNT;
reg [11:0]r_data;
always@(posedge Clk,negedge Rst_n)
if(!Rst_n)
Clk_CNT <= 0;
else if(en)
if(Clk_CNT == DIV_PARAM - 8'b1)
Clk_CNT <= 0;
else
Clk_CNT <= Clk_CNT + 8'b1;
else
Clk_CNT <= 0;
always@(posedge Clk,negedge Rst_n)
if(!Rst_n)
SCLK2X <= 0;
else if(en&&(Clk_CNT == DIV_PARAM - 8'b1))
SCLK2X <= 1;
else
SCLK2X <= 0;
always@(posedge Clk,negedge Rst_n)
if(!Rst_n)
en <= 0;
else if(Start)
en <= 1;
else if(Conv_Done)
en <= 0;
else
en <= en;
always@(posedge Clk,negedge Rst_n)
if(!Rst_n)
r_Channel <= 3'b0;
else if(Start)
r_Channel <= Channel;
else
r_Channel <= r_Channel;
always@(posedge Clk,negedge Rst_n)
if(!Rst_n)
SCLK2X_CNT <= 0;
else if(en&&SCLK2X)
if(SCLK2X_CNT == 33)
SCLK2X_CNT <= 0;
else
SCLK2X_CNT <= SCLK2X_CNT + 6'b1;
else
SCLK2X_CNT <= SCLK2X_CNT;
always@(posedge Clk,negedge Rst_n)
if(!Rst_n)begin
r_data <= 12'b0;
SCLK <= 1;
DIN <= 1;
CS_N <= 1;
end
else if(en)begin
case(SCLK2X_CNT)
0:
CS_N <= 0;
1,3,11,13,15,17,19,21,23,25,27,29,31:
SCLK <= 0;
2,4,6,8:
SCLK <= 1;
5:
begin
SCLK <= 0;
DIN <= r_Channel[2];
end
7:
begin
SCLK <= 0;
DIN <= r_Channel[1];
end
9:
begin
SCLK <= 0;
DIN <= r_Channel[0];
end
10,12,14,16,18,20,22,24,26,28,30,32:
begin
SCLK <= 1;
r_data <= {r_data[10:0],DIN};
end
33:
CS_N <= 1;
endcase
end
always@(posedge Clk,negedge Rst_n)
if(!Rst_n)
Conv_Done <= 0;
else if(en&&(SCLK2X_CNT == 33)&&SCLK2X)
Conv_Done <= 1;
else
Conv_Done <= 0;
always@(posedge Clk,negedge Rst_n)
if(!Rst_n)
Data <= 11'b0;
else if(en&&(SCLK2X_CNT == 33)&&SCLK2X)
Data <= r_data;
else
Data <= Data;
assign ADC_STATE = CS_N;endmodule
在Quatus 中仿真只能看到时序图,由于没有真实的ADCx芯片和采样点,因此DOUT是没有数据输出的。
`timescale 1ns/1ns
`define period 20module ADC_tb();
reg Clk;
reg Rst_n;
reg [7:0]DIV_PARAM;
reg [2:0]Channel;
reg Start;
reg DOUT;
wire Conv_Done;
wire ADC_STATE; //0-idle,1-busy
wire [11:0]Data;
wire SCLK;
wire DIN;
wire CS_N;
ADC ADC1(
.Clk(Clk),
.Rst_n(Rst_n),
.DIV_PARAM(DIV_PARAM),
.Channel(Channel),
.Start(Start),
.DOUT(DOUT),
.Conv_Done(Conv_Done),
.ADC_STATE(ADC_STATE), //0-idle,1-busy
.Data(Data),
.SCLK(SCLK),
.DIN(DIN),
.CS_N(CS_N)
);
initial Clk = 0;
always #10 Clk = ~Clk;
initial begin
Rst_n <= 0;
Start <= 0;
#`period;
Rst_n <= 1;
DIV_PARAM <= 8'd13;
Channel <= 3'b1;
Start <= 1;
#2000;
Start <= 0;
#20000;
$stop;
end
endmodule
仿真后得到的时序图如下
明天的你会感谢今天努力的自己!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。