XADC实验

1、XADC概述

Xilinx7系列内部自带一个双通道12位分辨率的高速(1MSPS 1M sample per second)采样速率的模拟混合信号处理模块,双通道的ADC支持单极和差分工作模式,最多支持17路外部模拟输入通道。称为XADC(Xilinx Analog signal Module),有JTAG和DRP(Dynamic Reconfiguration Port)接口,用于访问状态寄存器和控制寄存器(DRP),其中控制寄存器可以通过DRP进行读写从而实现XADC的初始化配置,状态寄存器只可进行读取操作,ADC将采样转换后的值保存在对应的状态寄存器,通过DRP即可将其读出。

单极工作模式和差分工作模式:

单极工作模式是指AD的模拟电压输入口检测到的电压相当于对地电压。单端输入只有一个输入引脚ADCIN,使用公共端作为电路的返回端,这种方式的优点是简单,缺点是如果Vin受到干扰,由于GND电位始终是0,所以最终ADC的采样值也会随着干扰而变化。

差分工作模式是指检测两个输入口之间的电压,比如一个是3.0V另一个是2.5V,如果两者进入差分工作模式,检测到的电压等于其差值,即0.5V。通常这两根差分线会布线在一起,所以他们收到的干扰是相近的,输入共模干扰,在输入ADC时会被减掉,从而降低了干扰,缺点是接线复杂

2、源码分析

源码main.c文件

/*

* main.c

*

*  Created on: 2016年6月25日

*      Author: Administrator

*/

#include <stdio.h>

//#include "platform.h"

#include "xadcps.h"

#include "xil_types.h"

#define XPAR_AXI_XADC_0_DEVICE_ID 0

//void print(char *str);

static XAdcPs XADCMonInst;

/*

Raw Temp 39966 Real Temp 34.191864

Raw VccInt 22202 Real VccInt 1.016327

Raw VccAux 39171 Real VccAux 1.793106

Raw VccBram 22171 Real VccBram 1.014908

Raw VccPInt 22166 Real VccPInt 1.014679

Raw VccPAux 39224 Real VccPAux 1.795532

Raw VccDDR 32738 Real VccDDR 1.498627

*

* */

int main()

