[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA基础篇连载-18 SPI接口ADC采集驱动设计

文档创建者:FPGA课程
浏览次数:317
最后更新:2024-08-28
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-FPGA部分 » 2_FPGA实验篇(仅旗舰) » 1-FPGA基础入门实验
本帖最后由 FPGA课程 于 2024-8-28 16:33 编辑

​ 软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!



1概述
一些低速高精度的ADC/DAC都具有SPI接口,SPI的速率最高可以到几百M,另外由于接口少硬件设计简单,通信时序容易实现,而被广泛应用一些AD/DA数据采集场合,笔者在诸多的项目中都使用到了串行SPI接口的ADC/DAC芯片方案。
本文实现AD7606 SPI通信方式实现8路ADC信号采集,本文也将灵活使用SPI的通信时序,而不是拘泥于前面编写的通用的SPI接口。更多时候我们在FPGA项目应用中会根据实际的外设接口编写最佳的时序方案,来实现最佳的性能。
2AD7606介绍2.1芯片功能概述
DAQ7606 数据采集卡,AD 转换芯片为AD7606-8,AD760-8 是16 位8 通道同步采样模数数据采集系统(DAS)。AD7606 内置模拟输入箝位保护、二阶抗混叠滤波器、跟踪保持放大器、16 位电荷再分配逐次逼近型ADC、灵活的数字滤波器、2.5V 基准电压源、基准电压缓冲以及高速串行和并行接口。
AD7606 采用5V单电源供电,可以处理±10V 和±5V 真双极性输入信号,同时所有通道均能以高达200 kSPS 的吞吐速率采样。输入箝位保护电路可以耐受最高达±16.5V 的电压。无论以何种采样频率工作,AD7606 的模拟输入阻抗均为1 MΩ。它采用单电源工作方式,具有片内滤波和高输入阻抗,因此无需驱动运算放大器和外部双极性电源。
AD7606 抗混叠滤波器的3 dB 截止频率为22 kHz;当采样速率为200 ksps 时,它具有40 dB 抗混叠抑制特性。灵活的数字滤波器采用引脚驱动,可以改善信噪比(SNR),并降低3 dB 带宽。
2.2ADC功能框图
9f2abe7a076d4e9cb5d33db46f876165.jpg
很多FPGA程序开发者不懂硬件,这是不行的,FPGA程序员不需要去画PCB但是必须可以阅读硬件的芯片datasheet,从datasheet中提取关键的编程信息,并且原理图的外设和FPGA芯片之间的连接关系。
对于AD7606的datasheet大家可以网上查到,从这副图我们可以看到AD7606芯片的关键结构图。
1)、8路18bit ADC输入,支持双极性输入
2)、8路16bit ADC实际通过多路复用的方式实现的,内部真正只有1个16bitADC
3)、支持并口传输和SPI串行传输
4)、具有内部的2.5V基准,通常采用内部电压基准,可以省去一个外部基准。
5)、还有一些比如BUSY、FRSTDATA、信号需要下面继续根据datasheet了解。
2.3 ADC转换控制时序
582f862ea7bb47ceb6e6a612a130fc30.jpg
                                                                               CONVST时序-转换之后读取

e7add2c9fade46c8bc0abddfd8dd3222.jpg
                                                                              CONVST时序-转换过程读取
