XADC功能很强大后续将通过多篇文章来介绍XADC的功能,本文将介绍在PL端调用片内XADC资源来采集 ADC对应管脚的模拟电压的功能
- 此章节内容适用于Smart ZYNQ SP SP2和 SL 版的板子 ( 不包含Smart ZYNQ 标准版 ),如是标准版或本站其他板子请看对应板子目录
- 本文在 vivado2018.3版本上演示
实验前须知:
首先 写在最最前面 XADC 引脚输入的电压 采集范围是(0-1V)大家尽量不要超过这个范围,否则可能会烧坏主芯片,重要的事情写3编
(0-1V)
(0-1V)
(0-1V)
如果电压范围超过这个区间,请先对信号进行预处理,比方说用电阻来进行分压,或者增加放大倍数小于1的调理电路,直到满足条件为止
即使是想采集(-0.5 ~ +0.5电压也是有条件的需要先OFFSET 信号才可以也就是最终还是在(0-1V),IP里也需要配置,具体的请对照官方XADC手册)
以下接正题
XADC除了可以读取芯片内部的 温度和电压等功能外(PS部分实验有介绍), 其实XADC跟单片机的ADC一样 还可以对外部的模拟量进行采集。 下面就演示PL端读取芯片引脚电压来进行演示
芯片内部 XADC资源框图如下
其中红圈框选出来的地方就是对应芯片外部管脚,不作为XADC 引脚的时候,可以作为普通IO口使用
板子排针接口引出来的XADC接口如下图所示 例 AD0P 和AD0N 是一组差分模拟脚,当然也可以直接将N端在硬件上用杜邦线接GND,作为单端信号检测 (备注 XADC 输入的电压范围是 0-1V)
XILINX 官方有一份 7系列的 XADC手册, 这里为了方便大家查找也上传到本网站
一、Vivado工程创建
工程创建的过程可以参考实验一中的内容,这里不详细描述了。基于Smart ZYNQ (SP/SP2/SL 版) 的FPGA实验一 用ZYNQ的PL资源点亮一个LED(完整图文) (芯片型号选XC7Z020CLG484-1)
二、添加XADC IP,并对IP进行设置
1.在IP Catalog中 添加 XADC 模块
2.在XADC 中进行下列设置 ,选择DRP接口(fpga调用的时候选择此接口),Channel Sequencer(该模式可以添加多路adc采样,方便以后拓展), Continuous Mode (连续采样模式,让XADC 一直工作在数据采样的模式下) ,DCLK设置默认的100Mhz
3.第二页的设置 保持默认就好
4.Alarms 警告页, 实验中并不需要报警信号 所以这里报警信号的勾全部都取消
5. 实验中 我们选AD9来作为测试的引脚(没特殊原因,因为AD9在排针上最容易找),所以这里选择vauxp9/vauxn9 ,这里去掉VP/VN ,否则采样频率会降低一半
6. 之后 按下OK 结束 xadc 的IP配置
7. 在弹出的窗口 选择Generate
8. 等待IP 编译完后,就能在工程中看到 我们添加的XADC模块了
三、添加一个ILA测试模块
1)这里我们计划添加一个ILA来观察XADC采集的结果,
2)选择 Native 接口, 探针数量为2 深度可以根据自己的需求选择 ,这里用8192(因为采样频率比较低,所以通过增加采样深度,来让采样更直观)
3)因为XADC 是12bit的,所以这里我们 位宽选择12,另外第二通道设置位宽为1,用来观察DRDY信号 之后选择OK进行保存
四、增加PLL模块来生成100Mhz 时钟
1) 将输入时钟设置成50M
2)输出时钟设置成100m
3)为了方便操作这里 去掉了 reset,和locked信号,之后点选OK 保存配置
五、增加顶层模块
六 、编辑代码
下图是XADC 的DRP接口,
XADC 转换模块在运行的过程中会自动把数据输入到DRP中,这里我们不需要写寄存器,只需要读取,因此di_in直接给0 ,读写使能信号一直设置成低电平,即读使能dwe_in
.di_in (16'd0) .dwe_in(1'b0)
do_out 就是最终输出的数据,这个数据是16bit的,其中的高12bit就是我们需要的adc数据
drdy_out 可以理解是输出指示信号,等于1的时候代表采集完成
den_in 与 daddr_in ,以及XADC 的 channel_out 和 eoc_out 首先介绍 channel_out 和eoc_out,当每个通道的ADC转换完成后eoc_out都会被拉高,与此同时channel_out指示对应转换完成的通道位。 而den_in代表输入信号使能,daddr_in代表drp的寄存器地址。所以这里将XADC 的eoc_out 代表转化完成标志 和DRP的den_in端口连接在一起,这样多路采样的某一路采样完成后,则DRP的寄存器地址就被指向daddr_in(因为daddr_in和channel_out补两位连接在一起,所以DRP的寄存器地址就指向对应刚转换完成的 ADC通道地址了), 用这种方式每当adc某个通道转换完了,do_out的输出都是刚转换完的这个通道的结果。(当然理论上也可以通过daddr_in永远固定,或者手动轮询采集某个通道的值,这个大家自行尝试)
.den_in (eoc_out) .eoc_out (eoc_out),//EOC_OUT,就是转化完成标志 .daddr_in ({2'd0,channel_out}), .channel_out (channel_out),//输出地址
因为XADC 会以轮询的方式在多个ADC端口中来回采样,所以我们需要增加一段逻辑来判断当前采集的数据是否是我们需要的通道的数据
reg [11:0]xadc_value_vauxp9; always @(posedge clk)begin if(drdy_out== 1'b1 && channel_out==5'h19)begin//19是 vauxp9通道的地址 xadc_value_vauxp9 <= do_out[15:4] ; end else begin xadc_value_vauxp9<= xadc_value_vauxp9; end end
如何确定 具体的通道对应哪个地址呢,可以参考下图,比方说 Temp 就是 地址00h ,如果是Vccint 就是01h ,我们是Vauxp[9]按照图片推算,通道9应该是 19h
以上就是 DRP接口的所有信号介绍
剩下的XADC信号介绍
vp、vn,是ZYNQ 物理存在的XADC脚,如果不测量外部数据可以直接给0(我们的板子是没有引出的,所以直接给0);
dclk_in 时钟信号连接DRP所使用的时钟即可,注意频率需要和XADC IP中的设置一样,这里需要给100Mhz
vauxp9、vauxn9 这两个信号就是通道9差分输入的P和N信号,这里我们把两个信号都引出(备注即使只采集单端信号,也把n端引出,否则直接给n赋0,实际测量误差挺大)
.vauxp9(vauxp9), .vauxn9(vauxn9),
备注 :理论上如果要使用单端测量模拟信号,可以直接把vauxn9直接接板子的GND 就可以 ,我也看到网上有一种说法是直接在模块例化的时候将N端 直接赋0,这个方法我也做了测试实际测试得到用这种方式测量到的电压和真实的电压会有很大的出入(我这边测量得到的结果是,fpga内部 直接给n端赋0,采集到的电压值会比正常电压低0.4-0.5V, 怀疑压差可能是FPGA芯片内部对地的逻辑门导致的)所以不论是测量单端还是差分电压,都请将 XADC 的P和N都引出。
如果是单端测量则可以通过杜邦线直接将XADC差分输入脚的N端接GND将P端接测量信号,如果是差分方式,则P和N都用来接信号两端。(备注 因为输入阻抗比较大,所以如果直接用板子去测量50欧阻抗的信号发生器输出的波形,实际测量到的结果可能是两倍信号的大小,这个是正常的(高端的示波器也会有50欧和1M欧两档,如输入阻抗和信号源不完全匹配,可能会造成波形幅度偏大或者偏小的情况))
添加下列代码
`timescale 1ns / 1ps module XADC_TEST_MODULE( input vauxp9, input vauxn9, input clk ); wire [4:0] channel_out; wire eoc_out; wire clk_100m; wire drdy_out; wire [15:0]do_out; reg [11:0]xadc_vauxp9_value; always @(posedge clk_100m)begin if(drdy_out== 1'b1 && channel_out==5'h19)begin//19是 vauxp9通道的地址 xadc_vauxp9_value <= do_out[15:4]; end else begin xadc_vauxp9_value<= xadc_vauxp9_value; end end clk_wiz_0 clk_wiz_inst( .clk_out1(clk_100m), .clk_in1(clk) ); xadc_wiz_0 xadc_wiz_inst ( .daddr_in({2'd0,channel_out}), .dclk_in(clk_100m), .den_in(eoc_out), .di_in(16'd0), .dwe_in(1'b0), .drdy_out(drdy_out), .do_out(do_out[15:0]), .reset_in(1'b0), .vauxp9(vauxp9), .vauxn9(vauxn9), .channel_out(channel_out), .eoc_out(eoc_out), .eos_out(), .alarm_out(), .busy_out(), .vp_in(), .vn_in() ); ila_0 u_ila( .clk(clk_100m), .probe0(xadc_vauxp9_value), .probe1(drdy_out) ); endmodule
六、编译 综合 添加管脚约束
1) 编译 RUN
2)之后按下图所示添加约束
3)综合并生成 bit文件
七、下载并在线测试结果
重要的事情再说一遍 XADC采集电压范围是(0-1V),超出范围有可能损坏器件
1)点选 Program Device 然后选择芯片xc7z020_1
2)点选 program
3)之后系统会对FPGA进行编程配置,并且vivado 会弹出ila调试界面
硬件连接 XADC 第9通道 vauxp9 接在排针的F18脚, vauxn9接在排针的E18脚 ,如果是单端测量则可以通过杜邦线直接将XADC差分输入脚的N端接GND将P端接测量信号,如果是差分方式,则P和N直接接在被测信号的两端(信号和信号的参考地)
注意 XADC 采集的范围是 0-1V, 所以对应的电压换算公式是
Voltage = (ADC /4096) x 1V
观测一 观测波形发生器的数值,这里我们将波形发生器设置成(VPP:0.5V, OFFSET 0.25V,频率为50khz的正弦波)考虑到波形发生器是低阻输出(50欧)而我们的xadc 又是高阻抗输入,所以这里实际采集到的波形理论上应该接近于两倍关系 即(VPP:1V, OFFSET 0.5V) 。
为什么会出现采集关系是波形发生器的两倍,这个问题上文也解答过,即使在示波器上也会出现这个现象,大家感兴趣的可以百度搜索下 “为什么示波器采集到的波形是信号发生器的两倍”
对FPGA进行program,随后系统会弹出ILA的观察界面,按下箭头进行数据的采集
接下来对采集的数据进行一些简单的设置以方便观察结果,首先将采集的结果定义为无符号整数
再将数据定义为 模拟信号,以方便观察波形
接下来我们观察ila的结果,下列两张图是测试结果,可以看到,输入的信号是一个正弦波(每个drdy_out高电平代表一个新的数据采集完成)
通过换算可以得到 正弦波的 最高电压接近 4083 (换算得到 4083/4096x1V=0.9968V)
通过换算可以得到 正弦波的 最低电压接近 15(换算得到 15/4096x1V=0.003V)
采集到的波形和信号发生器生成的波形满足两倍关系,即数据正确(为什么是两倍关系 上文中有提到)
观察二 用XADC 采集数字稳压源的电压
实验分别测试了0.5V 0.95V和0.1V 电压,通过ila界面 换算 结果都是正确的
另外 XADC功能非常强大 还可以 实现负电压的采集,也可以求平均后输出,也可以多路进行采集,更多的功能大家请自行研究。 XADC资料暂时整理到这里,后续有时间再出一个PS采集管脚电压的demo, 爆肝了好多天才测试成功也休息一下(XADC 拿来测试管脚全网的资料太少了 只能自己一点点尝试)重要的事情再说一遍 XADC采集电压范围是(0-1V),超出范围有可能损坏器件
- 本文的完整工程下载:10_PL_XADC_PIN_TEST
- VIVADO的版本:2018.3
- 工程创建目录:E:\Smart_ZYNQ_SP_SL\FPGA\10_PL_XADC_PIN_TEST
- 工程适用主板: Smart ZYNQ (SP / SP2 / SL) (不适用于Smart ZYNQ 标准版 )