OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 1143|回复: 0

[国产FPGA] 《ATK-DFPGL22G 之FPGA开发指南》第三十四章 高速AD/DA实验

[复制链接]

1117

主题

1128

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4666
金钱
4666
注册时间
2019-5-8
在线时间
1224 小时
发表于 2023-12-13 14:32:55 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 2023-12-13 14:32 编辑

第三十四章 高速AD/DA实验


1)实验平台:正点原子 ATK-DFPGL22G开发板

2) 章节摘自【正点原子】ATK-DFPGL22G之FPGA开发指南_V1.0


4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz-PGL22G.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)FPGA技术交流QQ群:435699340

155537c2odj87vz1z9vj6l.jpg

155537nfqovl2gg9faaol9.png

ADC/DAC(Analog to Digital Converter/ Digital to Analog Converter,即模数转换器/数模转换器)是大多数系统中必不可少的组成部件,用于将连续的模拟信号转换成离散的数字信号,或者将离散的数字信号转换成连续的模拟信号,它们是连接模电电路和数字电路必不可少的桥梁。在很多场合下,ADC/DAC的转换速度甚至直接决定了整个系统的运行速度。本章我们将使用高速DA芯片实现数模转换,产生正弦波模拟电压信号,并通过高速AD芯片将模拟信号转换成数字信号。
本章包括以下几个部分:
1.1高速AD-DA简介
1.2实验任务
1.3硬件设计
1.4程序设计
1.5下载验证

1.1 高速AD/DA简介
本章我们使用的AD-DA模块是正点原子推出的一款高速模数-数模转换模块(ATK_HS_AD_DA),高速AD转换芯片和高速DA转换芯片都是由ADI公司生产的,分别是AD9280/3PA9280(两款芯片兼容)和AD9708/3PD9708(两款芯片兼容)。
ATK_HS_AD_DA模块的硬件结构图如下图所示。                              
image002.png
图 34.1.1 ATK_HS_AD_DA模块硬件结构图
由上可知,AD9708芯片输出的是一对差分电流信号,为了防止受到噪声干扰,电路中接入了低通滤波器,然后通过高性能和高带宽的运放电路,实现差分变单端以及幅度调节等功能,使整个电路性能得到了最大限度的提升,最终输出的模拟电压范围是-5V~+5V。
AD9280芯片的输入模拟电压转换范围是0V~2V,所以电压输入端需要先经过电压衰减电路,使输入的-5V~+5V之间的电压衰减到0V~2V之间,然后经过AD9280芯片将模拟电压信号转换成数字信号。
下面我们分别介绍下这两个芯片。
AD9708芯片
AD9708是ADI公司(Analog Devices,Inc.,亚德诺半导体技术有限公司)生产的TxDAC系列数模转换器,具有高性能、低功耗的特点。AD9708的数模转换位数为8位,最大转换速度为125MSPS(每秒采样百万次Million Samples per Second)。
AD9708的内部功能框图如下图所示:
image003.png
图 34.1.2 AD9708内部功能框图
AD9708在时钟(CLOCK)的驱动下工作,内部集成了+1.2V参考电压(+1.20V REF)、运算放大器、电流源(CURRENT SOURCE ARRAY)和锁存器(LATCHES)。两个电流输出端IOUTA和IOUTB为一对差分电流,当输入数据为0(DB7~DB0=8’h00)时,IOUTA的输出电流为0,而IOUTB的输出电流达到最大,最大值的大小跟参考电压有关;当输入数据全为高点平(DB7~DB0=8’hff)时,IOUTA的输出电流达到最大,最大值的大小跟参考电压有关,而IOUTB的输出电流为0。
AD9708必须在时钟的驱动下才能把数据写入片内的锁存器中,其触发方式为上升沿触发,AD9708的时序图如下图所示:
image005.png
图 34.1.3 AD9708时序图
上图中的DBO-DB7和CLOCK是AD9708的8位输入数据和输入时钟,IOUTA和IOUTB为AD9708输出的电流信号。由上图可知,数据在时钟的上升沿锁存,因此我们可以在时钟的下降沿发送数据。需要注意的是,CLOCK的时钟频率越快,AD9708的数模转换速度越快,AD9708的时钟频率最快为125Mhz。
IOUTA和IOUTB为AD9708输出的一对差分电流信号,通过外部电路低通滤波器与运放电路输出模拟电压信号,电压范围是-5V至+5V之间。当输入数据等于0时,AD9708输出的电压值为5V;当输入数据等于255(8’hff)时,AD9708输出的电压值为-5V。
AD9708是一款数字信号转模拟信号的器件,内部没有集成DDS(Direct Digital Synthesizer,直接数字式频率合成器)的功能,但是可以通过控制AD9708的输入数据,使其模拟DDS的功能。例如,我们使用AD9708输出一个正弦波模拟电压信号,那么我们只需要将AD9708的输入数据按照正弦波的波形变化即可,下图为AD9708的输入数据和输出电压值按照正弦波变化的波形图。
image008.png
图 34.1.4 AD9708正弦波数据(左)、电压值(右)
由上图可知,数据在0至255之间按照正弦波的波形变化,最终得到的电压也会按照正弦波波形变化,当输入数据重复按照正弦波的波形数据变化时,那么AD9708就可以持续不断的输出正弦波的模拟电压波形。需要注意的是,最终得到的AD9708的输出电压变化范围由其外部电路决定的,当输入数据为0时,AD9708输出+5V的电压;当输入数据为255时,AD9708输出-5V的电压。
由此可以看出,只要输入的数据控制的得当,AD9708可以输出任意波形的模拟电压信号,包括正弦波、方波、锯齿波、三角波等波形。
在了解完高速DA转换芯片后,接下来我们介绍下高速AD转换芯片AD9280。

