} XAdcPs_Config;
//定义结构体XAdcPs_Config,结构体包含两个内容,一个是设备id,另一个是设备的基本地址
typedef struct {
XAdcPs_Config Config; /**< XAdcPs_Config of current device */
u32 IsReady; /**< Device is initialized andready */
} 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 FAILEDnr");
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 setFIFO 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 commuincationchannel between XADC and PS,If set,the PS-XADC will remain in reset until a 0is written to this bit */
XAdcPs_WriteReg((InstancePtr)->Config.BaseAddress,
XADCPS_MCTL_OFFSET,0x00);
/*
* Indicate the instance is now ready to useand
* 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 FAILEDnr");
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 andrelease 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 itsdefault state
*/
XAdcPs_Reset(InstancePtr);
/*
* Write a value into the Alarm Thresholdregisters, 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 theConfiguration 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));