正点原子 发表于 2020-10-13 10:39:15

【正点原子FPGA连载】第七章XADC实验--摘自【正点原子】达芬奇之Microblaze 开发指南

本帖最后由 正点原子 于 2020-10-16 16:43 编辑

1)实验平台:正点原子达芬奇FPGA开发板
2)购买链接:https://detail.tmall.com/item.htm?id=624335496505
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz_dafenqi.html
4) 正点原子官方B站:https://space.bilibili.com/394620890
5)对正点原子FPGA感兴趣的同学可以加群讨论:876744900 点击加入:                                                                                                                           
6)关注正点原子公众号,获取最新资料





第七章XADC实验

Vivado IP核提供了XADC软核,XADC包含两个模数转换器(ADC),一个模拟多路复用器,片上温度和片上电压传感器等。我们可以利用这个模块监测芯片温度和供电电压,也可以用来测量外部的模拟电压信号。
XADC提供了多种接口供外部模块访问,本章我们将使用Microblaze软核处理器端的XADC接口,读取芯片的温度电压等信息。
本章包括以下几个部分:
77.1简介
7.2实验任务
7.3硬件设计
7.4程序设计
7.5下载验证


7.1简介
7系列的XADC IP核包括两个12位的模数转换器,转换速率可以达到1MSPS(每秒一百万次采样)。它带有片上温度和电压传感器,可以测量芯片工作时的温度和供电电压。用户可以设置报警阈值,用来检测温度过高或者供电电压异常等事件。除此之外,通过XADC IP核内部的模拟多路复用器,它支持最多17路外部模拟输入信号的测量,且支持单极、双极和差分等信号类型。

图 7.1.1 XADC模块结构框图
左边红框圈1的,共十七组差分信号,这些端口也可接收单端信号,其中一对VP/N_0为专用的模拟差分输入,其他16对为复用的,不使用时可作为普通的管脚。最上边红框2,表明XADC模块也可采集片上传感器测量到的芯片温度、供电电压等信息;右边红框圈3,是两个12位的模数转换器。XADC采集转换后的数据存储在状态寄存器的专用寄存器内,可由FPGA内部动态配置端口(DRP----Dynamic Reconfiguration Port)的16位同步读/写端口访问;ADC的转换数据也可以由JTAG访问,当使用这种方式时,并不需要直接去例化XADC模块,因为这是一个已经存在与FPGA JTAG结构的专用接口,此时因为没有在设计中直接例化XADC模块,故XADC IP核工作在一种预先定义好的模式即缺省模式,此模式下XADC IP核专用于监视芯片上的供电电压和芯片温度。以上是对XADC IP核的简介。
达芬奇FPGA开发板板载的XADC接口能对0-1V范围间的模拟电压进行测量。由于该范围电压不易产生,所以本实验采集的是内部芯片的温度和电压。
7.2实验任务
本章的实验任务是通过AXI接口读取XADC测量的芯片温度、供电电压等信息,并通过串口打印出来。
7.3硬件设计
根据实验任务我们可以画出本次实验的系统框图,如图 7.3.1所示:

图 7.3.1 系统框图
在图 7.3.1中,CPU通过AXI接口直接读取XADC模块采集的温度和电压数据,然后通过串口打印出来。
通过系统框图可以看出,本次实验硬件设计和《Hello World》实验基本相同。我们将《Hello World》实验的工程另存为本次实验的工程,工程名为“xadc”。
打开Block Design添加XADC IP核,如图 7.3.2所示:

图 7.3.2 添加XADC
双击XADC Wizard IP核,进入配置页面,接下来我们将简要介绍各个配置选项的功能,首先Basic界面,如图 7.3.3所示:

图 7.3.3 XADC Basic界面
Interface Options(接口选择):此选项用于选择xadc的接口。您可以选择axi4lite、DRP或None选项。DRP端口是XADC的FPGA逻辑接口,它便于访问xadc的寄存器文件接口,可以使用此端口读取或写入xadc控制寄存器,但只有当dclk时钟存在时,才能启用此端口。
Timing Mode(计时模式):该选项可以选择Continuous Mode(连续模式)和Event Mode(事件模式)两种模式。Continuous Mode能够根据选择的通道连续采样和转换,Event Mode则需要触发时间才能进行采样和转换。
Startup Channel Selection(启动通道选择):四种模式,Simultaneous Selection(同时选择,可同时监控两个外部通道)、Independent ADC(独立ADC),Single Channel(单通道)和Channel Sequencer(通道序列器)。
AXI4-Stream Options(AXI4-Stream选择):通过该选项可以启用或禁用AXI4流接口,并在FIFO Depth选项选择FIFO深度(7-1020)。
DRP Timing Options(DRP时钟选择):在该处可以指定外部dclk频率(DCLK Frequency)和所需的ADC转换速率(Actual Conversion Rate,最大1msps),同时还显示了ADC时钟频率值和ADC的实际转换率。
Control/Status Ports(控制/状态端口):此处选项可选择reset_in(外部输入复位)、Temp Bus(输出Temp总线)和JTAG Arbiter(JTAG状态)三个端口;Event Mode Trigger选项可选择事件触发模式。
Analog Sim File Options(模拟Sim选项):仿真文件设置选项。
本界面无需修改,所有选项保持默认即可。
ADC Setup界面:

图 7.3.4 ADC Setup界面
如果在Basic界面将XADC的通道配置为“Channel Sequencer”、“Simultaneous Sampling”或者“Independent ADC”模式,则在ADC Setup界面Sequencer Mode可以设置为Continuous(连续)、One-pass(一次)或Default(默认)模式,否则该选项为灰色不可设置。Channel Averaging选项可以选择所需的平均值(None、16、64、256四种)。
External Multiplexer Setup(外部多路复用器设置):在该选项我们可以选中“Entemal Mulplexer”选项来启用外部多路复用器,在“Channel for MUX”选项选择需要的通道。
Power Down Options(断电模式):此选项可以选择给ADCB或ADCA断电。
Alarms界面:

图 7.3.5 Alarms界面
在该界面我们可以设置超温报警(Over Temperature Alarm)和用户温度报警(User Temperature Alarm)的触发(Trigger)和重置(Reset)温度。
我们还可以指定内核电压(VCCINT)、辅助电压(VCCAUX)和BRAM(VCCBRAM)电压报警阈值的上限和下限。
在本次实验中,XADC只用于数据采集和转换,并不需要做其他设置,因此我们对XADC的选项保持默认就可以了。点击“OK”按钮,关闭XADC IP核界面。
点击“Run Connection Automation”,在弹出的提示框内选中所有信号,然后点击“OK”,如图 7.3.6所示:

图 7.3.6 自动连线
连线完成后点击“Regenerate Layout”按钮,进行布局,最终的硬件设计布局如图 7.3.7所示:

图 7.3.7 最终布局图
接下来在Source窗口中右键点击Block Design设计文件“system.bd”,然后依次执行“Generate Output Products”和“Create HDL Wrapper”。
管脚约束不变。
最后在左侧Flow Navigator导航栏中找到PROGRAM AND DEBUG,点击该选项中的“Generate Bitstream”,对设计进行综合、实现、并生成Bitstream文件。
在生成Bitstream之后,在菜单栏中依次点击“File->Export->Export hardware”导出硬件,并在弹出的对话框中,勾选“Include bitstream”,在导出路径最后添加“/vitis”。然后在菜单栏依次点击“Tools->Launch Vitis”,启动Vitis软件。
7.4软件设计
在将硬件导出至Vitis,并打开Vitis开发环境后,创建应用工程的步骤都是一样的,这里不再赘述,新创建的空白应用工程命名为xadc。然后为应用工程新建一个源文件“main.c”,我们在新建的main.c文件中输入本次实验的代码:
1#include "xsysmon.h"
2#include "xparameters.h"
3#include "xstatus.h"
4#include "stdio.h"
5#include "sleep.h"
6
7//XADC ID
8#define SYSMON_DEVICE_ID    XPAR_SYSMON_0_DEVICE_ID
9
10 static XSysMon SysMonInst;    //XADC驱动实例
11
12 int SysMonFractionToInt(float FloatNum);
13
14 int main(void){
15   XSysMon_Config *ConfigPtr;
16   u32 TempRawData;    //温度 原始数据
17   u32 VccAuxRawData;//辅助电压 原始数据
18   u32 VccIntRawData;//内核电压 原始数据
19   u32 VccBRAMdata;    //BRAM电压 原始数据
20
21   float TempData;   //温度
22   float VccAuxData;   //辅助电压
23   float VccIntData;   //内核电压
24   float VBRAM;      //BRAM电压
25   float MaxData;      //最大值
26   float MinData;      //最小值
27   //初始化XADC器件
28   ConfigPtr = XSysMon_LookupConfig(SYSMON_DEVICE_ID);
29         if (ConfigPtr == NULL) {
30             return XST_FAILURE;
31         }
32   XSysMon_CfgInitialize(&SysMonInst, ConfigPtr, ConfigPtr->BaseAddress);
33                     
34 //默认安全模式
35 XSysMon_SetSequencerMode(&SysMonInst, XSM_SEQ_MODE_SAFE);
36
37 //使能的相应的通道
38 XSysMon_SetSeqChEnables(&SysMonInst,XSM_SEQ_CH_TEMP| //温度
39                           XSM_SEQ_CH_VCCINT |      //内核电压
40                           XSM_SEQ_CH_VCCAUX|       //辅助电压
41                           XSM_SEQ_CH_VBRAM         //BRAM电压
42                           );
43 //设置为循环模式
44 XSysMon_SetSequencerMode(&SysMonInst,XSM_SEQ_MODE_CONTINPASS);
45
46   while(1){
47         //读取温度
48         TempRawData = XSysMon_GetAdcData(&SysMonInst, XSM_CH_TEMP);
49         TempData = XSysMon_RawToTemperature(TempRawData);
50         xil_printf("\r\nThe Current Temperature is %0d.%03d Centigrades.\r\n",
51                     (int)(TempData), SysMonFractionToInt(TempData));
52         //读取最大温度
53         TempRawData = XSysMon_GetMinMaxMeasurement(&SysMonInst, XSM_MAX_TEMP);
54         MaxData = XSysMon_RawToTemperature(TempRawData);
55         xil_printf("The Maximum Temperature is %0d.%03d Centigrades. \r\n",
56                     (int)(MaxData), SysMonFractionToInt(MaxData));
57         //读取最小温度
58         TempRawData = XSysMon_GetMinMaxMeasurement(&SysMonInst, XSM_MIN_TEMP);
59         MinData = XSysMon_RawToTemperature(TempRawData);
60         xil_printf("The Minimum Temperature is %0d.%03d Centigrades. \r\n",
61                     (int)(MinData), SysMonFractionToInt(MinData));
62         //读取核心电压
63         VccIntRawData = XSysMon_GetAdcData(&SysMonInst, XSM_CH_VCCINT);
64         VccIntData = XSysMon_RawToVoltage(VccIntRawData);
65         xil_printf("The Current VCCINT is %0d.%03d Volts. \r\n",
66                     (int)(VccIntData), SysMonFractionToInt(VccIntData));
67      //读取辅助器电
68         VccAuxRawData = XSysMon_GetAdcData(&SysMonInst,XSM_CH_VCCAUX );
69         VccAuxData = XSysMon_RawToVoltage(VccAuxRawData);
70         xil_printf("The Current VCCAUX is %0d.%03d Volts. \r\n",
71                     (int)(VccAuxData), SysMonFractionToInt(VccAuxData));
72         //读取BRAM电压
73         VccBRAMdata = XSysMon_GetAdcData(&SysMonInst,XSM_CH_VCCAUX );
74         VBRAM = XSysMon_RawToVoltage(VccBRAMdata);
75         xil_printf("The Current VBRAM is %0d.%03d Volts. \r\n",
76                         (int)(VBRAM), SysMonFractionToInt(VBRAM));
77         sleep(1);
78         }
79
80         return 0;
81   }
82
83 int SysMonFractionToInt(float FloatNum)
84 {
85   float Temp;
86
87   Temp = FloatNum;
88   if (FloatNum < 0) {
89         Temp = -(FloatNum);
90   }
91   //将浮点数线束部分扩大1000倍,以便打印
92   return( ((int)((Temp -(float)((int)Temp)) * (1000.0f))));
93 }
在主函数中,首先需要对XADC的驱动进行初始化,如程序第28至33行所示。然后在程序的第36行,我们通过调用XSysMon_SetSequencerMode( )函数将XADC的操作模式设置为默认模式(安全模式)。在该模式下,XADC会自动监测片上温度和电压传感器的数据,并将结果保存在状态寄存器中,此时XADC的操作与其他任何控制寄存器的设置无关。在芯片上电并且配置完成后,XADC同样工作在默认模式下。接着我们调用XSysMon_SetSeqChEnables函数使能相应的通道(温度,内核电压,辅助电压和BRAM电压),然后再次调用XSysMon_SetSequencerMode函数将操作模式设置为循环模式,进行循环采样。
在XADC配置完成后,我们通过一个while语句循环读取XADC转换后的温度和电压数据。首先通过XSysMon_GetAdcData(XSysMon *InstancePtr, u8 Channel)函数获取XADC采集到的传感器原始数据,该函数的第二个参数是XADC的通道号,每个通道对应不同的传感器数据。
接下来我们分别通过XSysMon_RawToTemperature ( )函数和XSysMon_RawToVoltage ( )函数,将读出的传感器原始数据分别转换成以摄氏度和伏为单位的温度和电压值。程序的最后我们将转换之后的数据打印出来,然后延迟1秒之后再次读取。
需要注意的是在代码第83到93行,使用了SysMonFractionToInt函数,该函数的目的就是将转化后的温度和电压数据的小数部分扩大1000倍,以便于打印。我们可以看到在while语句中,调用了xil_printf的函数,但是该函数并不支持打印浮点型数据,因此,分别打印其浮点型数据的整数部分和小数部分,再用小数点连接,以此来打印浮点型数据。
程序设计完成后,按快捷键Ctrl+S保存main.c文件,接着编译工程。编译完成后控制台(Console)中会出现提示信息“Build Finished”,同时在应用工程的Binaries目录下可以看到生成的elf文件。
7.5下载验证
首先我们将下载器与达芬奇开发板上的JTAG接口连接,下载器另外一端与电脑连接。然后使用USB连接线将开发板左侧的USB_UART接口与电脑连接,用于串口通信。最后连接开发板的电源,并打开电源开关。
调出Vitis的Terminal窗口,设置并连接串口成功(过程不再赘述)。下载本次实验软件程序,下载完成后,在下方的Vitis Terminal中可以看到应用程序每隔1秒打印一次芯片温度和电压等信息,如图 7.5.1所示:

图 7.5.1 串口终端中打印的信息
从图 7.5.1中可以看到,串口终端能够正确打印温度和电压信息,说明本次实验在开发板上面下载验证成功。
页: [1]
查看完整版本: 【正点原子FPGA连载】第七章XADC实验--摘自【正点原子】达芬奇之Microblaze 开发指南