{

XAdcPs_Config *ConfigPtr;

XAdcPs *XADCInstPtr = &XADCMonInst;

//status of initialisation

int Status_ADC;

//temperature readings

u32 TempRawData;

float TempData;

//Vcc Int readings

u32 VccIntRawData;

float VccIntData;

//Vcc Aux readings

u32 VccAuxRawData;

float VccAuxData;

//Vbram readings

u32 VBramRawData;

float VBramData;

//VccPInt readings

u32 VccPIntRawData;

float VccPIntData;

//VccPAux readings

u32 VccPAuxRawData;

float VccPAuxData;

//Vddr readings

u32 VDDRRawData;

float VDDRData;

// init_platform();

//printf("Adam Edition MicroZed Using Vivado How To Printf \n\r");

printf("新年快乐~~!!!2015-12-31 \n\r");

//XADC initilization

ConfigPtr = XAdcPs_LookupConfig(XPAR_AXI_XADC_0_DEVICE_ID);

if (ConfigPtr == NULL) {

return XST_FAILURE;

}

Status_ADC = XAdcPs_CfgInitialize(XADCInstPtr,ConfigPtr,ConfigPtr->BaseAddress);

if(XST_SUCCESS != Status_ADC){

print("ADC INIT FAILED\n\r");

return XST_FAILURE;

}

//self test

Status_ADC = XAdcPs_SelfTest(XADCInstPtr);

if (Status_ADC != XST_SUCCESS) {

return XST_FAILURE;

}

//stop sequencer

XAdcPs_SetSequencerMode(XADCInstPtr,XADCPS_SEQ_MODE_SINGCHAN);

//disable alarms

XAdcPs_SetAlarmEnables(XADCInstPtr, 0x0);

//configure sequencer to just sample internal on chip parameters

XAdcPs_SetSeqInputMode(XADCInstPtr, XADCPS_SEQ_MODE_SAFE);

//configure the channel enables we want to monitor

XAdcPs_SetSeqChEnables(XADCInstPtr,XADCPS_CH_TEMP|XADCPS_CH_VCCINT|XADCPS_CH_VCCAUX|XADCPS_CH_VBRAM|XADCPS_CH_VCCPINT| XADCPS_CH_VCCPAUX|XADCPS_CH_VCCPDRO);

while(1)

{

TempRawData = XAdcPs_GetAdcData(XADCInstPtr, XADCPS_CH_TEMP);

TempData = XAdcPs_RawToTemperature(TempRawData);

printf("Raw Temp %lu Real Temp %f \n\r", TempRawData, TempData);

VccIntRawData= XAdcPs_GetAdcData(XADCInstPtr, XADCPS_CH_VCCINT);

VccIntData = XAdcPs_RawToVoltage(VccIntRawData);

printf("Raw VccInt %lu Real VccInt %f \n\r", VccIntRawData,VccIntData);

VccAuxRawData = XAdcPs_GetAdcData(XADCInstPtr, XADCPS_CH_VCCAUX);

VccAuxData = XAdcPs_RawToVoltage(VccAuxRawData);

printf("Raw VccAux %lu Real VccAux %f \n\r", VccAuxRawData,VccAuxData);

VBramRawData = XAdcPs_GetAdcData(XADCInstPtr, XADCPS_CH_VBRAM);

VBramData = XAdcPs_RawToVoltage(VBramRawData);

printf("Raw VccBram %lu Real VccBram %f \n\r", VBramRawData, VBramData);

VccPIntRawData = XAdcPs_GetAdcData(XADCInstPtr, XADCPS_CH_VCCPINT);

VccPIntData = XAdcPs_RawToVoltage(VccPIntRawData);

printf("Raw VccPInt %lu Real VccPInt %f \n\r", VccPIntRawData, VccPIntData);

VccPAuxRawData = XAdcPs_GetAdcData(XADCInstPtr, XADCPS_CH_VCCPAUX);

VccPAuxData = XAdcPs_RawToVoltage(VccPAuxRawData);

printf("Raw VccPAux %lu Real VccPAux %f \n\r", VccPAuxRawData, VccPAuxData);

VDDRRawData = XAdcPs_GetAdcData(XADCInstPtr, XADCPS_CH_VCCPDRO);

VDDRData = XAdcPs_RawToVoltage(VDDRRawData);

printf("Raw VccDDR %lu Real VccDDR %f \n\r", VDDRRawData, VDDRData);

}

return 0;

}

分析

#include<stdio.h>

包含基本输入输出操作指令

#define XPAR_AXI_XADC_0_DEVICE_ID 0

//宏定义XADC的设备IDentity为0

typedef struct {

u16  DeviceId;      /**< Unique ID of device */

u32  BaseAddress;  /**< Device base address */

} XAdcPs_Config;

//定义结构体XAdcPs_Config,结构体包含两个内容,一个是设备id,另一个是设备的基本地址

typedef struct {

XAdcPs_Config Config;  /**< XAdcPs_Config of current device */

u32  IsReady;       /**< Device is initialized and ready  */

} XAdcPs;

//该结构体定义了设备的实例数据,第一部分包含两个内容(id、basement),第二部分为设备的成功初始化完毕标志。

程序语句1: XAdcPs_Config *ConfigPtr;

定义了一个结构体指针,结构体使用指针时对于其中内容的操作需要使用->操作符而不可使用包含操作符 . ,该结构体指针所指向的地址存储单元寄存了设备的id与基础地址

程序语句2:XAdcPs *XADCInstPtr = &XADCMonInst;

本语句与上类似,但是多一个ready信号,将在XAdcPs_CfgInitalize()语句中进行综合。此外,与数组不同的是,结构名并不是结构的地址,因此在对结构指针进行初始化时需要在结构名前加取址符&

