Smart ZYNQ 板 工程三十 在PL端调用片内XADC资源来读取 ADC对应管脚的电平电压

XADC功能很强大后续将通过多篇文章来介绍XADC的功能,在PL端调用片内XADC资源来采集 ADC对应管脚的模拟电压的功能

备注 此章节仅适用于Smart ZYNQ 标准版的主板,如果是SP,SL或者SP2请看对应章节的内容

首先 写在最最前面 XADC 引脚输入的电压 采集范围是(0-1V)大家尽量不要超过这个范围,否则可能会烧坏主芯片,重要的事情写3编

(0-1V)

(0-1V)

(0-1V)

如果电压范围超过这个区间,请先对信号进行预处理,比方说用电阻来进行分压,或者增加放大倍数小于1的调理电路,直到满足条件为止

即使是想采集(-0.5 ~ +0.5电压也是有条件的需要先OFFSET 信号才可以也就是最终还是在(0-1V),IP里也需要配置,具体的请对照官方XADC手册)

以下接正题

XADC除了上一节介绍的读取芯片内部的 温度和电压等功能外, 其实XADC跟单片机的ADC一样 还可以对外部的模拟量进行采集。 下面就演示PL端读取芯片引脚电压来进行演示

芯片内部 XADC资源框图如下

其中红圈框选出来的地方就是对应芯片外部管脚,不作为XADC 引脚的时候,可以作为普通IO口使用

板子排针接口引出来的XADC接口如下图所示 例 AD0P 和AD0N 是一组差分模拟脚,当然也可以直接将N端在硬件上用杜邦线接GND,作为单端信号检测 (备注 XADC 输入的电压范围是 0-1V

XILINX 官方有一份 7系列的 XADC手册, 这里为了方便大家查找也上传到本网站

ug480_7Series_XADC下载

二 . 创建工程

1)打开Vivado 新建一个项目, 新建一个VIVADO 工程,打开软件 选中Create Project, 如下图所示

2)点击NEXT ,在出现的第二个对话框“Project name”中输入工程名;在“Project location”中选择保存路径;勾选“Create project subdirectory”(默认),最后点击“Next” 备注,所有的路径均不能出现中文名称

3)点击 RTL PROJECT 选项,点击NEXT

4) 第四步Add Sources 选项直接留空,NEXT

5)第五步Add Constraints 选项直接留空,NEXT

6)选择芯片型号 (板子生产了多个芯片型号,请根据自己板子的型号来进行选择,下图以XA7Z020来进行演示,其余型号自行选择,必须要按照实际型号去填写)

  • XA7Z020 (直接选择xc7z020CLG400-1,因为系统识别到的是xc7z020-1)
  • XC7Z010-1 (xc7z010CLG400-1) (7010 芯片)

备注 (7020 车规级版在vivado2018.3识别出的是xc7z020,如果工程选择xa7z020 ,在SDK环境下有时候会弹出警告,所以这里直接选择Xc7z020CLG400-1)

7)确认所选信息 点击“Finish”,完成vivado的工程创建

之后 工程就新建好了, vivado 进入到开发界面

三、添加XADC IP,并对IP进行设置

1.在IP Catalog中 添加 XADC 模块

2.在XADC 中进行下列设置 ,选择DRP接口(fpga调用的时候选择此接口),Channel Sequencer(该模式可以添加多路adc采样,方便以后拓展), Continuous Mode (连续采样模式,让XADC 一直工作在数据采样的模式下) ,DCLK设置默认的100Mhz

3.第二页的设置 保持默认就好

4.Alarms 警告页, 实验中并不需要报警信号 所以这里报警信号的勾全部都取消

5. 实验中 我们选AD7来作为测试的引脚(没特殊原因,因为AD7在排针上最容易找),所以这里选择vauxp7/vauxn7 ,这里去掉VP/VN ,否则采样频率会降低一半

6. 之后 按下OK 结束 xadc 的IP配置

7. 在弹出的窗口 选择Generate

8. 等待IP 编译完后,就能在工程中看到 我们添加的XADC模块了

三、添加一个ILA测试模块

