FPGA|CPLD|ASIC论坛
400万+工程师在用
华为|鸿蒙开发者日
直播报名
400万+工程师在用
华为|鸿蒙开发者日
直播报名

runileking

7年用户 301经验值
擅长:可编程逻辑 MEMS/传感技术
私信 关注
[资料]

AD5686实例讲解基于FPGA控制的SPI型数模/模数转换器配置

2016-12-14 17:20

之前看到有人在网上提问ADC,DAC怎么控制啊,感觉就是照着手册上时序的样子把对应的控制线拉高拉低就可以了,可能从完全不懂开始刚上手做这些东西,有时候会遇到一些小障碍,这里以AD5686芯片的驱动为例,详细叙述实现过程以及涉及到的FPGA逻辑电路设计的相关问题。
       AD5686是一款4通道16为精度的AD转换器,通过SPI接口进行配置,实现将数字信号转换为模拟信号的功能。SPI接口协议通常有四根数据线,CS,SCLK,SDIN,SDO。CS为片选信号线,当CS为低电平时SPI接口才处于工作状态;SCLK为串行时钟,用来同步数据传输;SDIN为器件的输入信号线,SDO为器件的输出信号线。SPI协议通常采用上升沿发送,下降沿接收,高位先发送的方式。对于数模转换器来说,SDIN输入的信号在SCLK的下降沿进行采集,打入DAC芯片的寄存器,在SCLK的上升沿,SDO输出信号发生变化。
1.png

file:///C:/Users/cheng/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg
图1
       上图是AD5686数据手册上配置接口的时序要求,SCLK为SPI接口的串行时钟信号,SYNC相当于CS,为片选信号,当SYNC拉低时SPI接口开始工作,具体拉低多少时间,拉低不同的时间对应什么结果,手册里会有详细的介绍。这里只是照着这个时序图去写FPGA的逻辑代码,就能保证AD5686正常工作。SDIN为输入数据,即需要转换为模拟信号的数字信号。为什么是从DB23开始呢,因为包含四位控制字和四位地址位,如下图,具体见手册。
2.png
file:///C:/Users/cheng/AppData/Local/Temp/msohtmlclip1/01/clip_image003.png
图2
SDO为AD5686的输出信号,用于菊花链或者反馈,这里只用单个AD5686做数模转换的话可以不用,上边的时序图里也没给出这根信号线。LDAC控制数模转换器的模拟输出信号同步更新还是异步更新,本次实例将LDAC一直拉低。RESET为高时芯片输出才能正常工作,需要输出模拟信号时RESET控制线一定要注意将其拉高。另外就是图一中列出时间要求,注意那个时间表里的时间只是一个范围要求,满足那个范围就可以,不是严格控制的,上次看到有人在网上问。说清楚了这些,现在就来通过ISE创建一个AD5686驱动程序。VeriloG代码如下:
module DAC(CLK,RESET,SCLK,SYNC,SDIN,LDAC,RSTDAC);

       input CLK;
       inputRESET;
       outputSCLK;
       output regSYNC;
       output regSDIN;
       output regLDAC;
       output regRSTDAC;

       reg[4:0]n;
       wire[23:0]data;
       assigndata={4'b0001,4'b0001,16'b0101_0101_0101_0101};//控制字位4'b0001;地址位4'b0001,表示由A口输出模拟信号

       always@(posedge CLK_50M or negedge RESET)
              begin
                     if(!RESET)
                            begin
                                   SYNC<=0;
                                   SDIN<=0;
                                   LDAC<=0;
                                   RSTDAC<=1;
                                   n<=5'd24;
                            end
                     else
                            begin
                                   if(n==5'd24)
                                          begin
                                                 SYNC<=1;
                                                 n<=n-5'd1;
                                          end
                                   elseif(n==5'd23)
                                          begin
                                                 SDIN<=data[n];
                                                 SYNC<=0;

                                                 n<=n-5'd1;
                                          end
                                   elseif(n<5'd23&&n>0)
                                          begin
                                                 SDIN<=data[n];
                                                 SYNC<=0;

                                                 n<=n-5'd1;
                                          end
                                   elseif(n==0)
                                          begin
                                                 SDIN<=data[0];
                                                 n<=5'd24;
                                          end
                            end
              end

        DCM instance_name
    (// clock inports
   .CLK_IN1(CLK),      // IN
    // Clock outports
   .CLK_OUT1(CLK_50M)     // OUT
        );    //OUT

        Oddr2 #(

                            //The following parameters specify the behavior
                            //of the component.
                            .DDR_ALIGNMENT("NONE"),// Sets output alignment // to "NONE", "C0" or"C1"
                            .INIT(1'b0),    // Sets initial state of the Q  //  output to 1'b0 or 1'b1
                            .SRTYPE("SYNC")// Specifies "SYNC" or "ASYNC"
                  //   set/reset
       )

       ODDR2_sclk(
                                   .Q(SCLK),   // 1-bit DDR output data
                                   .C0(CLK_50M),// 1-bit clock input
                                   .C1(~CLK_50M),// 1-bit clock input
                                   .CE(1'b1),// 1-bit clock enable input
                                   .D0(1'b1),// 1-bit data input (associated with C0)
                                   .D1(1'b0),// 1-bit data input (associated with C1)
                                   .R(1'b0),   // 1-bit reset input
                                   .S(1'b0)    // 1-bit set input
       );

endmodule
       例程中SDIN输入的数据为16'b0101_0101_0101_0101,对应的十进制数是21845,而AD5686为16位精度,参考电压为2.5V,2.5*21845/65536约等于0.83V,也就是说上边代码对应的电路去驱动AD5686,其模拟信号输出端A口输出约为0.83V的直流电压。对上述代码进行仿真,仿真结果如图3所示。
3.png
file:///C:/Users/cheng/AppData/Local/Temp/msohtmlclip1/01/clip_image005.jpg
图3
       对比图3和图1可以发现,仿真时序图与手册给的时序一致,SDIN在SCLK的上升沿变化,正好能保证AD5686在SCLK下降沿将数据打入寄存器时数据保持稳定不变。本人有一个XC6SLX45T的板卡带有AD5686,进行管脚分配后布局布线,可以下载上板测试进行验证。由于SCLK通过非全局时钟引脚输出,所以使用了ODDR2那段代码,关于ODDR2网上可以找到。最后下载程序编译测试,万用表测得输出电压为0.832V,与设计预期一致,其余SPI接口控制型ADC或者DAC驱动方法类似。

回帖(2)

lt星空

2016-12-28 22:40:31
不错,学习学习

李圳

2017-6-14 08:26:39
学习中

更多回帖

打开APP