程序语句3:

ConfigPtr = XAdcPs_LookupConfig(XPAR_AXI_XADC_0_DEVICE_ID);

if (ConfigPtr == NULL) {

return XST_FAILURE;

}

该语句用于XADC的初始化,首先查看XAdcPs_LookupConfig函数的定义:

XAdcPs_Config *XAdcPs_LookupConfig(u16 DeviceId)

{

XAdcPs_Config *CfgPtr = NULL;

u32 Index;

for (Index=0; Index < 1; Index++) {

if (XAdcPs_ConfigTable[Index].DeviceId == DeviceId) {

CfgPtr = &XAdcPs_ConfigTable[Index];

break;

}

}

return CfgPtr;

}

传入参数是16bit的设备ID,返回的是一个XAdcPs_Config结构体格式的指针,返回值将指针地址赋值给配置结构指针ConfigPtr,该子函数的定义中,将传入的ID参数与Xilinx头文件中已定义的XADC的设备ID进行相等判断,if true,则将库中设备配置文件表XAdcPs_ConfigTable结构的地址的赋给开头定义的结构指针并返回。如果不等,则定义的指针仍然为NULL,这会在接下来的判断语句中用到。

目的:以上代码就是从系统中查看是否有该设备的定义,如果有,可以看到关于该设备描述的结构以及该设备在ZYNQ地址空间中的地址。就是一个查询语句。

程序语句4:

Status_ADC=XAdcPs_CfgInitialize(XADCInstPtr,ConfigPtr,ConfigPtr->BaseAddress);

if(XST_SUCCESS != Status_ADC){

print("ADC INIT FAILED\n\r");

return XST_FAILURE;

}

该语句的作用是对设备进行初始化配置,首先声明几个调用的子函数:

(1)、断言函数—Xil_AssertNonvoid(Expression)

#define Xil_AssertNonvoid(Expression)             \

{                                                  \

if (Expression) {                              \

Xil_AssertStatus = XIL_ASSERT_NONE;       \

} else {                                       \

Xil_Assert(__FILE__, __LINE__);            \

Xil_AssertStatus = XIL_ASSERT_OCCURRED;   \

return 0;                                  \

}                                              \

}

该函数作用是如果传入参数为true则程序正常执行,否则条件返回错误,终止程序运行。

(2)、地址数据读取函数

#define XAdcPs_ReadReg(BaseAddress, RegOffset) \

(Xil_In32((BaseAddress) + (RegOffset)))

通过宏定义的形式定义函数,在宏定义时若隔行操作需要加反斜杠 \,其中的Xil_In32函数为一内联(inline)函数,内联函数可以减少一次函数调用的时间。为什么这么设计?查阅到的答案是:在头文件中加内联声明inline,外不要使用不会内联,要使用的话必须加static,文本域为全局。

static INLINE u32 Xil_In32(UINTPTR Addr)