AD9280芯片
AD9280是ADI公司生产的一款单芯片、8位、32MSPS(Million Samples Per Second,每秒采样百万次)模数转换器,具有高性能、低功耗的特点。
AD9280的内部功能框图如下图所示:
image009.png
图 34.1.5 AD9280内部功能框图
AD9280在时钟(CLK)的驱动下工作,用于控制所有内部转换的周期;AD9280内置片内采样保持放大器(SHA),同时采用多级差分流水线架构,保证了32MSPS的数据转换速率下全温度范围内无失码;AD9280内部集成了可编程的基准源,根据系统需要也可以选择外部高精度基准满足系统的要求。
AD9280输出的数据以二进制格式表示,当输入的模拟电压超出量程时,会拉高OTR(out-of-range)信号;当输入的模拟电压在量程范围内时,OTR信号为低电平,因此可以通过OTR信号来判断输入的模拟电压是否在测量范围内。
AD9280的时序图如下图所示:
image011.png
图 34.1.6 AD9280时序图
模拟信号转换成数字信号并不是当前周期就能转换完成,从采集模拟信号开始到输出数据需要经过3个时钟周期。比如上图中在时钟CLK的上升沿沿采集的模拟电压信号S1,经过3个时钟周期后(实际上再加上25ns的时间延时),输出转换后的数据DATA1。需要注意的是,AD9280芯片的最大转换速度是32MSPS,即输入的时钟最大频率为32MHz。
AD9280支持输入的模拟电压范围是0V至2V,0V对应输出的数字信号为0,2V对应输出的数字信号为255。而AD9708经外部电路后,输出的电压范围是-5V~+5V,因此在AD9280的模拟输入端增加电压衰减电路,使-5V~+5V之间的电压转换成0V至2V之间。那么实际上对我们用户使用来说,当AD9280的模拟输入接口连接-5V电压时,AD输出的数据为0;当AD9280的模拟输入接口连接+5V电压时,AD输出的数据为255。
当AD9280模拟输入端接-5V至+5V之间变化的正弦波电压信号时,其转换后的数据也是成正弦波波形变化,转换波形如下图所示:
image014.png
图 34.1.7 AD9280正弦波模拟电压值(左)、数据(右)
由上图可知,输入的模拟电压范围在-5V至5V之间,按照正弦波波形变化,最终得到的数据也是按照正弦波波形变化。

1.2 实验任务
本节实验任务是使用ATK-DFPGL22G开发板及高速AD-DA扩展模块(ATK_HS_AD_DA模块)实现数模及模数的转换。首先ATK-DFPGL22G开发板产生正弦波变化的数字信号,经过DA芯片后转换成模拟信号,将DA的模拟电压输出端连接至AD的模拟电压输入端,AD芯片将模拟信号转换成数字信号,然后通过ILA观察数字信号的波形是否按照正弦波波形变化。

