XADC功能很强大后续将通过多篇文章来介绍XADC的功能,本文将简单演示通过 PS端调用片内XADC资源 来实时读取芯片的电源和温度等信息。
- 此章节内容适用于Smart ZYNQ SP SP2和 SL 版的板子 ( 不包含Smart ZYNQ 标准版 ),如是标准版或本站其他板子请看对应板子目录
- 本文在 vivado2018.3版本上演示
XADC功能认识
在ZYNQ芯片内部其实自带了AD功能模块XADC,XADC包含两个12bit 1MSPS(每秒一百万次采样) 的模数转换器,以及一个模拟多路选择器MUX,XADC还包含了电压和温度传感器,我们可以用XADC 对芯片内部各路的电源电压,以及芯片的温度进行监控和采集,也可以用XADC模块来采集外部的模拟电压信号(VAUXP 和VAUXN 是XADC的ADC采集口,平常不作ADC口的时候,可作为普通PL的GPIO使用)
芯片内部 XADC资源框图如下
XILINX 官方有一份 7系列的 XADC手册, 这里为了方便大家查找也上传到本网站
XADC功能很强大后续将通过多篇文章来介绍XADC的功能,本文将简单演示通过 PS端调用片内XADC资源 来实时读取芯片的电源和温度等信息。
XADC 模块的使用有两种方法,一 直接用 FPGA JTAG 专用接口访问,这样我们可以在VIVADO软件中直接读取实时的电压和温度等信息,二 ZYNQ的PS通过PS-XADC直接调用XADC模块来对模拟数据进行采集,三 在PL例化 XADC IP核来读取XADC数据(PL端读取xadc值也可以用这种方式)
以下的演示我们分两个部分 1.在vivado的软件中直接读取XADC值 2. 在PS中软件去读取XADC的数据
一.在vivado的软件中直接读取XADC值
这种方式很简单,不需要编程,只需要创建工程后,直接JTAG连接设备就能读取到数据
1.按照以往例程方式创建一个vivado工程,创建的过程中芯片型号选择XC7Z020-CLG484-1
2. 连接好主板,下载器和电脑(如果是Smart zynq SP SP2 或者 Smart ZYNQ 标准版 则自带下载器功能,SL版需要外接下载器 )
3.在PROGRAM AND DEBUG 里点选 Open Target 选项
这时如果连接正确,vivado 会跳出芯片型号,以及在芯片型号下方显示XADC的功能
4. 双击 XADC 功能并在展开的窗口修改名称并选择OK
5. 这时vivado 就通过JTAG采集到了 XADC读取的芯片内部的 温度信息了
备注 重要: 最好将板子调整成 JTAG启动方式 再重新上电,如再SD启动方式下,vivado界面采集到的数据会是错误的
这时我们通过点选 加号,还可以添加更多的 采集信息,包括外部XADC引脚的电压信息,或芯片内部 VCCAUX,VCCBRAM,VCCPINT等的电压信息
如下图所示,这里我添加了 芯片内部的几个关键电压,通过界面我们可以看到各路的实时电压信息
二 . 在PS中软件读取xadc的数据
和之前在vivado里直接读取 XADC的值不同,本方法是在PS中通过代码去读取XADC的值
1.在BLOCK DESIGN 中搜索并添加一个ZYNQ模块
2.在右侧的窗口里 ,点击加号,在选择框里搜索ZYNQ,并找到ZYNQ7 PROCESSING SYSTEM 双击并打开
3.软件自动生成了一个 zynq的block 如下图所示,接下来要做一些相应的设置,双击下图中的ZYNQ核
4. 在ZYNQ 设置界面,设置 DDR MT41K256M16RE-125的型号 和位宽16bit
5.使能ZYNQ的UART功能(因为需要通过串口 传出数据)
6.因为工程暂时用不到 AXI功能,所以可以先禁用AXI功能
7.完成后点选 Run Block Automation,完成后续自动布线
8.因为我们增加了EMIO 的UART,所以这里需要将UART的引脚引出 ,右键选择ZYNQ模块的UART_0,然后选择Make External
9)source→Design Source ,右键我们创建的BLOCK工程,点击create HDL wrapper,打包BLOCK文件并生成.v代码
10) 点击绿色箭头RUN 对代码进行编译
11) 点击RTL 中的SCHEMATIC , 并选择右边出现的 IO Ports 来增加UART 0 EMIO部分的管脚定义(这一步也可以在约束文件中定义, 可看之前的例子)
将 UART 部分的 TX RX 分别设置成 L17,M17 电压属性设置成 LVCMOS33, 之后保存
10) 生成bit文件 :按下Generate Bitstream 完成综合以及生成bit文件(会弹出窗口要求保存 约束规则文件)
SDK程序编写
1)File→Export→Export hardware…,在弹出的对话框中勾选“include bitstream”,点击“OK”确认,如下图所示。
2)File→Lauch SDK,在弹出的对话框中,保存默认,点击“OK”,如下图所示。
系统将自动打开SDK开发环境
3)新建一个工程 file→new→Application Project,来新建一个“Application Project”,如下图所示。
4)在新建工程名中输入自己的工程名称(XADC_TEST),点击NEXT
5)选择一个空工程,点击完成
6) 这里我们偷个懒,官方SDK里已经编写了XADC 读取温度电压的DEMO,所以这里我们可以直接参考官方的demo来快速实现我们调用XADC的功能( 后续可以将官方demo的代码直接copy到自己的工程里进行使用)
如下图所示 打开bsp 列表里的 mss, 并导入xadc 对应的工程 点击 xadcps 右边的 import Examples
这里又两个工程,一个是中断的参考工程,一个是轮询的, 这里我们选择轮询的方式
这样工程中会多出一个 官方的demo
8.代码下载验证
a 连接好板子的串口线,以及下载器(SP 自带下载器,SL需要外接下载器功能)
b 因为我们需要用串口来观察数据,而程序一运行就直接输出数据了,所以我们需要先打开串口助手(或VIVADO的串口功能) 备注 不同的电脑对应的串口号不同,可以通过查看设备管理器确认
c 再对 RUN AS 的环境进行配置
在弹出的窗口中 对4个 方框都进行勾选操作,以确保每次运行都会重新启动系统,并且重新编程FPGA(如PS没有出现 下图对话框,可以直接双击Xilinx C/C++ application (System Debugger ))
d 设置好之后,选择Run As
-> Launch on Hardware (System Debugger)
如果一切正常的话, 板子上的串口就会在下载程序后 输出XADC 的数据信息了,包括 温度 以及芯片内部 INT AUX DDR对应的电压信息等
这里仅仅演示了XADC的一小部分功能,大家可以查阅xadcps.h 头文件尝试打印更多其他的数据。
程序分析:
我们以VCCPINT电压部分的XADC代码举例,采集代码如下:
VccPintRawData = XAdcPs_GetAdcData(XAdcInstPtr, XADCPS_CH_VCCPINT);
VccPintData = XAdcPs_RawToVoltage(VccPintRawData);
printf("\r\nThe Current VCCPINT is %0d.%03d Volts. \r\n",
(int)(VccPintData), XAdcFractionToInt(VccPintData));
- XAdcPs_GetAdcData:负责从指定的地址获取adc值
- XAdcPs_RawToVoltage:负责将采集到的原始adc值换算成对应的电压值
- XAdcFractionToInt:负责将分数部分转换成可以整数,以方便printf打印
- 注意:这里要注意一个地方 XAdcPs_RawToVoltage函数:
- 这个函数中 /65536 而不是/4096 是因为,ADC默认输出是16位,其中高12位是ADC直接采集到的值,剩下的4位是根据平局得到的用来提高精度的位(需要在软件中设置)。
- 另外这个函数还有个地方值得注意的是,内部电压的参考是以3为准的,所以这里是乘以3。
除了上述显示的温度和几个内部电压外,我们还可以采集下面部分的ADC值
- 本文的完整工程下载:17_PS_XADC_TEMPVOLT
- VIVADO的版本:2018.3
- 工程创建目录:E:\Smart_ZYNQ_SP_SL\SDK\17_PS_XADC_TEMPVOLT
- 工程适用主板: Smart ZYNQ (SP / SP2 / SL) (不适用于Smart ZYNQ 标准版 )
想问一下,如果我在主函数里加一个循环函数,让他定时1s输出。我的定时空for循环中的计数应该取多少呢?或者这个有系统编写的延迟函数吗?我在PS端怎么才能像FPGA端中一样利用时钟准确定时呢?谢谢
你可以在PS 中添加一个定时器 1S触发一次即可