{

return *(volatile u32 *) Addr;

此处还需要理解*(volatile *)的作用:第一是强制转换为指针类型 volatile *将一个普通的32位值转换为地址。第二是再加一个*的作用是对地址进行取值。

(3)、地址数据写入

#define XAdcPs_WriteReg(BaseAddress, RegOffset, Data) \

(Xil_Out32((BaseAddress) + (RegOffset), (Data)))

原函数定义

int XAdcPs_CfgInitialize(XAdcPs *InstancePtr, XAdcPs_Config *ConfigPtr,

u32 EffectiveAddr)

{

u32 RegValue;

/*

*对输入的两个结构体指针进行断言处理,断言处理完成向下进行

*/

Xil_AssertNonvoid(InstancePtr != NULL);

Xil_AssertNonvoid(ConfigPtr != NULL);

/*

* 将设备ID和设备地址赋值给实例结构,此处C语法是结构指针只能用->不可用.

*/

InstancePtr->Config.DeviceId = ConfigPtr->DeviceId;

InstancePtr->Config.BaseAddress = EffectiveAddr;

/* 首先是将设备进行解锁,unlock,这个寄存器的基本地址XPAR_XDCFG_0_BASEADDRESSs=0xF8007000u 偏移地址UNLOCK_OFFSET=0x034,解锁值XAdcPs_WriteReg是0x757bdf0d,根据数据手册,该寄存器的作用是保护设备寄存器面授ROM代码损坏*/

XAdcPs_WriteReg(XPAR_XDCFG_0_BASEADDR, XADCPS_UNLK_OFFSET,XADCPS_UNLK_VALUE);

/*本语句是Xilinx的套路用法,首先将控制寄存器的值读出来,然后再根据要设置的项目进行或处理,即置一设置,

Enable the PS access of xadc and set FIFO thresholds */

RegValue = XAdcPs_ReadReg((InstancePtr)->Config.BaseAddress,

XADCPS_CFG_OFFSET);

RegValue = RegValue | XADCPS_CFG_ENABLE_MASK |

XADCPS_CFG_CFIFOTH_MASK | XADCPS_CFG_DFIFOTH_MASK;

XAdcPs_WriteReg((InstancePtr)->Config.BaseAddress,

XADCPS_CFG_OFFSET, RegValue);

/* Release xadc from reset 本语句的作用是将XADC从复位中释放,XADCPS_MCTL_OFFSET=0x18,即偏移地址为0x18,该寄存器的第四位【4】平时为1,则PS-XADC的通道不通,所以需要从复位中释放,也就是写入0,其实只给bit【4】写0就可以,但是还得重新写函数,麻烦了,所以就一起写0吧,因为其他位都没有用,bit4的说明是:This bit will reset the commuincation channel between XADC and PS,If set,the PS-XADC will remain in reset until a 0 is written to this bit */

XAdcPs_WriteReg((InstancePtr)->Config.BaseAddress,

XADCPS_MCTL_OFFSET, 0x00);

/*

* Indicate the instance is now ready to use and

* initialized without error.以上语句执行完毕之后就可以将Isready位置一了,表示初始化配置完成

*/

InstancePtr->IsReady = XIL_COMPONENT_IS_READY;

return XST_SUCCESS;    /*执行完毕,返回0 */

}

/*程序返回之后,将返回值XST_SUCCESS给Status进行判断,不相等即初始化失败,其实也可以判断IsReady*/

if(XST_SUCCESS != Status_ADC){

print("ADC INIT FAILED\n\r");

return XST_FAILURE;

}

程序语句5:Status_ADC = XAdcPs_SelfTest(XADCInstPtr);

(1)、XAdcPs_Reset(InstancePtr);

void XAdcPs_Reset(XAdcPs *InstancePtr)

{

/*

* Assert the arguments.

*/

Xil_AssertVoid(InstancePtr != NULL);

Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

/*

* Generate the reset by Control* register and release from reset

*再次将XADC从复位中释放,

*/

XAdcPs_WriteReg((InstancePtr)->Config.BaseAddress,

XADCPS_MCTL_OFFSET, 0x10);

XAdcPs_WriteReg((InstancePtr)->Config.BaseAddress,

XADCPS_MCTL_OFFSET, 0x00);

}

函数定义

int XAdcPs_SelfTest(XAdcPs *InstancePtr)

{

int Status;

u32 RegValue;

/*

* 断言语句判断输入的结构指针是否为空,初始化成功是否为真

*/

Xil_AssertNonvoid(InstancePtr != NULL);

Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

/*

* Reset the device to get it back to its default state

*/

XAdcPs_Reset(InstancePtr);

/*

* Write a value into the Alarm Threshold registers, read it back, and

* do the comparison将一个值写入警报阈值寄存器并读取,进行比较判断是否设置成功

*/

XAdcPs_SetAlarmThreshold(InstancePtr, XADCPS_ATR_VCCINT_UPPER,

XADCPS_ATR_TEST_VALUE);

RegValue = XAdcPs_GetAlarmThreshold(InstancePtr, XADCPS_ATR_VCCINT_UPPER);

if (RegValue == XADCPS_ATR_TEST_VALUE) {

Status = XST_SUCCESS;

} else {

Status = XST_FAILURE;

}

/*

* Reset the device again to its default state.

*/

XAdcPs_Reset(InstancePtr);

/*

* Return the test result.

*/

return Status;

}

Status_ADC = XAdcPs_SelfTest(XADCInstPtr);

if (Status_ADC != XST_SUCCESS) {

return XST_FAILURE;

}

程序语句6:XAdcPs_SetSequencerMode(XADCInstPtr,XADCPS_SEQ_MODE_SINGCHAN);

void XAdcPs_SetSequencerMode(XAdcPs *InstancePtr, u8 SequencerMode)

{

u32 RegValue;

/*

* Assert the arguments.

*/

Xil_AssertVoid(InstancePtr != NULL);

Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);

Xil_AssertVoid((SequencerMode <= XADCPS_SEQ_MODE_SIMUL_SAMPLING) ||

(SequencerMode == XADCPS_SEQ_MODE_INDEPENDENT));

/*

* Set the specified sequencer mode in the Configuration Register 1.在配置寄存器1中读取寄存器的值,然后设置这个寄存器,使XADC停止顺序模式

*/

RegValue = XAdcPs_ReadInternalReg(InstancePtr,

XADCPS_CFR1_OFFSET);

RegValue &= (~ XADCPS_CFR1_SEQ_VALID_MASK);

RegValue |= ((SequencerMode  << XADCPS_CFR1_SEQ_SHIFT) &

XADCPS_CFR1_SEQ_VALID_MASK);

XAdcPs_WriteInternalReg(InstancePtr, XADCPS_CFR1_OFFSET,

RegValue);

}