1.3 硬件设计
ATK_HS_AD_DA模块由DA转换芯片(AD9708)和AD转换芯片(AD9280)组成。AD9708的原理图如下图所示。
image015.png
图 34.3.1 AD9708原理图
由上图可知,AD9708输出的一对差分电流信号先经过滤波器,再经过运放电路得到一个单端的模拟电压信号。图中右侧的W1为滑动变阻器,可以调节输出的电压范围,推荐通过调节滑动变阻器,使输出的电压范围在-5V至+5V之间,从而达到AD转换芯片的最大转换范围。
AD9280的原理图如下图所示。
image017.png
图 34.3.2 AD9280原理图
上图中输入的模拟信号SMA_IN(VI)经过衰减电路后得到AD_IN2(VO)信号,两个模拟电压信号之间的关系是VO=VI/5+1,即当VI=5V时,VO=2V;VI=-5V时,VO=0V。
ATK_HS_AD_DA模块的实物图如下图所示。
image019.png
图 34.3.3 ATK-HS-AD-DA模块实物图
需要注意的是,在进行该实验之前,一定要确认数码管上方的P6跳线帽连接如下图所示,主要原因是该跳线帽负责控制BANK R1的电压,可以选择1.8V或者是3.3V,本实验用到的模块需要的驱动电平是3.3V,所以我们将该BANK的电压修改到3.3V,对应开发板上左边的P2排针端口电平也会来到3.3V。
image021.jpg
图 34.3.4 P6跳线连接示意图
本实验中,各端口信号的管脚分配如下表所示。
QQ截图20231213142511.png
表 34.3.1 高速AD-DA转换实验管脚分配
对应的UCF约束语句如下所示:
  1. define_attribute {p:sys_clk} {PAP_IO_DIRECTION}{INPUT}
  2. define_attribute {p:sys_clk}{PAP_IO_LOC} {B5}
  3. define_attribute {p:sys_clk}{PAP_IO_VCCIO} {3.3}
  4. define_attribute {p:sys_clk}{PAP_IO_STANDARD} {LVCMOS33}
  5. define_attribute {p:sys_clk}{PAP_IO_NONE} {TRUE}
  6. define_attribute {p:sys_rst_n} {PAP_IO_DIRECTION}{INPUT}
  7. define_attribute {p:sys_rst_n}{PAP_IO_LOC} {G5}
  8. define_attribute {p:sys_rst_n}{PAP_IO_VCCIO} {1.5}
  9. define_attribute {p:sys_rst_n}{PAP_IO_STANDARD} {LVCMOS15}
  10. define_attribute {p:sys_rst_n}{PAP_IO_NONE} {TRUE}
  11. define_attribute {p:da_data[7]}{PAP_IO_DIRECTION} {OUTPUT}
  12. define_attribute {p:da_data[7]}{PAP_IO_LOC} {J17}
  13. define_attribute {p:da_data[7]}{PAP_IO_VCCIO} {1.2}
  14. define_attribute {p:da_data[7]}{PAP_IO_STANDARD} {LVCMOS12}
  15. define_attribute {p:da_data[7]}{PAP_IO_DRIVE} {2}
  16. define_attribute {p:da_data[7]}{PAP_IO_NONE} {TRUE}
  17. define_attribute {p:da_data[7]}{PAP_IO_SLEW} {SLOW}
  18. define_attribute {p:da_data[6]}{PAP_IO_DIRECTION} {OUTPUT}
  19. define_attribute {p:da_data[6]}{PAP_IO_LOC} {H17}
  20. define_attribute {p:da_data[6]}{PAP_IO_VCCIO} {1.2}
  21. define_attribute {p:da_data[6]}{PAP_IO_STANDARD} {LVCMOS12}
  22. define_attribute {p:da_data[6]}{PAP_IO_DRIVE} {2}
  23. define_attribute {p:da_data[6]}{PAP_IO_NONE} {TRUE}
  24. define_attribute {p:da_data[6]}{PAP_IO_SLEW} {SLOW}
  25. define_attribute {p:da_data[5]}{PAP_IO_DIRECTION} {OUTPUT}
  26. define_attribute {p:da_data[5]}{PAP_IO_LOC} {J18}
  27. define_attribute {p:da_data[5]}{PAP_IO_VCCIO} {1.2}
  28. define_attribute {p:da_data[5]}{PAP_IO_STANDARD} {LVCMOS12}
  29. define_attribute {p:da_data[5]}{PAP_IO_DRIVE} {2}
  30. define_attribute {p:da_data[5]}{PAP_IO_NONE} {TRUE}
  31. define_attribute {p:da_data[5]}{PAP_IO_SLEW} {SLOW}
  32. define_attribute {p:da_data[4]}{PAP_IO_DIRECTION} {OUTPUT}
  33. define_attribute {p:da_data[4]}{PAP_IO_LOC} {H18}
  34. define_attribute {p:da_data[4]}{PAP_IO_VCCIO} {1.2}
  35. define_attribute {p:da_data[4]}{PAP_IO_STANDARD} {LVCMOS12}
  36. define_attribute {p:da_data[4]}{PAP_IO_DRIVE} {2}
  37. define_attribute {p:da_data[4]}{PAP_IO_NONE} {TRUE}
  38. define_attribute {p:da_data[4]}{PAP_IO_SLEW} {SLOW}
  39. define_attribute {p:da_data[3]}{PAP_IO_DIRECTION} {OUTPUT}
  40. define_attribute {p:da_data[3]}{PAP_IO_LOC} {L17}
  41. define_attribute {p:da_data[3]}{PAP_IO_VCCIO} {1.2}
  42. define_attribute {p:da_data[3]}{PAP_IO_STANDARD} {LVCMOS12}
  43. define_attribute {p:da_data[3]} {PAP_IO_DRIVE}{2}
  44. define_attribute {p:da_data[3]}{PAP_IO_NONE} {TRUE}
  45. define_attribute {p:da_data[3]}{PAP_IO_SLEW} {SLOW}
  46. define_attribute {p:da_data[2]}{PAP_IO_DIRECTION} {OUTPUT}
  47. define_attribute {p:da_data[2]}{PAP_IO_LOC} {K17}
  48. define_attribute {p:da_data[2]}{PAP_IO_VCCIO} {1.2}
  49. define_attribute {p:da_data[2]}{PAP_IO_STANDARD} {LVCMOS12}
  50. define_attribute {p:da_data[2]}{PAP_IO_DRIVE} {2}
  51. define_attribute {p:da_data[2]}{PAP_IO_NONE} {TRUE}
  52. define_attribute {p:da_data[2]}{PAP_IO_SLEW} {SLOW}
  53. define_attribute {p:da_data[1]}{PAP_IO_DIRECTION} {OUTPUT}
  54. define_attribute {p:da_data[1]}{PAP_IO_LOC} {L18}
  55. define_attribute {p:da_data[1]}{PAP_IO_VCCIO} {1.2}
  56. define_attribute {p:da_data[1]}{PAP_IO_STANDARD} {LVCMOS12}
  57. define_attribute {p:da_data[1]}{PAP_IO_DRIVE} {2}
  58. define_attribute {p:da_data[1]}{PAP_IO_NONE} {TRUE}
  59. define_attribute {p:da_data[1]}{PAP_IO_SLEW} {SLOW}
  60. define_attribute {p:da_data[0]}{PAP_IO_DIRECTION} {OUTPUT}
  61. define_attribute {p:da_data[0]}{PAP_IO_LOC} {K18}
  62. define_attribute {p:da_data[0]}{PAP_IO_VCCIO} {1.2}
  63. define_attribute {p:da_data[0]}{PAP_IO_STANDARD} {LVCMOS12}
  64. define_attribute {p:da_data[0]}{PAP_IO_DRIVE} {2}
  65. define_attribute {p:da_data[0]}{PAP_IO_NONE} {TRUE}
  66. define_attribute {p:da_data[0]}{PAP_IO_SLEW} {SLOW}
  67. define_attribute {p:ad_data[7]}{PAP_IO_DIRECTION} {INPUT}
  68. define_attribute {p:ad_data[7]}{PAP_IO_LOC} {G18}
  69. define_attribute {p:ad_data[7]}{PAP_IO_VCCIO} {1.2}
  70. define_attribute {p:ad_data[7]}{PAP_IO_STANDARD} {LVCMOS12}
  71. define_attribute {p:ad_data[7]}{PAP_IO_NONE} {TRUE}
  72. define_attribute {p:ad_data[6]}{PAP_IO_DIRECTION} {INPUT}
  73. define_attribute {p:ad_data[6]}{PAP_IO_LOC} {J15}
  74. define_attribute {p:ad_data[6]}{PAP_IO_VCCIO} {1.2}
  75. define_attribute {p:ad_data[6]}{PAP_IO_STANDARD} {LVCMOS12}
  76. define_attribute {p:ad_data[6]}{PAP_IO_NONE} {TRUE}
  77. define_attribute {p:ad_data[5]}{PAP_IO_DIRECTION} {INPUT}
  78. define_attribute {p:ad_data[5]}{PAP_IO_LOC} {G17}
  79. define_attribute {p:ad_data[5]}{PAP_IO_VCCIO} {1.2}
  80. define_attribute {p:ad_data[5]}{PAP_IO_STANDARD} {LVCMOS12}
  81. define_attribute {p:ad_data[5]}{PAP_IO_NONE} {TRUE}
  82. define_attribute {p:ad_data[4]}{PAP_IO_DIRECTION} {INPUT}
  83. define_attribute {p:ad_data[4]}{PAP_IO_LOC} {J14}
  84. define_attribute {p:ad_data[4]}{PAP_IO_VCCIO} {1.2}
  85. define_attribute {p:ad_data[4]}{PAP_IO_STANDARD} {LVCMOS12}
  86. define_attribute {p:ad_data[4]}{PAP_IO_NONE} {TRUE}
  87. define_attribute {p:ad_data[3]}{PAP_IO_DIRECTION} {INPUT}
  88. define_attribute {p:ad_data[3]}{PAP_IO_LOC} {F18}
  89. define_attribute {p:ad_data[3]}{PAP_IO_VCCIO} {1.2}
  90. define_attribute {p:ad_data[3]}{PAP_IO_STANDARD} {LVCMOS12}
  91. define_attribute {p:ad_data[3]}{PAP_IO_NONE} {TRUE}
  92. define_attribute {p:ad_data[2]}{PAP_IO_DIRECTION} {INPUT}
  93. define_attribute {p:ad_data[2]}{PAP_IO_LOC} {H16}
  94. define_attribute {p:ad_data[2]}{PAP_IO_VCCIO} {1.2}
  95. define_attribute {p:ad_data[2]}{PAP_IO_STANDARD} {LVCMOS12}
  96. define_attribute {p:ad_data[2]}{PAP_IO_NONE} {TRUE}
  97. define_attribute {p:ad_data[1]}{PAP_IO_DIRECTION} {INPUT}
  98. define_attribute {p:ad_data[1]}{PAP_IO_LOC} {F17}
  99. define_attribute {p:ad_data[1]}{PAP_IO_VCCIO} {1.2}
  100. define_attribute {p:ad_data[1]}{PAP_IO_STANDARD} {LVCMOS12}
  101. define_attribute {p:ad_data[1]}{PAP_IO_NONE} {TRUE}
  102. define_attribute {p:ad_data[0]}{PAP_IO_DIRECTION} {INPUT}
  103. define_attribute {p:ad_data[0]}{PAP_IO_LOC} {J16}
  104. define_attribute {p:ad_data[0]}{PAP_IO_VCCIO} {1.2}
  105. define_attribute {p:ad_data[0]}{PAP_IO_STANDARD} {LVCMOS12}
  106. define_attribute {p:ad_data[0]}{PAP_IO_NONE} {TRUE}
  107. define_attribute {p:ad_clk}{PAP_IO_DIRECTION} {OUTPUT}
  108. define_attribute {p:ad_clk}{PAP_IO_LOC} {H13}
  109. define_attribute {p:ad_clk}{PAP_IO_VCCIO} {1.2}
  110. define_attribute {p:ad_clk}{PAP_IO_STANDARD} {LVCMOS12}
  111. define_attribute {p:ad_clk}{PAP_IO_DRIVE} {2}
  112. define_attribute {p:ad_clk}{PAP_IO_NONE} {TRUE}
  113. define_attribute {p:ad_clk}{PAP_IO_SLEW} {SLOW}
  114. define_attribute {p:da_clk}{PAP_IO_DIRECTION} {OUTPUT}
  115. define_attribute {p:da_clk}{PAP_IO_LOC} {H14}
  116. define_attribute {p:da_clk}{PAP_IO_VCCIO} {1.2}
  117. define_attribute {p:da_clk}{PAP_IO_STANDARD} {LVCMOS12}
  118. define_attribute {p:da_clk}{PAP_IO_DRIVE} {2}
  119. define_attribute {p:da_clk}{PAP_IO_NONE} {TRUE}
  120. define_attribute {p:da_clk}{PAP_IO_SLEW} {SLOW}
  121. define_attribute {p:ad_otr}{PAP_IO_DIRECTION} {INPUT}
  122. define_attribute {p:ad_otr}{PAP_IO_LOC} {K15}
  123. define_attribute {p:ad_otr}{PAP_IO_VCCIO} {1.2}
  124. define_attribute {p:ad_otr}{PAP_IO_STANDARD} {LVCMOS12}
  125. define_attribute {p:ad_otr}{PAP_IO_NONE} {TRUE}
