本帖最后由 正点原子01 于 2020-9-4 16:24 编辑
1)实验平台:正点原子领航者ZYNQ开发板
2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-301505-1-1.html
4)本章实例源码下载:
XADC接口实验.zip
(7.83 MB, 下载次数: 211)
5)对正点原子FPGA感兴趣的同学可以加群讨论:712557122
6)关注正点原子公众号,获取最新资料更新
第九章PS XADC接口实验
在ZYNQ的PL端有一个数模混合模块——XADC,它是一个硬核。XADC包含两个模数转换器(ADC),一个模拟多路复用器,片上温度和片上电压传感器等。我们可以利用这个模块监测芯片温度和供电电压,也可以用来测量外部的模拟电压信号。 XADC提供了多种接口供外部模块访问,本章我们将使用PS端的XADC接口,读取芯片的温度电压等信息。本章包括以下几个部分: 1 1.1 简介 1.2 实验任务 1.3 硬件设计 1.4 软件设计 1.5 下载验证
1.1 简介ZYNQ SoC的XADC模块包括两个12位的模数转换器,转换速率可以达到1MSPS(每秒一百万次采样)。它带有片上温度和电压传感器,可以测量芯片工作时的温度和供电电压。用户可以设置报警阈值,用来检测温度过高或者供电电压异常等事件。除此之外,通过XADC内部的模拟多路复用器,它还支持最多17路外部模拟输入信号的测量,且支持单极、双极和差分等信号类型。 在7系列的FPGA中,XADC提供了JTAG和DRP(dynamic reconfiguration port)接口,用于访问其内部的状态和控制寄存器。在ZYNQ-7000 SoC器件中,XADC增加了一个PS-XADC接口,用于PS中的软件控制XADC模块。 XADC模块的系统框图如下所示:
图 9.1.1 XADC模块系统框图 在图 10.1.1中PL-JTAG接口可以用于开发工具(Vivado)控制XADC模块,包括读取芯片温度信息等。而运行在PS中的软件则可以通过两种方式与XADC进行通信: 1、 通过PS-XADC接口,此时不需要对PL进行编程配置; 2、 通过PS到PL的AXI Master接口(M_AXI_GP),此时需要在PL中调用AXI XADC IP核。 在使用PS控制XADC时,如果对应用的性能要求较高,则推荐第二种方式,它使用的是一个并行的数据路径(DRP接口)。而PS-XADC接口同PL-JTAG接口一样,使用的是串行的数据路径,相对较慢。不过使用PS-XADC接口不占用PL的资源,也不需要对PL进行编程,只需要对PL部分供电即可。 需要注意的是,PL-JTAG接口与PS-XADC接口不能同时使用。而XADC可以在PL-JTAG接口(或PS-XADC接口)与DRP接口之间进行仲裁。 1.2 实验任务本章的实验任务是通过PS-XADC接口,读取XADC测量的芯片温度、供电电压等信息,并通过串口打印出来。 1.3 硬件设计根据实验任务我们可以画出本次实验的系统框图,如下图所示:
图 9.3.1 系统框图 在图 10.3.1中,CPU通过PS端的PS-XADC接口直接读取PL内XADC模块采集的温度和电压数据,然后通过串口打印出来。需要注意的是,虽然用到了PL内的资源,但是因为使用是硬核模块,所以不需要对PL进行配置。 本次实验在《HelloWorld》实验中的最小系统上就可以完成,也就是说不需要额外配置PS端或者添加PL端的外设。从图 10.3.2中也可以看到,在ZYNQ PS的配置界面中,右下角的PS-XADC接口是灰色的,表明它是不可配置的。 图 9.3.2 PS配置界面 1.4 软件设计在SDK软件中新建一个BSP工程和一个空的应用工程,应用工程名为“ps_xadc”。然后为应用工程新建一个源文件“main.c”,我们在新建的main.c文件中输入本次实验的代码: - #include "xparameters.h"
- #include "xadcps.h"
- #include "stdio.h"
- #include "xil_printf.h"
- #include "sleep.h"
-
- #defineXADC_DEVICE_ID XPAR_XADCPS_0_DEVICE_ID //PS XADC 器件ID
-
- static XAdcPs xadc_inst; //XADC 驱动实例
- int main(void)
- {
- XAdcPs_Config *ConfigPtr; //XADC配置指针
- u32 temp_rawdata; //温度 原始数据
- u32vcc_pint_rawdata; //PS 内核电压 原始数据
- u32vcc_paux_rawdata; //PS 辅助电压 原始数据
- u32vcc_pddr_rawData; //PS DDR电压 原始数据
- u32 vcc_int_rawdata; //PL 内核电压 原始数据
- u32 vcc_aux_rawdata; //PL 辅助电压 原始数据
- u32vcc_bram_rawData; //PL BRAM电压 原始数据
- float temp; //温度
- float vcc_pint; //PS 内核电压
- float vcc_paux; //PS 辅助电压
- float vcc_pddr; //PS DDR电压
- float vcc_int; //PL 内核电压
- float vcc_aux; //PL 辅助电压
- float vcc_bram; //PL BRAM电压
- //初始化XADC驱动
- ConfigPtr =XAdcPs_LookupConfig(XADC_DEVICE_ID);
- XAdcPs_CfgInitialize(&xadc_inst, ConfigPtr,ConfigPtr->BaseAddress);
- //设置XADC操作模式为“默认安全模式”
- XAdcPs_SetSequencerMode(&xadc_inst,XADCPS_SEQ_MODE_SAFE);
- while(1){
- //获取原始温度传感器数据
- temp_rawdata =XAdcPs_GetAdcData(&xadc_inst,XADCPS_CH_TEMP);
- //转换成温度信息
- temp =XAdcPs_RawToTemperature(temp_rawdata);
- //获取VCCPINT传感器数据,并转换成电压信息
- vcc_pint_rawdata = XAdcPs_GetAdcData(&xadc_inst,XADCPS_CH_VCCPINT);
- vcc_pint =XAdcPs_RawToVoltage(vcc_pint_rawdata);
- //获取VCCPAUX传感器数据,并转换成电压信息
- vcc_paux_rawdata = XAdcPs_GetAdcData(&xadc_inst,XADCPS_CH_VCCPAUX);
- vcc_paux =XAdcPs_RawToVoltage(vcc_paux_rawdata);
- //获取VCCPDRO传感器数据,并转换成电压信息
- vcc_pddr_rawData = XAdcPs_GetAdcData(&xadc_inst,XADCPS_CH_VCCPDRO);
- vcc_pddr =XAdcPs_RawToVoltage(vcc_pddr_rawData);
- //获取VCCINT传感器数据,并转换成电压信息
- vcc_int_rawdata= XAdcPs_GetAdcData(&xadc_inst,XADCPS_CH_VCCINT);
- vcc_int =XAdcPs_RawToVoltage(vcc_int_rawdata);
- //获取VCCAUX传感器数据,并转换成电压信息
- vcc_aux_rawdata= XAdcPs_GetAdcData(&xadc_inst,XADCPS_CH_VCCAUX);
- vcc_aux =XAdcPs_RawToVoltage(vcc_aux_rawdata);
- //获取VBRAM传感器数据,并转换成电压信息
- vcc_bram_rawData = XAdcPs_GetAdcData(&xadc_inst,XADCPS_CH_VBRAM);
- vcc_bram =XAdcPs_RawToVoltage(vcc_bram_rawData);
- //打印温度、电压信息
- printf("Raw Temp %lu, Real Temp %fC \n",temp_rawdata, temp);
- printf("Raw VccPInt %lu, Real VccPInt %fV \n",vcc_pint_rawdata, vcc_pint);
- printf("Raw VccPAux %lu, Real VccPAux %fV \n",vcc_paux_rawdata, vcc_paux);
- printf("Raw VccPDDR %lu, Real VccPDDR %fV \n",vcc_pddr_rawData, vcc_pddr);
- printf("Raw VccInt %lu, Real VccInt %fV \n",vcc_int_rawdata, vcc_int);
- printf("Raw VccAux %lu, Real VccAux %fV \n",vcc_aux_rawdata, vcc_aux);
- printf("Raw VccBram %lu, Real VccBram %fV \n\r",vcc_bram_rawData, vcc_bram);
- //延时5s
- sleep(5);
- }
- return 0;
- }
复制代码在主函数中,首先需要对XADC的驱动进行初始化,如程序第31至33行所示。然后在程序的第36行,我们通过调用XAdcPs_SetSequencerMode( )函数将XADC的操作模式设置为默认模式(安全模式)。在该模式下,XADC会自动监测片上温度和电压传感器的数据,并将结果保存在状态寄存器中,此时XADC的操作与其他任何控制寄存器的设置无关。在芯片上电并且配置完成后,XADC同样工作在默认模式下。 在XADC配置完成后,我们通过一个while语句循环读取XADC采集到的温度和电压数据。首先通过XAdcPs_GetAdcData(XAdcPs *InstancePtr, u8 Channel)函数获取XADC采集到的传感器原始数据,该函数的第二个参数是XADC的通道号,每个通道对应不同的传感器数据。如下图所示:
图 9.4.1 XADC默认模式下各通道数据 接下来我们分别通过XAdcPs_RawToTemperature()函数和XAdcPs_RawToVoltage( )函数,将读出的传感器原始数据分别转换成以摄氏度和伏为单位的温度和电压值。程序的最后我们将转换之后的数据打印出来,然后延迟5秒之后再次读取。 程序设计完成后,按快捷键Ctrl+S保存main.c文件,工具会自动进行编译。编译完成后控制台(Console)中会出现提示信息“Build Finished”,同时在应用工程的Binaries目录下可以看到生成的elf文件。 1.5 下载验证首先我们将下载器与领航者底板上的JTAG接口连接,下载器另外一端与电脑连接。然后使用Mini USB连接线将开发板左侧的USB_UART接口与电脑连接,用于串口通信。最后连接开发板的电源,并打开电源开关。 在SDK软件下方的SDK Terminal窗口中点击右上角的加号设置并连接串口。然后下载本次实验软件程序,下载完成后,在下方的SDK Terminal中可以看到应用程序每隔5秒打印一次芯片温度和电压等信息,如下图所示:
图 9.5.1 串口终端中打印的信息 从图 10.5.1中可以看到,串口终端能够正确打印温度和电压信息,说明本次实验在领航者ZYNQ开发板上面下载验证成功。
|