程序语句7:

XAdcPs_SetAlarmEnables(XADCInstPtr, 0x0);

//同上,先读取控制寄存器1,然后通过或的形式取消alarm

//配置XADC仅进行内部电压转换

XAdcPs_SetSeqInputMode(XADCInstPtr, XADCPS_SEQ_MODE_SAFE);

//设置检测通道

XAdcPs_SetSeqChEnables(XADCInstPtr,XADCPS_CH_TEMP|XADCPS_CH_VCCINT|XADCPS_CH_VCCAUX|XADCPS_CH_VBRAM|XADCPS_CH_VCCPINT| XADCPS_CH_VCCPAUX|XADCPS_CH_VCCPDRO);

程序语句8:数据读取

TempRawData = XAdcPs_GetAdcData(XADCInstPtr, XADCPS_CH_TEMP);

//

RegData = XAdcPs_ReadInternalReg(InstancePtr,

(XADCPS_TEMP_OFFSET +

Channel));

XADC的更多相关文章

  1. MiZ702学习笔记9——XADC采集片上数据PS版

    这次借助zynq的内嵌的XADC来采集zynq内部的一些参数: •VCCINT:内部PL核心电压 •VCCAUX:辅助PL电压 •VREFP:XADC正参考电压 •VREFN:XADC负参考电压 •V ...

  2. 开源地图SharpMap源码解析-(1)简介

    1.简介 SharpMap最新版基于.NET Framework 4,采用C#开发的地图渲染引擎,非常易于使用.我这次研究的是比较稳定发布的V1.1版本.可以在GitHub下载该源码,地址:https ...

  3. Learn ZYNC (4)

    最近整理出一些适合学习zed的实例(所有的例程都基于Vivado2013.4开发环境) (1)关于zed双核的测试案例: 官方链接:地址1.11.standalone,地址1.12.linux 修改源 ...

  4. ZedBoard 引脚约束参考

    从ISE转换到Vivado时,UCF转XDC的几种方法: (1)软件自动转换 参考网址:Youtube 用ISE->EDK->PlanAhead打开所需转换的工程文件*.xise,并打开b ...

  5. [FPGA] 1、Artix-7 35T Arty FPGA 评估套件学习 + SiFive risc-v 指令集芯片验证

    目录 1.简介 2.深入 3.DEMO 4.SiFive基于risc-v指令集的芯片验证 LINKS 时间 作者 版本 备注 2018-10-09 08:38 beautifulzzzz v1.0 到 ...

  6. Java NIO的工作方式

    1.BIO带来的挑战 BIO即阻塞IO,不管是磁盘IO,还是网络IO,数据在写入OutputStream或者从InputStream读取时都有可能发生阻塞,一旦有阻塞,当前线程将会被挂起,即线程进入非 ...

  7. 7 Serial Configuration 理解(三)

    *Dynamic Reconfiguration Port(DRP) 动态重配置端口:在7系列FPGA中,配置存储器主要用于实现用户逻辑,连接和I / O,但它也用于其他目的. 例如,它用于指定功能块 ...

  8. 【Python】使用torrentParser1.03对单文件torrent的分析结果

    C:\Users\horn1\Desktop\python\42-torrentParser>python torrentParser.py 文件名=./5.torrent 文件结构: anno ...

  9. 【Python】使用torrentParser1.03对多文件torrent的分析结果

    Your environment has been set up for using Node.js 8.5.0 (x64) and npm. C:\Users\horn1>cd C:\User ...