复制代码

1.4 程序设计
根据本章的实验任务,FPGA需要连续输出正弦波波形的数据,才能使AD9708连续输出正弦波波形的模拟电压,如果通过编写代码使用三角函数公式运算的方式输出正弦波数据,那么程序设计会变得非常复杂。在工程应用中,一般将正弦波波形数据存储在RAM或者ROM中,由于本次实验并不需要写数据到RAM中,因此我们将正弦波波形数据存储在只读的ROM中,直接读取ROM中的数据发送给DA转换芯片即可。
图 34.4.1是根据本章实验任务画出的系统框图。ROM里面事先存储好了正弦波波形的数据,DA数据发送模块从ROM中读取数据,将数据和时钟送到AD9708的输入数据端口和输入时钟端口;AD数据接收模块给AD9280输出驱动时钟信号和使能信号,并采集AD9280输出模数转换完成的数据。
高速AD/DA实验的系统框图如图 34.4.1所示:
image023.png
图 34.4.1 高速AD/DA系统框图
顶层模块的原理图如下图所示:
image025.png
图 34.4.2 顶层模块原理图
FPGA顶层模块(hs_ad_da)例化了以下三个模块:DA数据发送模块(da_wave_send)、ROM波形存储模块(rom_256x8b)和AD数据接收模块(ad_wave_rec)。
DA数据发送模块(da_wave_send):DA数据发送模块输出读ROM地址,将输入的ROM数据发送至DA转换芯片的数据端口。
ROM波形存储模块(rom_256x8b):ROM波形存储模块由Pango DesignSuite软件自带的Distributed ROM IP核实现,其存储的波形数据可以使用波形转存储文件的上位机来生成.DAT文件。
AD数据接收模块(ad_wave_rec):AD数据接收模块输出AD转换芯片的驱动时钟和使能信号,随后接收AD转换完成的数据。
顶层模块的代码如下:
  1. 1  module hs_ad_da(
  2. 2      input                 sys_clk     ,  //系统时钟
  3. 3      input                 sys_rst_n   ,  //系统复位,低电平有效
  4. 4      //DA芯片接口
  5. 5      output                da_clk      ,  //DA(AD9708)驱动时钟,最大支持125Mhz时钟
  6. 6      output    [7:0]       da_data     ,  //输出给DA的数据
  7. 7      //AD芯片接口
  8. 8      input     [7:0]       ad_data     ,  //AD输入数据
  9. 9      //模拟输入电压超出量程标志(本次试验未用到)
  10. 10     input                 ad_otr      ,  //0:在量程范围 1:超出量程
  11. 11     output                ad_clk         //AD(AD9280)驱动时钟,最大支持32Mhz时钟
  12. 12 );
  13. 13
  14. 14 //wire define
  15. 15 wire      [7:0]    rd_addr;              //ROM读地址
  16. 16 wire      [7:0]    rd_data;              //ROM读出的数据
  17. 17 //*****************************************************
  18. 18 //**                    main code
  19. 19 //*****************************************************
  20. 20
  21. 21 //DA数据发送
  22. 22 da_wave_sendu_da_wave_send(
  23. 23     .clk         (sys_clk),
  24. 24     .rst_n       (sys_rst_n),
  25. 25     .rd_data     (rd_data),
  26. 26     .rd_addr     (rd_addr),
  27. 27     .da_clk      (da_clk),  
  28. 28     .da_data     (da_data)
  29. 29     );
  30. 30
  31. 31 //ROM存储波形
  32. 32 rom_256x8b  u_rom_256x8b (
  33. 33   .clk  (sys_clk),    // input wire clka
  34. 34   .addr (rd_addr),    // input wire [7 : 0] addra
  35. 35   .rst  (~sys_rst_n) ,
  36. 36   .rd_data (rd_data)     // output wire [7 : 0] douta
  37. 37 );
  38. 38 //AD数据接收
  39. 39 ad_wave_recu_ad_wave_rec(
  40. 40     .clk         (sys_clk),
  41. 41     .rst_n       (sys_rst_n),
  42. 42     .ad_data     (ad_data),
  43. 43     .ad_otr      (ad_otr),
  44. 44     .ad_clk      (ad_clk)
  45. 45     );   
  46. 46 endmodule