AD7606支持2种时序转换,由于我们采用的时串行SPI模式,本身SPI读取数据就会耽误很多时间,所以必须采用第二种工作时序,才能确保200Kbps的采样率。
通过这个转换时序,我们需要把上图的时序中的所有信号作用搞清楚。
1、RESET信号用于对AD7606芯片的复位,复位的高电平时间参数tRESET=50ns,复位和转换信号CONVSTA/ONVSTB的上升沿时间参数t7=25ns
2、CONVSTA/ CONVSTB的低电平时间参数t2=40ns
3、CONVSTA/ CONVSTB如果不是同步,那么他们之间的时间差不能超过t5=0.5ms,我们这里时同时的
4、转换周期tCYCLE=5us
5、BUSY信号为高电平代表数据正在转换,转换时间参数tCONV为最大4.15us
6、CS信号和BUSY信号有一个时间参数t6不能大于25ns
由于设计FPGA接口芯片程序,都是和时序相关联的,所以了解了以上时序参数后,我们FPGA代码设计就要能够满足这些参数指标。
2.4 ADC SPI时序
869de22bee894b579336e2de86712fb7.jpg
当数据完成转换后,CS为电平期间,每个时钟的上升沿完成数据的采样,这里有一个FRSTDATA的表中,代表每次转换的第一个数据,这里实际可以不用这个信号,因为每次CS之后的第一个上升沿时钟我们就是开始采样数据,每16次完成一路ADC的采集。
对于AD7606具有8路ADC,DOUTA对于1~4路ADC通道,DOUTB对应5~8路ADC通道。而且ADC的2组4个通道可以一次性完成采集,也就是说16X4共计64个时钟上升沿完成4路ADC采集,DOUTA和DOUTB各4路。
3 硬件电路分析
硬件接口和子卡模块请阅读“附录 1”
配套工程的 FPGA PIN 脚定义路径为 fpga_prj/uisrc/04_pin/ fpga_pin.xdc。
4AD7606 FPGA程序设计
4.1 AD7606SPI.v
  1. /*******************************AD7606 SPI串行采样*********************
  2. --以下是米联客设计的AD7606 SPI串行采样驱动程序
  3. --1.代码简洁,占用极少逻辑资源,代码结构清晰,逻辑设计严谨
  4. --2.AD7606可以工作于并行模式,和串行模式,串行模式可以使用更少的IO
  5. --3.AD7606最高可以工作于200K 8通道同时采样,默认就是工作于200K 采样,SPI_DIV 和T5US_DIV根据不同的系统时钟需要正确设置
  6. *********************************************************************/

  7. `timescale 1ns / 1ns//仿真时间刻度/精度

  8. module uispi7606
  9. (
  10. input          I_ad_clk,         //系统时钟输入   
  11. input           I_ad_rst,         //系统复位输入
  12. input          I_ad_busy,        //ad7606 忙标志位
  13. output [2:0]   O_ad_os,          //ad7606 过采样倍率选择,本驱动不使用
  14. output          O_ad_cs,          //ad7606 CS信号输出,低电平SPI数据线输出AD7606寄存器数据
  15. output reg        O_ad_sclk,        //ad7606 SCLK时钟输出
  16. output         O_ad_rst,         //ad7606 复位输出
  17. output          O_ad_convsta,     //ad7606 A组通道转换
  18. output          O_ad_convstb,     //ad7606 B组通道转换
  19. output          O_ad_range,       //ad7606 模拟输入范围,设置1范围:±10V,设置0范围±5V
  20. input           I_O_ad_out_a,       //串行A组通道采集输入,V1,V2,V3,V4  
  21. input           I_O_ad_out_b,       //串行B组通道采集输入, V5,V6,V7,V8  
  22. output reg [63:0] O_ad_out_a,       //A组通道采集有效数据输出
  23. output reg [63:0] O_ad_out_b,       //B组通道采集有效数据输出
  24. output            O_ad_cap_en                  //采集完成使能
  25. );
  26. localparam  CLK_FREQ =  100000000;
  27. localparam  SET_5US  =  5; //5us周期
  28. localparam  T5US_DIV =  CLK_FREQ*SET_5US/1000000 -1; //计算5us 分频系数
  29. localparam  SPI_DIV  =  CLK_FREQ/16666666 -1 ;//产生SPI时钟,设置最高16.666667MHZ

  30. assign O_ad_range = 1'b1;    //±10V真直流输入范围
  31. assign O_ad_os    = 3'b000;  //无过采样

  32. //ad复位时间高电平,复位时间最少50ns
  33. reg [23: 0] rst_cnt;
  34. assign O_ad_rst   = !rst_cnt[23];
  35. always@(posedge I_ad_clk or posedge I_ad_rst)begin        
  36.     if(I_ad_rst)
  37.         rst_cnt  <= 24'd0;
  38.     else if(!rst_cnt[23])
  39.         rst_cnt  <= rst_cnt + 1'b1;
  40. end      
  41.    
  42. //设置采样频率,AD7606为8通道可以工作于200Kbps采样率,因此采样周期为5us
  43. reg [9:0] tcnt5us;
  44. wire cycle_end = (tcnt5us == T5US_DIV);
  45. always@ (posedge I_ad_clk)begin   
  46.      if(O_ad_rst)
  47.          tcnt5us <= 10'd0;
  48.      else if(tcnt5us < T5US_DIV)
  49.          tcnt5us <= tcnt5us + 1'b1;
  50.      else
  51.          tcnt5us <= 10'd0;
  52. end

  53. localparam [9:0] SPI_DIV1    = SPI_DIV/2; //半周期分频
  54. reg [9:0] clk_div = 10'd0;//分频计数器   

  55. //SPI 时钟分频,对于200K采样,设置20M时钟
  56. always@(posedge I_ad_clk)begin
  57.     if(clk_div < SPI_DIV)  
  58.         clk_div <= clk_div + 1'b1;
  59.     else
  60.         clk_div <= 10'd0;
  61. end

  62. //产生SPI时钟
  63. wire clk_en1 = (clk_div == SPI_DIV1);// 半周期使能,控制输出0
  64. wire clk_en2 = (clk_div == SPI_DIV);//  半周期使能,控制输出1

  65. always@(posedge I_ad_clk)begin
  66.      if(clk_en2) O_ad_sclk <= 1'b1; //输出高电平
  67.     else if(clk_en1) O_ad_sclk <= 1'b0; //输出高低平
  68. end

  69. //AD转换状态机
  70. reg [1:0] AD_S;
  71. reg ad_convst; //ADC转换控制信号,A组通道和B组通道采用同一通道
  72. //ADC工作于SPI模式,以及边读边转换模式,本次数据转换的同时,可以读出前一次转换的结果
  73. assign O_ad_cs = ~((AD_S == 2'd3)&&I_ad_busy);//当AD7606工作在串行模式,cs=0代表输出通过SPI数据总线,输出之前的采样数据
  74. assign O_ad_convsta = ad_convst; //ADC转换控制信号,A组通道和B组通道采用同一通道
  75. assign O_ad_convstb = ad_convst; //ADC转换控制信号,A组通道和B组通道采用同一通道

  76. always @(posedge I_ad_clk)
  77. begin
  78.     if(O_ad_rst||I_ad_rst)begin
  79.         ad_convst <= 1'b1;     
  80.         AD_S <= 2'd0;
  81.     end
  82.     else begin
  83.         case(AD_S)  
  84.         2'd0:if(clk_en2)begin    //clk_en2,控制SCLK输出1,因此这里相当于SCLK上升沿
  85.              ad_convst <= 1'b0;  //设置ad_convst=0
  86.              AD_S <= 2'd1;//下一状态
  87.         end           
  88.         2'd1:if(clk_en2)begin //延迟50ns,ad_convst低电平至少25ns,对于SCLK时钟是20MHZ,所以这里ad_convst低电平是50ns
  89.              ad_convst <= 1'b1;//ad_convst 低电平50ns后拉高为高电平
  90.              AD_S <= 2'd2;//下一状态
  91.         end
  92.         2'd2:if(clk_en2&&I_ad_busy)//延迟50ns,并且等待busy高,只要ADC正常工作,busy必然为高,说明ADC处于采样转换下
  93.              AD_S <= 2'd3;            
  94.         2'd3:if(cycle_end)//ADC转换时间最大4.2us,5us周期结束,代表本次8通道完全采集结束
  95.              AD_S <= 2'd0; //回到初始状态,进行下一次采样   
  96.         endcase   
  97.      end            
  98. end

  99. //SPI采样
  100. reg [7 : 0] nbits; // bits计数器,用于计数完成了从AD7606 SPI总线读出的bits数
  101. wire ad_cap_en_r1 = (nbits==8'd64); //数据同步输出使能
  102. reg  ad_cap_en_r2 = 1'b0; //数据同步输出使能寄存一次
  103. assign O_ad_cap_en = ({ad_cap_en_r1,ad_cap_en_r2}==2'b10);//高电平输出系统时钟的一个周期

  104. always@(posedge I_ad_clk) begin //寄存一次ad_cap_en_r1
  105.     ad_cap_en_r2 <= ad_cap_en_r1;
  106. end

  107. //当CS信号为低电平,每个SCL的下降沿输出采样数据,每组通道采样64bits
  108. wire cap_en  = (!O_ad_cs)&&clk_en1&&(nbits<8'd64);

  109. //ADC 串并转换模块
  110. always@(posedge I_ad_clk) begin
  111.     if(O_ad_rst) begin //ADC复位期间重置相关寄存器
  112.         O_ad_out_a <= 64'd0;
  113.         O_ad_out_b <= 64'd0;
  114.         nbits    <= 8'd0;
  115.     end
  116.     else if(O_ad_cs)begin //高电平,重置  nbits   
  117.         nbits   <= 8'd0;                       
  118.     end   
  119.     else if(cap_en)begin//当CS信号为低电平,每个SCL的下降沿采样数据,每组通道采样64bits
  120.         nbits    <= nbits + 1'b1; //
  121.         O_ad_out_a <= {O_ad_out_a[62:0],I_O_ad_out_a};//保存A组通道数据,V1~V4,每个通道16bits
  122.         O_ad_out_b <= {O_ad_out_b[62:0],I_O_ad_out_b};//保存B组通道数据,V5~V8,每个通道16bits
  123.     end                                                                                                                                    
  124. end
  125.                   
  126. endmodule
复制代码

4.2 AD7606SPI程序分析
本文的SPI接口不是标准的SPI接口,主要区别是传输位宽达到了64bit,而之前我们学习SPI通信的文章是采用的标准的SPI接口去讲解的。标准的接口使用起来会比较方便,但是对于我们这种ADC采集往往编写专用的SPI接口更加实用。
本文的ADC采集程序主要需要注意3点:
1、ADC转换状态机
这个状态机需要设置相关的AD采集转换采集时序
2、SPI采样时序
这个比较简单,和我们之前讲解过标准的SPI接口类似,这里只是把位宽扩展到64bit
3、关键功能设计
1)、时钟单元
时钟单元通过时钟IP产生一个100MHZ的时钟用于AD转换采集时序的状态机以及SPI7606 IP核内部使用,SPI7606 IP核通过计数器,生成采样频率及SPI时钟。
  1. //设置采样频率,AD7606为8通道可以工作于200Kbps采样率,因此采样周期为5us
  2. reg [9:0] tcnt5us;
  3. wire cycle_end = (tcnt5us == T5US_DIV);
  4. always@ (posedge I_ad_clk)begin   
  5.      if(O_ad_rst)
  6.          tcnt5us <= 10'd0;
  7.      else if(tcnt5us < T5US_DIV)
  8.          tcnt5us <= tcnt5us + 1'b1;
  9.      else
  10.          tcnt5us <= 10'd0;
  11. end

  12. localparam [9:0] SPI_DIV1    = SPI_DIV/2; //半周期分频
  13. reg [9:0] clk_div = 10'd0;//分频计数器   

  14. //SPI 时钟分频,对于200K采样,设置20M时钟
  15. always@(posedge I_ad_clk)begin
  16.     if(clk_div < SPI_DIV)  
  17.         clk_div <= clk_div + 1'b1;
  18.     else
  19.         clk_div <= 10'd0;
  20. end

  21. //产生SPI时钟
  22. wire clk_en1 = (clk_div == SPI_DIV1);// 半周期使能,控制输出0
  23. wire clk_en2 = (clk_div == SPI_DIV);//  半周期使能,控制输出1

  24. always@(posedge I_ad_clk)begin
  25.      if(clk_en2) O_ad_sclk <= 1'b1; //输出高电平
  26.     else if(clk_en1) O_ad_sclk <= 1'b0; //输出高低平
  27. end
复制代码

2)、AD7606复位信号
AD7606的复位时间设置为41943040ns远大于芯片要求的50ns,所以满足要求。
  1. //ad复位时间高电平,复位时间最少50ns
  2. reg [23: 0] rst_cnt;
  3. assign O_ad_rst   = !rst_cnt[23];
  4. always@(posedge I_ad_clk or posedge I_ad_rst)begin        
  5.     if(I_ad_rst)
  6.         rst_cnt  <= 24'd0;
  7.     else if(!rst_cnt[23])
  8.         rst_cnt  <= rst_cnt + 1'b1;
  9. end   
复制代码

3)、采样周期计数器
为了确保200kbps的采样率,我们需要设置一个时间计数器,每间隔5us,定义是T5US_DIV  = 10'd999进行下一次的采样。
  1. //设置采样频率,AD7606为8通道可以工作于200Kbps采样率,因此采样周期为5us
  2. reg [9:0] tcnt5us;
  3. wire cycle_end = (tcnt5us == T5US_DIV);
  4. always@ (posedge I_ad_clk)begin   
  5.      if(O_ad_rst)
  6.          tcnt5us <= 10'd0;
  7.      else if(tcnt5us < T5US_DIV)
  8.          tcnt5us <= tcnt5us + 1'b1;
  9.      else
  10.          tcnt5us <= 10'd0;
  11. end
复制代码

4)、AD转换及采样状态机
AD7606芯片的模拟转数字过程由状态机控制,一些控制信号必须满足芯片手册给出的时序要求。我们可以结合程序,以及芯片给出的AD转换时序图分析程序。
7f845c13ed89434f902146075cb29434.jpg
上图种的,t1、 t5 、tReset等时间参数都可以在芯片手册里面找到,我们的状态机设计的AD控制及转换时序需要满足上图的要求。
  1. //AD转换状态机
  2. reg [1:0] AD_S;
  3. reg ad_convst; //ADC转换控制信号,A组通道和B组通道采用同一通道
  4. //ADC工作于SPI模式,以及边读边转换模式,本次数据转换的同时,可以读出前一次转换的结果
  5. assign O_ad_cs = ~((AD_S == 2'd3)&&I_ad_busy);//当AD7606工作在串行模式,cs=0代表输出通过SPI数据总线,输出之前的采样数据
  6. assign O_ad_convsta = ad_convst; //ADC转换控制信号,A组通道和B组通道采用同一通道
  7. assign O_ad_convstb = ad_convst; //ADC转换控制信号,A组通道和B组通道采用同一通道

  8. always @(posedge I_ad_clk)
  9. begin
  10.     if(O_ad_rst||I_ad_rst)begin
  11.         ad_convst <= 1'b1;     
  12.         AD_S <= 2'd0;
  13.     end
  14.     else begin
  15.         case(AD_S)  
  16.         2'd0:if(clk_en2)begin    //clk_en2,控制SCLK输出1,因此这里相当于SCLK上升沿
  17.              ad_convst <= 1'b0;  //设置ad_convst=0
  18.              AD_S <= 2'd1;//下一状态
  19.         end           
  20.         2'd1:if(clk_en2)begin //延迟50ns,ad_convst低电平至少25ns,对于SCLK时钟是20MHZ,所以这里ad_convst低电平是50ns
  21.              ad_convst <= 1'b1;//ad_convst 低电平50ns后拉高为高电平
  22.              AD_S <= 2'd2;//下一状态
  23.         end
  24.         2'd2:if(clk_en2&&I_ad_busy)//延迟50ns,并且等待busy高,只要ADC正常工作,busy必然为高,说明ADC处于采样转换下
  25.              AD_S <= 2'd3;            
  26.         2'd3:if(cycle_end)//ADC转换时间最大4.2us,5us周期结束,代表本次8通道完全采集结束
  27.              AD_S <= 2'd0; //回到初始状态,进行下一次采样   
  28.         endcase   
  29.      end            
  30. end
复制代码

4)、SPI采样单元
完成一次64bit数据传输需要64个时钟,采样的条件需满足三个(!ad_cs_o)&&clk_en1&&(nbits<8'd64),下降沿的时候开始采样,通过nbits计数。这里只要简单实用移位寄存器实现操作就可以。

  1. //SPI采样
  2. reg [7 : 0] nbits; // bits计数器,用于计数完成了从AD7606 SPI总线读出的bits数
  3. wire ad_cap_en_r1 = (nbits==8'd64); //数据同步输出使能
  4. reg  ad_cap_en_r2 = 1'b0; //数据同步输出使能寄存一次
  5. assign O_ad_cap_en = ({ad_cap_en_r1,ad_cap_en_r2}==2'b10);//高电平输出系统时钟的一个周期

  6. always@(posedge I_ad_clk) begin //寄存一次ad_cap_en_r1
  7.     ad_cap_en_r2 <= ad_cap_en_r1;
  8. end

  9. //当CS信号为低电平,每个SCL的下降沿输出采样数据,每组通道采样64bits
  10. wire cap_en  = (!O_ad_cs)&&clk_en1&&(nbits<8'd64);

  11. //ADC 串并转换模块
  12. always@(posedge I_ad_clk) begin
  13.     if(O_ad_rst) begin //ADC复位期间重置相关寄存器
  14.         O_ad_out_a <= 64'd0;
  15.         O_ad_out_b <= 64'd0;
  16.         nbits    <= 8'd0;
  17.     end
  18.     else if(O_ad_cs)begin //高电平,重置  nbits   
  19.         nbits   <= 8'd0;                       
  20.     end   
  21.     else if(cap_en)begin//当CS信号为低电平,每个SCL的下降沿采样数据,每组通道采样64bits
  22.         nbits    <= nbits + 1'b1; //
  23.         O_ad_out_a <= {O_ad_out_a[62:0],I_O_ad_out_a};//保存A组通道数据,V1~V4,每个通道16bits
  24.         O_ad_out_b <= {O_ad_out_b[62:0],I_O_ad_out_b};//保存B组通道数据,V5~V8,每个通道16bits
  25.     end                                                                                                                                    
  26. end
复制代码
  1. /*******************************AD7606 SPI串行仿真模型驱动*********************
  2. --以下是米联客设计的AD7606 SPI串行仿真驱动程序
  3. --模拟AD7606的SPI 数据输出时序
  4. *********************************************************************/

  5. `timescale 1ns / 1ns//仿真时间刻度/精度

  6. module ad7606(
  7. output  reg     O_ad_busy,            //系统时钟输入   
  8. input          I_ad_cs,              //ad7606 CS信号输入,低电平SPI数据线输出AD7606寄存器数据
  9. input          I_ad_sclk,            //ad7606 SCLK时钟输入
  10. input          I_ad_reset,           //ad7606 复位输入
  11. input          I_ad_convsta,         //ad7606 A组通道转换开始
  12. input          I_ad_convstb,         //ad7606 B组通道转换开始
  13. input           I_ad_range,           //ad7606 模拟输入范围,设置1范围:±10V,设置0范围±5V
  14. output          O_ad_out_a,           //A组通道采集有效数据输出
  15. output          O_ad_out_b            //B组通道采集有效数据输出
  16. );

  17. //仿真信号,仿真busy忙
  18. always @(posedge I_ad_convsta or posedge I_ad_reset) begin
  19. if(I_ad_reset)begin
  20.    O_ad_busy = 1'b0;
  21. end
  22. else begin
  23.    #10;
  24.    O_ad_busy = 1'b1;
  25.    #4100; //busy 持续4.1us
  26.    O_ad_busy = 1'b0;
  27. end
  28. end

  29. reg       first ;        //通过first设置,第一个时钟,不移位  
  30. reg[15:0] ad_da16 = 16'd0; //ad_da16,ADC的寄存器值
  31. reg[63:0] ad_data;         //4个16bit ADC值,放入此寄存器移位输出

  32. assign O_ad_out_a = ad_data[63]; //a通道,SPI数据总线输出
  33. assign O_ad_out_b = ad_data[63]; //b通道,SPI数据总线输出

  34. always @(posedge I_ad_sclk or posedge I_ad_reset ) begin
  35. if(I_ad_reset)begin
  36.    ad_data = 64'd0;
  37.    first   = 1'b0;
  38. end   
  39. else begin
  40.     if(!I_ad_cs) begin //当ad的CS为低电平,模拟AD寄存器串行数据输出
  41.         if(first == 1'b0) //通过first设置,第一个时钟,不移位
  42.            first = 1'b1;  
  43.          else
  44.         ad_data[63:0] = {ad_data[62:0],ad_data[63]}; //模拟输出ADC的采集
  45.    end
  46.     else if(I_ad_cs)begin//当ad的CS为高电平
  47.         first   = 1'b0;
  48.         ad_data ={ad_da16,ad_da16,ad_da16,ad_da16};   //初始化需要发送的ADC模拟值
  49.     end   
  50.       
  51. end
  52. end

  53. //每一个CS 上升沿,模拟ADC的值加1
  54. always @(posedge I_ad_cs) begin
  55.     ad_da16 = ad_da16[12:0] + 1'b1;   
  56. end   
  57.    
  58.    
  59. endmodule
  60.    
复制代码


tb_AD7606SPI.v仿真文件
  1. /*******************************AD7606 SPI串行采集仿真*********************
  2. *********************************************************************/
  3. `timescale 1ns / 1ns//仿真时间刻度/精度

  4. module tb_AD7606SPI();

  5. reg I_sysclk_p;
  6. reg I_sysclk_n; //系统时钟

  7. initial begin
  8.     #100 I_sysclk_p = 1'b0;
  9.     #100 I_sysclk_n = 1'b1;
  10. end

  11. always #5 I_sysclk_p = !I_sysclk_p;
  12. always #5 I_sysclk_n = !I_sysclk_n; //100MHZ 系统时钟

  13. //AD7606相关信号定义
  14. wire I_ad_busy;
  15. wire O_ad_cs;
  16. wire O_ad_sclk;
  17. wire O_ad_reset;
  18. wire O_ad_convsta;
  19. wire O_ad_convstb;
  20. wire O_ad_range;
  21. wire I_O_ad_out_a;
  22. wire I_O_ad_out_b;

  23. //例化AD7606的采集模块
  24. ad7606_top ad7606_top_inst
  25. (
  26. .I_sysclk_p(I_sysclk_p),
  27. .I_sysclk_n(I_sysclk_n),  //系统时钟输入           
  28. .I_ad_busy(I_ad_busy),   //ad7606 忙标志位输入      
  29. .O_ad_cs(O_ad_cs),       //ad7606 CS信号输出,低电平SPI数据线输出AD7606寄存器数据         
  30. .O_ad_sclk(O_ad_sclk),   //ad7606 SCLK时钟输出         
  31. .O_ad_rst(O_ad_reset),   //ADC复位输出         
  32. .O_ad_convsta(O_ad_convsta),  //ad7606 A组通道转换      
  33. .O_ad_convstb(O_ad_convstb),  //ad7606 B组通道转换         
  34. .O_ad_range(O_ad_range), //ad7606 模拟输入范围,设置1范围:±10V,设置0范围±5V
  35. .I_O_ad_out_a(I_O_ad_out_a), //A组通道采集有效数据输入
  36. .I_O_ad_out_b(I_O_ad_out_b)  //B组通道采集有效数据输入
  37. );

  38. //例化 AD7606 的SPI 仿真驱动   
  39. ad7606 ad7606_inst
  40. (
  41. .O_ad_busy(I_ad_busy),   //ad7606 忙标志位 输出               
  42. .I_ad_cs(O_ad_cs),    //ad7606 CS信号输入,低电平SPI数据线输出AD7606寄存器数据                  
  43. .I_ad_sclk(O_ad_sclk),   //ad7606 SCLK时钟输入           
  44. .I_ad_reset(O_ad_reset), //ADC复位输入         
  45. .I_ad_convsta(O_ad_convsta), //ad7606 A组通道转换         
  46. .I_ad_convstb(O_ad_convstb),  //ad7606 B组通道转换      
  47. .I_ad_range(O_ad_range),//ad7606 模拟输入范围,设置1范围:±10V,设置0范围±5V
  48. .O_ad_out_a(I_O_ad_out_a),//A组通道采集有效数据输出
  49. .O_ad_out_b(I_O_ad_out_b)//B组通道采集有效数据输出
  50. );   
  51. endmodule
复制代码


仿真波形图
4bd0b7720a8340f090bb415a74e699bc.jpg
在5us的采样周期内,我们可以看到convsta/convsta从高到低后,AD转换开始,busy信号变高,之后CS变低,并且可以看到CS的结束在busy信号后,所以可以确保最后读取的数据时已经转换好的数据。
9838b0c2432346a19b95824ada1bd10d.jpg
上图通过把数据以模拟信号的方式显示可以看到锯齿波。
6硬件接线
我们使用信号发生器产生两路频率分别为600HZ、300HZ,幅度为5V的正弦波。
7d9a01a7b81345768bb699d76159288a.jpg

(该教程为通用型教程,教程中仅展示一款示例开发板的连接方式,具体连接方式以所购买的开发板型号以及结合配套代码管脚约束为准。)
本实验注意采我们的cep跳线帽跳线1.8V,采用1.8V的FEP-DAQ7606子卡。请确保下载器和开发板已经正确连接,另外需要把核心板上的2P模式开关设置到JTAG模式,即ON ON,并且开发板已经上电。(注意JTAG端子不支持热插拔,而USB接口支持,所以在不通电的情况下接通好JTAG后,再插入USB到电脑,之后再上电,以免造成JTAG IO损坏)
324c6bbc887b4043b08e28234896deed.jpg
7实验结果
设置Capture mode,设置cap_en信号为高时进行采样
bdc09e788e0f4712a90f48bfb8866e2f.jpg
测试输入波形只看通道1和通道2的输入,其他通道读者可以自行测试,结果一样。
4cbfbdf7fc2c459ebf78e4140d384b37.jpg



您需要登录后才可以回帖 登录 | 立即注册

本版积分规则