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. ArrayList的contains()和HashSet的contains()效率比较

    ArrayList的contains(Object o)方法内部只有一行代码:判断indexOf(0)是否大于等于0.而indexOf(o)内部会从头遍历数组,直到某位置的元素等于o,极端情况下,要把 ...

  2. luogu P1063 能量项链 x

    P1063 能量项链 题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子, ...

  3. sh_12_转义字符

    sh_12_转义字符 # \t 在控制台输出一个 制表符,协助在输出文本时 垂直方向 保持对齐 print("1\t2\t3") print("10\t20\t30&qu ...

  4. 【转】django rest framework ModelSerializer 、serializers小结

    转自:https://blog.csdn.net/l_vip/article/details/79156113 引言 serializers是什么?官网是这样的”Serializers allow c ...

  5. Java课堂动手动脑

    1.使用Files. walkFileTree()找出指定文件夹下所有大于指定大小(比如1M)的文件: 代码: package test; import java.io.IOException; im ...

  6. cin.clear()、cin.sync()

    看机器学习时,发现之前学的C++代码忘了,cin.clear().cin.sync() cin.clear():将流中的所有状态值都重设为有效值 cin.sync():清空流 这个很有意思,如果没有c ...

  7. 【Python】学习笔记九:面向对象拓展

    调用类的其他信息 在定义方法的时候,必须有self这一参数.这个参数表示某个对象,对象拥有类的所有性质.那么我们可以通过self,调用类属性 class people(object): action ...

  8. Yii2.0简单隐藏index.php文件和模块配置和layout布局配置禁用和日志写入配置

    隐藏index.php文件 目的:想去掉浏览器地址栏中的 index.php?r= 这一块. 在/config/web.php中   ’components'=>[]   中添加如下代码: 'u ...

  9. Python的datetime与Decimal数据进行json序列化的简单说明

    我们在Python的json.JSONEncoder类中可以查看Python数据序列化为JSON格式的数据时数据类型的对应关系: class JSONEncoder(object): "&q ...

  10. Lombok 注解简介

    Lombok @AllArgsConstructor /** * 生成一个包含所有属性的构造函数 */ @Target(ElementType.TYPE) @Retention(RetentionPo ...