赞
踩
模块名称 : adc_128s022 模数驱动模块设计
主要功能 :本实验设计了adc_128s022 数模驱动芯片,通过在ADC_DIN输出端发送配置数据来完成芯片通道的配置和数字电压信号的传输,ADC_DOUT 来获取信号的输入,最终内部转换得到输出采集的数字信号。
设计流程:我们在这次实验中,在内部通过CLK的时钟分频,来输出时钟ADC_SCLK信号,根据ADC_SCLK 的时钟,通过ADC_DIN 来发送通道的配置引脚,随后ADC_DOUT 来接收模拟信号的采样数据点。最终完成在内部进行转换得到电压。通过该时钟,我们进而来设计线性序列机(可以理解一种比较特殊的状态机)来编写ADC模数芯片的SPI的时序.
AD128S022芯片的线性序列逻辑:
12位分辨率
CS_N : 片选信号,低电平有效
SCLK : 时钟
DIN(FPGA输出) : 信号输入引脚,SCLK 上升沿采样输入,【对于FPGA,需要下降沿改变输出的数据】
DOUT(对应FPGA输入): 转换结构输出脚,SCLK下降沿输出,【对于FPGA,还是上升沿读取】。
模块实现:
数据手册的基本信息:
ksps (kilo samples per second) : 每秒多少K次采样。
500ksps -1Msps : 表示的是采样速率是,500k采样/1s - 1000k采样/1s.
功能描述:
注:这里主要关注的是一些关于dac的位数,工作电压,支持的采样速率,低功耗模式等较为重要的信息。
这个是内部电路给出的时序操作图:
实现过程可以看到,在CS片选信号拉低以后,我们将以SCLK的下降来进行计数,DIN在第四个下降沿到来时,开始连续的发送3个采样的信道地址ADDR[2:0]。同时我们也统计上升沿的个数,我们在SCLK的第5个上升沿开始接收采样的数据DATA[11:0],统计16个上升沿数据。随后完成一次数据的采集。
在上述图片中,描述的是一个连续的信号采集过程,一次完整的信号采集一共有16个上升沿和16个下降沿,我们以下降作为一次的开始(实际的情况也是下降沿作为信号采集的起始信号)计数,一共有16个时钟周期。随后又是16个时钟周期开始执行相同的操作。
数据典型电路:
布局布线设计电路:
ad128s022.v 文件
module ad128s022 ( Clk, Rst_n, Channel, Data, En_Conv, Conv_Done, ADC_State, DIV_PARAM, ADC_SCLK, ADC_DOUT, ADC_DIN, ADC_CS_N ); input Clk; input Rst_n; input [2:0]Channel; output reg [11:0]Data; input En_Conv; output reg Conv_Done; output ADC_State; input [7:0]DIV_PARAM; output reg ADC_SCLK; input ADC_DOUT; output reg ADC_DIN; output reg ADC_CS_N; reg en ; reg [2:0]r_Channel; reg [7:0]DIV_CNT ; reg SCLK2X ; reg [5:0]SCLK_GEN_CNT; reg [11:0]r_Data; // en handle always@(posedge Clk or negedge Rst_n) if(!Rst_n) en <= 1'b0; else if(En_Conv) en <= 1'b1; else if(Conv_Done) en <= 1'b0 ; else en <= en ; // r_Channel we set En_Conv is a plus signal always@(posedge Clk or negedge Rst_n) if(!Rst_n) r_Channel <= 3'd0; else if(En_Conv) r_Channel <= Channel; else r_Channel <= r_Channel; // 时钟分频脉冲计数 // reg [7:0]DIV_CNT ; always@(posedge Clk or negedge Rst_n) if(!Rst_n) DIV_CNT <= 8'd0 ; else if(en) begin if(DIV_CNT == (DIV_PARAM -1) ) DIV_CNT <= 8'd0 ; else DIV_CNT <= DIV_CNT + 1'd1 ; end else DIV_CNT <= 8'd0 ; // SCLK2X plus // reg SCLK2X always@(posedge Clk or negedge Rst_n) if(!Rst_n) SCLK2X <= 1'b0; else if(DIV_CNT == (DIV_PARAM -1) ) SCLK2X <= 1'b1 ; else SCLK2X <= 1'b0; // reg [5:0]SCLK_GEN_CNT always@(posedge Clk or negedge Rst_n) if(!Rst_n) SCLK_GEN_CNT <= 6'd0 ; else if(en && SCLK2X) begin if(SCLK_GEN_CNT == 6'd33) SCLK_GEN_CNT <=6'd0; else SCLK_GEN_CNT <= SCLK_GEN_CNT + 1'b1 ; end else SCLK_GEN_CNT <= SCLK_GEN_CNT ; // /* output ADC_SCLK input ADC_DOUT; output ADC_DIN; output reg ADC_CS_N; reg [11:0]r_Data; */ always@(posedge Clk or negedge Rst_n) if(!Rst_n) begin ADC_SCLK <= 1'b1; ADC_DIN <= 1'b0; ADC_CS_N <= 1'b1; end else if(en && SCLK2X) begin case(SCLK_GEN_CNT) 0: begin ADC_CS_N <= 1'b0; ADC_SCLK <= 1'b1; ADC_DIN <= 1'b0; end 1,3: begin ADC_SCLK <= 1'b0; end 2,4,6,8: begin ADC_SCLK <= 1'b1 ; end 5: begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[2]; end 7: begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[1]; end 9: begin ADC_SCLK <= 1'b0; ADC_DIN <= r_Channel[0]; end 10: begin ADC_SCLK <= 1'b1; r_Data[11] <= ADC_DOUT ; end 12: begin ADC_SCLK <= 1'b1; r_Data[10] <= ADC_DOUT ; end 14: begin ADC_SCLK <= 1'b1; r_Data[9] <= ADC_DOUT ; end 16: begin ADC_SCLK <= 1'b1; r_Data[8] <= ADC_DOUT ; end 18: begin ADC_SCLK <= 1'b1; r_Data[7] <= ADC_DOUT ; end 20: begin ADC_SCLK <= 1'b1; r_Data[6] <= ADC_DOUT ; end 22: begin ADC_SCLK <= 1'b1; r_Data[5] <= ADC_DOUT ; end 24: begin ADC_SCLK <= 1'b1; r_Data[4] <= ADC_DOUT ; end 26: begin ADC_SCLK <= 1'b1; r_Data[3] <= ADC_DOUT ; end 28: begin ADC_SCLK <= 1'b1; r_Data[2] <= ADC_DOUT ; end 30: begin ADC_SCLK <= 1'b1; r_Data[1] <= ADC_DOUT ; end 32: begin ADC_SCLK <= 1'b1; r_Data[0] <= ADC_DOUT ; end 11,13,15,17,19,21,23,25,27,29,31: begin ADC_SCLK <= 1'b0; end 33: begin ADC_CS_N <= 1'b1; end default: ; endcase end // output [11:0]Data always@(posedge Clk or negedge Rst_n) if(!Rst_n) Data <= 12'd0 ; else if(en && SCLK2X && (SCLK_GEN_CNT == 6'd33)) Data <= r_Data ; else Data <= Data ; // conv_Done signal always@(posedge Clk or negedge Rst_n) if(!Rst_n) Conv_Done <= 1'd0 ; else if(en && SCLK2X && (SCLK_GEN_CNT == 6'd33)) Conv_Done <= 1'd1 ; else Conv_Done <= 1'd0 ; //产生ADC工作状态指示信号,保持和CS片选信号同步即可 assign ADC_State = ADC_CS_N ; endmodule
注(这个是用于分析时序的时钟问题): SCLK2X 和 DIV_PARAM 这两个信号,DIV_PARAM 是一个输入分频信号,可以看到:
情况1:
假设DIV_PARAM =2时,
SCLK2X = Clk/DIV_PARAM = 50Mhz/2=25Mhz 的【周期脉冲信号,非标准方波信号】。
这样的话,ADC_SCLK输出的时钟是 = SCLK2X/2 =25Mhz/2 =12.5Mhz 的时钟。
情况2:
假设DIV_PARAM =4时,
SCLK2X = Clk/DIV_PARAM = 50Mhz/4=12.5Mhz 的【周期脉冲信号,非标准方波信号】
这样的话,ADC_SCLK输出的时钟是 = SCLK2X/2 =25Mhz/2 =6.25Mhz 的时钟。
这里非常需要了解输出SCLK 的最终的时钟输出。
SCL2X:这个是来统计上升沿和下降沿的计数。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。