随机推荐

  1. Unity PlayerPrefs 存储的位置

    Mac OS 在Mac OS X上PlayerPrefs是存储在~/Library/Preferences文件夹,名为unity.[company name].[product name].plist ...

  2. 2018-2019-2 网络对抗技术 20165220 Exp 9 Web安全基础

    2018-2019-2 网络对抗技术 20165220 Exp 9 Web安全基础 实验任务 本实践的目标理解常用网络攻击技术的基本原理,做不少于7个题目,共3.5分.包括(SQL,XSS,CSRF) ...

  3. 实验报告(一)&第三周总结

    Java实验报告 实验一 Java开发环境与简单Java程序 一. 实验目的 (1)      熟悉JDK开发环境 (2)      熟练掌握结构化程序设计方法 二. 实验内容 1.      打印输 ...

  4. Mac OS下Flutter环境搭建记录,VS Code开发

    安装Flutter 获取FlutterSDK 终端cd进入SDK安装目录,比如 cd ~/FlutterSDK 由于在国内访问Flutter有时可能会受到限制,Flutter官方为中国开发者搭建了临时 ...

  5. linux测试某进程占用oi、cpu、内存的使用情况

    pidstat 概述 pidstat是sysstat工具的一个命令,用于监控全部或指定进程的cpu.内存.线程.设备IO等系统资源的占用情况.pidstat首次运行时显示自系统启动开始的各项统计信息, ...

  6. Python 使用Qt进行开发(二)

    上次简单实现了显示窗口,下面我们在窗口中加入一些部件. 1,我们在窗口中使用 setToolTip() 方法添加一个文本提示,在窗口中鼠标暂停几秒即可显示该文本信息. class test(): de ...

  7. 【C++进阶:atoi()与itoa()】

    两种函数: atoi 把字符串转为整形: itoa 整形转为字符串: https://www.cnblogs.com/bluestorm/p/3168719.html

  8. eclipse link方式安装插件安装不上

    只能要features和plugins两个文件夹,其他文件需要删除

  9. N个小时学SAP ABAP

    接触SAP已将近3年了,期间ABAP资料也看了不少,都是东看一点.西看一点的,也没做个笔记之类的,很明显效果不是很好.今天突然间领悟到了一点:不能再这样漫无目的的学习了,应该一本书一本书的看,否则就太 ...

  10. wpf slider刻度

    TickFrequency:刻度之间的间隔   IsSnapToTickEnabled:是否对齐到刻度   TickPlacement:刻度位置