2.EP4CE10F17的ADC设计

前记:师夷长技以自强


                                                                                                                                                              P285

1.基本概念

ADC:Analog to Digital Conver,是将模拟信号转变为数字信号的电子元件。分为间接ADC和直接ADC两种,实验中使用的ADC128S022是逐次逼近型属于直接ADC。

ADC128S022:主要特性是8通道12位转换速度为50Ksps~200Ksps,输出的数据兼容SPI,QSPI,等接口的二进制数据。

2.ADC128S022电气特性

2.1封装和结构

实验中的ADC芯片共16管脚,采用双排直插式封装,

了解它内部的结构有助于更好地掌握芯片的使用方式,基本上分为三大块:多路选择子模块、逐次逼近转换子模块和逻辑控制模块

可以看出,与FPGA有关的只有SCLK、\CS、DIN、DOUT。

2.2时序

首先一次采样有16个SCLK时钟,前3个时钟ADC处于采用模式,后13个为保持模式。其中DIN的输入发生在SCLK的上升沿,DOUT的输出发生在SCLK的下降沿,上图中的DOUT应该往右移半拍。

DIN的8个控制寄存器只用了其中的3位:

Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0
DONTCDONTCADD2ADD1ADD0DONTCDONTCDONTC

其中的ADD2,ADD1,ADD0组成的3位二进制数代表了IN的通道号。

由于SCLK的工作频率是0.8~3.2MHz,系统频率为50MHz,这里定义ADC的工作频率为1.92MHz,为了完成线性序列机的设计,需要一个两倍的时钟SCLK2X=3.84MHz,大概经过系统时钟13分频得到。下面先列出信号随时间的操作表:

计数值对应信号操作
0\CS = 0;
1SCLK = 0;
2SCLK = 1;
3

SCLK = 0;

4SCLK = 1;
5SCLK = 0;DIN = ADD2;
6SCLK = 1;
7SCLK =0,DIN = ADD1;
8

SCLK = 1;

9SCLK = 0;DIN = ADD0;
10SCLK = 1;r_data[11] = DOUT;
11SCLK = 0;
12SCLK = 1;r_data[10] = DOUT;
13SCLK = 0;
14SCLK = 1;r_data[9] = DOUT;
15SCLK = 0;
16SCLK = 1;r_data[8] = DOUT;
17SCLK = 0;
18SCLK = 1;r_data[7] = DOUT;
19SCLK = 0;
20SCLK = 1;r_data[6] = DOUT;
21SCLK = 0;
22SCLK = 1;r_data[5] = DOUT;
23SCLK = 0;
24SCLK = 1;r_data[4] = DOUT;
25SCLK = 0;
26SCLK = 1;r_data[3] = DOUT;
27SCLK = 0;
28SCLK = 1;r_data[2] = DOUT;
29SCLK = 0;
30SCLK = 1;r_data[1] = DOUT;
31SCLK = 0;
32SCLK = 1;r_data[0] = DOUT;
33CS_N = 1;

3.ADC驱动设计

3.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中的驱动模块应如下图所示:

 

3.2代码设计

同样在代码中加了一个表示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

3.3仿真测试

在Quatus 中仿真只能看到时序图,由于没有真实的ADCx芯片和采样点,因此DOUT是没有数据输出的。

`timescale 1ns/1ns
`define period 20

module 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
 

仿真后得到的时序图如下

 

 

明天的你会感谢今天努力的自己!

 

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值