复制代码
DA数据发送模块输出的读ROM地址(rd_addr)连接至ROM模块的地址输入端,ROM模块输出的数据(rd_data)连接至DA数据发送模块的数据输入端,从而完成了从ROM中读取数据的功能。
在代码的第32至36行例化了ROM模块,由Distributed ROM IP核配置生成。
我们在前面说过,ROM中存储的波形数据可以使用上位机波形转DAT软件生成,在这里我们介绍一个简单易用的波形转DAT工具的使用方法,该工具位于开发板所随附的资料“6_软件资料/1_软件/WaveToMem”目录下,双击“WaveToMem_V1.2.exe”运行软件。
接下来我们对软件进行设置,如图 34.4.3所示,这里对软件界面做个简单的介绍。
位宽:波形数据的位宽。由于ATK_HS_AD_DA模块的DA芯片数据位宽为8位,因此这里保持默认,即设置成8位。
深度:一个波形周期包含了多少个数据量。这里保持默认,即设置成256。需要说明的是,在用Distributed ROM IP核生成ROM时,配置ROM的宽度和深度和上位机设置的位宽和深度保持一致。
波形频率设置:对波形倍频,倍数值越大,最终生成的波形频率越快(频率太高,可能导致波形失真),这里保持默认,即设置成1位。
波形类型:软件支持将正弦波、方波、锯齿波和三角波的波形转换成存储波形格式的文件。
生成文件:软件支持将波形转换成DAT(PDS软件支持的存储格式)和MIF(Quartus软件支持的存储格式)格式文件,这里保持默认,即选中DAT文件格式。
然后点击“一键生成”按钮,在弹出的界面中选择DAT文件的存放路径并输入文件名,这里将DAT文件保存在工程的doc文件夹下。WaveToMem转换过程中的软件界面如下图所示:
image029.png
图 34.4.3 WaveToMem软件界面
使用Notepad++代码编辑器打开生成的DAT文件后如下图所示:
image028.png
图 34.4.4 dat文件
工程中创建了一个单端口ROM,并命名为“rom_256x8b”,在调用Distributed ROM IP核时,“Configure”选项也配置如下图所示:
image030.png
图 34.4.6 Distributed ROM IP核配置页面
我们将PortA的地址位宽设置为9,以存储上位机生成的256个数据,数据位宽设置为8,以对应DAC的数据端口,接下来配置“Init File”选项,加载刚才生成的.dat文件,最后点击“Generate”按钮完成IP核的配置。
DA数据发送模块的代码如下:
  1. 1  module da_wave_send(
  2. 2      input                 clk    ,  //时钟
  3. 3      input                 rst_n  ,  //复位信号,低电平有效
  4. 4      
  5. 5      input        [7:0]    rd_data,  //ROM读出的数据
  6. 6      output  reg  [7:0]    rd_addr,  //读ROM地址
  7. 7      //DA芯片接口
  8. 8      output                da_clk ,  //DA(AD9708)驱动时钟,最大支持125Mhz时钟
  9. 9      output       [7:0]    da_data   //输出给DA的数据  
  10. 10     );
  11. 11
  12. 12 //parameter
  13. 13 //频率调节控制
  14. 14 parameter  FREQ_ADJ = 8'd5;  //频率调节,FREQ_ADJ的值越大,最终输出的频率越低,范围0~255
  15. 15
  16. 16 //reg define
  17. 17 reg    [7:0]    freq_cnt  ;  //频率调节计数器
  18. 18
  19. 19 //*****************************************************
  20. 20 //**                    main code
  21. 21 //*****************************************************
  22. 22
  23. 23
  24. 24
  25. 25 assign  da_clk = clk;      
  26. 26 assign  da_data = rd_data;   //将读到的ROM数据赋值给DA数据端口
  27. 27
  28. 28 //频率调节计数器
  29. 29 always @(posedge clk or negedge rst_n) begin
  30. 30     if(rst_n == 1'b0)
  31. 31         freq_cnt <= 8'd0;
  32. 32     else if(freq_cnt == FREQ_ADJ)   
  33. 33         freq_cnt <= 8'd0;
  34. 34     else         
  35. 35         freq_cnt <= freq_cnt + 8'd1;
  36. 36 end
  37. 37
  38. 38 //读ROM地址
  39. 39 always @(posedge clk or negedge rst_n) begin
  40. 40     if(rst_n == 1'b0)
  41. 41         rd_addr <= 8'd0;
  42. 42     else begin
  43. 43         if(freq_cnt == FREQ_ADJ) begin
  44. 44             rd_addr <= rd_addr + 8'd1;
  45. 45         end   
  46. 46     end            
  47. 47 end
  48. 48
  49. 49 endmodule
复制代码
在代码的第14行定义了一个参数FREQ_ADJ(频率调节),可以通过控制频率调节参数的大小来控制最终输出正弦波的频率大小,频率调节参数的值越小,正弦波频率越大。频率调节参数调节正弦波频率的方法是通过控制读ROM的速度实现的,频率调节参数越小,freq_cnt计数到频率调节参数值的时间越短,读ROM数据的速度越快,那么正弦波输出频率也就越高;反过来,频率调节参数越大,freq_cnt计数到频率调节参数值的时间越长,读ROM数据的速度越慢,那么正弦波输出频率也就越低。由于freq_cnt计数器的位宽为8位,计数范围是0~255,所以频率调节参数FREQ_ADJ支持的调节范围是0~255,可通过修改freq_cnt计数器的位宽来修改FREQ_ADJ支持的调节范围。
WaveToMem软件设置ROM深度为256,倍频系数为1,而输入时钟为50Mhz,那么一个完整的正弦波周期长度为256*20ns = 5120ns,当FREQ_ADJ的值为0时,即正弦波的最快输出频率为1s/5120ns(1s = 1000000000ns) ≈ 195.3Khz。当我们把FREQ_ADJ的值设置为5时,一个完整的正弦波周期长度为5120ns*(5+1) = 30720ns,频率约为32.55KHz。也可以在WaveToMem软件设置中增加倍频系数或者增加AD的驱动时钟来提高正弦波输出频率。
AD数据接收模块的代码如下:
  1. 1  module ad_wave_rec(
  2. 2      input                 clk         ,  //时钟
  3. 3      input                 rst_n       ,  //复位信号,低电平有效
  4. 4      
  5. 5      input         [7:0]   ad_data     ,  //AD输入数据
  6. 6      //模拟输入电压超出量程标志(本次试验未用到)
  7. 7      input                 ad_otr      ,  //0:在量程范围 1:超出量程
  8. 8      output   reg          ad_clk         //AD(AD9280)驱动时钟,最大支持32Mhz时钟
  9. 9      );
  10. 10
  11. 11 //*****************************************************
  12. 12 //**                    main code
  13. 13 //*****************************************************
  14. 14
  15. 15 //时钟分频(2分频,时钟频率为25Mhz),产生AD时钟
  16. 16 always @(posedge clk or negedge rst_n) begin
  17. 17     if(rst_n == 1'b0)
  18. 18         ad_clk <= 1'b0;
  19. 19     else
  20. 20         ad_clk <= ~ad_clk;
  21. 21 end   
  22. 22
  23. 23 endmodule
复制代码
由于AD转换芯片支持的最大时钟频率为32Mhz,而ATK-DFPGL22G开发板系统时钟频率为50Mhz,所以需要先对时钟进行分频,将分频后的时钟作为AD转换芯片的驱动时钟(分频计数见代码的第16行至第21行)。
需要说明的是,AD数据接收模块没有对输入的ad_otr(输入的模拟电压超出量程指示)和ad_data(AD输入的数据)做任何处理,这两个信号是在Debugger中观察信号的变化的。

1.5 下载验证
将高速AD-DA模块插入ATK-DFPGL22G开发板的P2扩展口,连接时注意扩展口电源引脚方向和开发板电源引脚方向一致,然后将下载器一端连接电脑,另一端与开发板上对应端口连接,最后连接电源线并打开电源开关。
ATK-DFPGL22G开发板硬件连接实物图如下图所示:
image032.png
图 34.5.1 ATK-DFPGL22G开发板开发板硬件连接实物图
将工程生成的比特流文件下载到ATK-DFPGL22G开发板中后,然后使用示波器测量DA输出通道的波形。首先将示波器带夹子的一端连接到开发板的GND位置(可使用杜邦线连接至开发板上的任一的GND管脚),然后将另一端探针插入高速AD-DA模块的DA通道中间的金属圆圈内(注意将红色的保护套拿掉),如图 34.5.2所示。或者也可以直接测试高速AD-DA模块的TP引脚,如图 34.5.3所示。
image035.png
图 34.5.2 DA模拟电压测量孔位

image036.png
图 34.5.3 DA模拟电压测量点(TP)
此时观察示波器可以看到正弦波的波形,如果观察不到波形,可查看示波器设置是否正确,可以尝试按下示波器的“AUTO”,再次观察示波器波形。示波器的显示界面如下图所示:
image038.jpg
图 34.5.4 示波器显示界面
观察到正弦波波形后,说明DA已经正确输出模拟电压波形了,接下来我们来验证AD的功能,首先使用两头都是公头的杜邦线,将DA输出通道和AD输入通道连接起来,杜邦线连接图下图所示。
image040.png
图 34.5.5 AD-DA通道杜邦线连接图
连接后在Debugger中观察ad_data数据的变化,观察到的波形如下图所示。
image042.png
图 34.5.5 AD数据接收模块采集到的Debugger波形图
由上图可知,输入的ad_data数据为正弦波变化的波形,说明AD-DA实验验证成功。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 17:31

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表