XADC功能很强大后续将通过多篇文章来介绍XADC的功能,本文将简单演示通过 PS端调用片内XADC资源 来实时读取芯片的电源和温度等信息。以及介绍使用Vp,Vn脚来采集外部电压的方法。
- 此章节内容适用于Lemon 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-CLG400-1
2. 连接好主板,下载器和电脑(Lemon Zynq自带板载下载器 )
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. 因为Lemon ZYNQ主板的PS时钟是50M的晶振输入的,所以这里需要把默认的PS输入时钟33.33M改成50M
6. 在PS的MIO配置选项增加UART部分,使能UART 0 并在IO选项里选择MIO(14-15)方式
7.因为工程暂时用不到 AXI功能,所以可以先禁用AXI功能
8.完成后点选 Run Block Automation,完成后续自动布线
9. source→Design Source ,右键我们创建的BLOCK工程,点击create HDL wrapper,打包BLOCK文件并生成.v代码
10. 点击绿色箭头RUN 对代码进行编译
11) 因为本工程只用到PS部分资源,并没有用到PL或者EMIO等涉及到PL IO的资源,所以这里我们不需要做管脚约束。
12) 生成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 连接好板子的串口线,以及下载器
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值
实战测试VP_VN脚的电压:
1)板子除了上述内部电压和温度外,还可以测量外部引脚的电压,大多数XADC输出脚都接在PL端,只能通过PL协同才能调用,但是也有两个脚是可供PS程序上直接调度的。
上图XADCPS_CH_VPVN对应的就是ZYNQ芯片上的 VP,VN模拟脚, 这两个脚是不需要PL部分协同,我们可以在PS通过读取XADCPS_CH_VPVN的电压值得到 VP和VN脚之间的电压差。(这个范围是0-1V),测量的时候也可以直接把VN接GND, 这样通过采集XADCPS_CH_VPVN得到的电压即VP点的电压。
1)注释掉demo中的 Xadc运行模式为XADCPS_SEQ_MODE_CONTINPASS,并且增加检测序列,在里面添加XADCPS_SEQ_CH_VPVN。
//XAdcPs_SetSequencerMode(XAdcInstPtr, XADCPS_SEQ_MODE_SAFE);
XAdcPs_SetSeqChEnables (XAdcInstPtr,XADCPS_SEQ_CH_TEMP |XADCPS_SEQ_CH_VCCPINT
| XADCPS_SEQ_CH_VCCPAUX |XADCPS_SEQ_CH_VCCPDRO | XADCPS_SEQ_CH_VCCINT
| XADCPS_SEQ_CH_VCCAUX | XADCPS_SEQ_CH_VBRAM| XADCPS_SEQ_CH_VPVN);
XAdcPs_SetSequencerMode(XAdcInstPtr,XADCPS_SEQ_MODE_CONTINPASS);
2)模仿demo中内部电压检测的代码,写一个VPVN的采集ADC采集部分代码,注意:原先demo中内部电压的adc采集参考电压是3V ,这里需要修改成1V。
u32 VccPvpvnRawData;
float VccPvpvnData;
VccPvpvnRawData = XAdcPs_GetAdcData(XAdcInstPtr, XADCPS_CH_VPVN);
VccPvpvnData=((((float)(VccPvpvnRawData))* (1.0f))/65536.0f);
printf("\r\nThe Current VpVn is %0d.%03d Volts. \r\n\r\n",
(int)(VccPvpvnData), XAdcFractionToInt(VccPvpvnData));
3)硬件上,因为VP,VN是一组差分双电极的模拟采集口,这里我们要采集电压源的电压,可以直接将Vp 接到电压源的正极,Vn接到板子的GND上,电压源的负极也接到GND上,相当于拿Vp当单端模拟采集口对电压进行采集。
4)之后SDK下保存并运行程序,查看结果:如下图所示,XADC采集到的电压值和实际的电压值一致,VP,VN电压采集成功。
关于Vp Vn 修改过的程序可以查看本文的完整工程。
以上就是本节的内容,等有时间再整理一下如何在PS端采集VP VN以外其他XADC IO的方法。
- 本文的完整工程下载:17_PS_XADC_TEMPVOLT
- VIVADO的版本:2018.3
- 工程创建目录:E:\Lemon_ZYNQ\SDK\17_PS_XADC_TEMPVOLT