这里我们计划添加一个ILA来观察XADC采集的结果,

选择 Native 接口, 探针数量为2 深度可以根据自己的需求选择 ,这里用8192(因为采样频率比较低,所以通过增加采样深度,来让采样更直观)

因为XADC 是12bit的,所以这里我们 位宽选择12,另外第二通道设置位宽为1,用来观察DRDY信号 之后选择OK进行保存

四、增加PLL模块来生成100Mhz 时钟

将输入时钟设置成50M

输出时钟设置成100m

为了方便操作这里 去掉了 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_vauxp7;
always @(posedge clk)begin
if(drdy_out== 1'b1 && channel_out==5'h17)begin//17是 vauxp7通道的地址
xadc_value_vauxp7 <= do_out[15:4] ;
end else begin
xadc_value_vauxp7<= xadc_value_vauxp7;
end
end

如何确定 具体的通道对应哪个地址呢,可以参考下图,比方说 Temp 就是 地址00h ,如果是Vccint 就是01h ,我们是Vauxp[7]按照图片推算,通道7应该是 17h

以上就是 DRP接口的所有信号介绍

剩下的XADC信号介绍

vp、vn,是ZYNQ 物理存在的XADC脚,如果不测量外部数据可以直接给0(我们的板子是没有引出的,所以直接给0);

dclk_in    时钟信号连接DRP所使用的时钟即可,注意频率需要和XADC IP中的设置一样,这里需要给100Mhz

vauxp7、vauxn7  这两个信号就是通道7差分输入的P和N信号,这里我们把两个信号都引出(备注即使只采集单端信号,也把n端引出,否则直接给n赋0,实际测量误差挺大
.vauxp7(vauxp7),
.vauxn7(vauxn7),

备注 :理论上如果要使用单端测量模拟信号,可以直接把vauxn7直接接板子的GND 就可以 ,我也看到网上有一种说法是直接在模块例化的时候将N端 直接赋0,这个方法我也做了测试实际测试得到用这种方式测量到的电压和真实的电压会有很大的出入(我这边测量得到的结果是,fpga内部 直接给n端赋0,采集到的电压值会比正常电压低0.4-0.5V, 怀疑压差可能是FPGA芯片内部对地的逻辑门导致的)所以不论是测量单端还是差分电压,都请将 XADC 的P和N都引出

如果是单端测量则可以通过杜邦线直接将XADC差分输入脚的N端接GND将P端接测量信号,如果是差分方式,则P和N都用来接信号两端。(备注 因为输入阻抗比较大,所以如果直接用板子去测量50欧阻抗的信号发生器输出的波形,实际测量到的结果可能是两倍信号的大小,这个是正常的(高端的示波器也会有50欧和1M欧两档,如输入阻抗和信号源不完全匹配,可能会造成波形幅度偏大或者偏小的情况))

添加下列代码

//www.hellofpga.com
//20230803

`timescale 1ns / 1ps

module XADC_TEST_MODULE(
input vauxp7,
input vauxn7,
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_vauxp7_value;

always @(posedge clk_100m)begin
if(drdy_out== 1'b1 && channel_out==5'h17)begin//17是 vauxp7通道的地址
xadc_vauxp7_value <= do_out[15:4];
end
else begin
xadc_vauxp7_value<= xadc_vauxp7_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),
.vauxp7(vauxp7),
.vauxn7(vauxn7),
.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_vauxp7_value),
.probe1(drdy_out)
);



endmodule

六、编译 综合 添加管教约束

编译 RUN

之后按下图所示添加约束

综合并生成 bit文件

七 下载并在线测试结果

重要的事情再说一遍 XADC采集电压范围是(0-1V),超出范围有可能损坏器件

点选 Program Device 然后选择芯片xc7z020_1

点选 program

之后系统会对FPGA进行编程配置,并且vivado 会弹出ila调试界面

硬件连接 XADC 第7通道 vauxp7 接在排针的L14脚, vauxn7接在排针的L15脚 ,如果是单端测量则可以通过杜邦线直接将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),超出范围有可能损坏器件

工程这里大家自行创建,有问题的可以给我留言

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注