学会Zynq(23)XADC报警功能与中断使用示例

本文介绍XADC报警功能及中断使用方法,通过设置温度和VCCPAUX的上下限阈值实现报警,并通过中断处理进行提示。展示了XADC在Zynq平台上的具体应用实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上篇中我们简单了解了XADC和其基本使用方法,包括对片内温度和各种电源电压的测量。本文我们将学习XADC的报警功能和中断的使用方法。程序中我们设置温度和VCCPAUX的上、下报警阈值。当超出这个范围时,便进入中断进行报警提示。


SDK程序设计

由于要使用中断系统,我们翻出两个“老伙计”,第14篇中的sys_intr.h和sys_intr.c。将GIC初始化和串口中断初始化分开,这样当设计中有多个中断源时,编写代码会更方便。

user_xadc.h文件的代码如下:

#ifndef SRC_USER_XADC_H_
#define SRC_USER_XADC_H_

#include <stdio.h>
#include "sleep.h"
#include "xil_printf.h"
#include "xadcps.h"       //XADC设备的支持驱动程序
#include "xscugic.h"

#define XADCINTR_ID	  XPAR_XADCPS_INT_ID  //中断ID

int XADC_Init(XAdcPs* XADCMonInst);
int XADC_Inter(XScuGic *Intc, XAdcPs *XAdcPtr, u16 IntrId);
void XADC_Alarm_Init(XAdcPs *XAdcInstPtr);
void XAdcInterruptHandler(void *CallBackRef);

#endif /* SRC_USER_XADC_H_ */

user_xadc.c文件的代码如下,设计XADC的中断初始化函数、中断处理函数和报警设置函数:

#include "user_xadc.h"

//---------------------------------------------------------
//                   XADC初始化函数
//---------------------------------------------------------
int XADC_Init(XAdcPs* XADCMonInst)
{
	int Status;

	/* 初始化XADC */
	XAdcPs_Config *ConfigPtr;
	ConfigPtr = XAdcPs_LookupConfig(XPAR_XADC_WIZ_0_DEVICE_ID);
	if (ConfigPtr == NULL) {
		xil_printf("Can't find XADC device.\r\n");
		return XST_FAILURE;
	}
	Status = XAdcPs_CfgInitialize(XADCMonInst,ConfigPtr,ConfigPtr->BaseAddress);
	if (Status != XST_SUCCESS) {
		xil_printf("XADC Init FAILED!\r\n");
		return XST_FAILURE;
	}

	//XADC自检
	Status = XAdcPs_SelfTest(XADCMonInst);
	if (Status != XST_SUCCESS) {
		xil_printf("XADC selftest FAILED!\r\n");
		return XST_FAILURE;
	}

	XAdcPs_SetSequencerMode(XADCMonInst,XADCPS_SEQ_MODE_SAFE); //默认模式,报警值不启动
	XAdcPs_SetAlarmEnables(XADCMonInst, 0x0);   //禁用所有报警
	XAdcPs_SetSeqInputMode(XADCMonInst, XADCPS_SEQ_MODE_SAFE);  //设置模拟输入模式

	//设置片内温度的报警阈值 <20 | >45
	XAdcPs_SetAlarmThreshold(XADCMonInst, XADCPS_ATR_TEMP_UPPER,XAdcPs_TemperatureToRaw(45));
	XAdcPs_SetAlarmThreshold(XADCMonInst, XADCPS_ATR_TEMP_LOWER,XAdcPs_TemperatureToRaw(20));
	//设置VCCPAUX的报警阈值 <1.55 | >1.79
	XAdcPs_SetAlarmThreshold(XADCMonInst, XADCPS_ATR_VCCPAUX_UPPER,XAdcPs_VoltageToRaw(1.79));
	XAdcPs_SetAlarmThreshold(XADCMonInst, XADCPS_ATR_VCCPAUX_LOWER,XAdcPs_VoltageToRaw(1.55));

	xil_printf("XADC Init SUCCESS!\r\n");
	return XST_SUCCESS;
}

//---------------------------------------------------------
//                   XADC中断初始化函数
//---------------------------------------------------------
int XADC_Inter(XScuGic *Intc, XAdcPs *XAdcPtr, u16 IntrId)
{
	int Status;

	Status = XScuGic_Connect(Intc, IntrId,
					(Xil_InterruptHandler)XAdcInterruptHandler,
					(void *)XAdcPtr);
	if (Status != XST_SUCCESS) {
		return Status;
	}
	XScuGic_Enable(Intc, IntrId);

	return XST_SUCCESS;
}

//---------------------------------------------------------
//                   XADC报警功能设置
//---------------------------------------------------------
void XADC_Alarm_Init(XAdcPs *XAdcInstPtr)
{
	u32 IntrStatus;

	//清除中断状态寄存器中的所有位。
	IntrStatus = XAdcPs_IntrGetStatus(XAdcInstPtr);
	XAdcPs_IntrClear(XAdcInstPtr, IntrStatus);

	//使能片内温度的Alarm 0中断和VCCPAUX的Alarm 5中断
	XAdcPs_IntrEnable(XAdcInstPtr,
		(XADCPS_INTX_ALM5_MASK | XADCPS_INTX_ALM0_MASK));

	//使能对应的报警功能
	XAdcPs_SetAlarmEnables(XAdcInstPtr, (XADCPS_CFR1_ALM_VCCPAUX_MASK
								| XADCPS_CFR1_ALM_TEMP_MASK));
	XAdcPs_SetSequencerMode(XAdcInstPtr, XADCPS_SEQ_MODE_INDEPENDENT);
}

//---------------------------------------------------------
//                   XADC中断处理函数
//---------------------------------------------------------
void XAdcInterruptHandler(void *CallBackRef)
{
	u32 IntrStatusValue;
	XAdcPs *XAdcPtr = (XAdcPs *)CallBackRef;
	u32 TempRawData, VccPAuxRawData;
	float TempData, VccPAuxData;

	// 获取中断状态标志
	IntrStatusValue = XAdcPs_IntrGetStatus(XAdcPtr);

	// Alarm 0中断
	if (IntrStatusValue & XADCPS_INTX_ALM0_MASK) {
		xil_printf("Temp Warning!\r\n");
		TempRawData = XAdcPs_GetAdcData(XAdcPtr, XADCPS_CH_TEMP);
		TempData = XAdcPs_RawToTemperature(TempRawData);
		printf("Raw Temp %lu Real Temp %f \r\n", TempRawData, TempData);
		XAdcPs_IntrDisable(XAdcPtr,XADCPS_INTX_ALM0_MASK); //禁用中断
	}
	// Alarm 5中断
	if (IntrStatusValue & XADCPS_INTX_ALM5_MASK) {
		xil_printf("VccPAUX Warning!\r\n");
		VccPAuxRawData = XAdcPs_GetAdcData(XAdcPtr, XADCPS_CH_VCCPAUX);
		VccPAuxData = XAdcPs_RawToVoltage(VccPAuxRawData);
		printf("Raw VccPAux %lu Real VccPAux %f \r\n", VccPAuxRawData, VccPAuxData);
		XAdcPs_IntrDisable(XAdcPtr,XADCPS_INTX_ALM5_MASK); //禁用中断
	}

	// 清除中断状态标志
	XAdcPs_IntrClear(XAdcPtr, IntrStatusValue);
}

main.c文件的代码如下

//---------------------------------------------------------------
//            Writen by CUIT 刘奇 2019.3.28
//            此程序为XADC报警功能和中断示例
//---------------------------------------------------------------

#include "user_xadc.h"
#include "sys_intr.h"

static XScuGic Intc;  //GIC
static XAdcPs XADCInst;  //XADC

void System_Init(void)
{
	XADC_Init(&XADCInst);
	Init_Intr_System(&Intc);
	Setup_Intr_Exception(&Intc);
	XADC_Inter(&Intc, &XADCInst, XADCINTR_ID);
	XADC_Alarm_Init(&XADCInst);
}

int main()
{
	System_Init();
	while(1);
}

测试结果如下,VCCPAUX报警很快触发。耐心等待一会,当Zynq片内温度超过45℃后,温度报警也触发。
在这里插入图片描述


相关API函数

1.报警阈值设置

在初始化XADC时,使用XAdcPs_SetAlarmThreshold函数设置报警阈值。

void XAdcPs_SetAlarmThreshold(XAdcPs *InstancePtr,u8 AlarmThrReg,u16 Value)

第二个参数是要设置的报警阈值寄存器;第三个参数时要写入的16位阈值。各种报警阈值寄存器的宏定义在xadcps.h文件中。XADC的8个报警中断共有16个报警寄存器,各有一个上阈值和下阈值。
在这里插入图片描述
我这里只设置了温度和VCCPAUX的上、下阈值。设置阈值时借助XAdcPs_VoltageToRaw和XAdcPs_TemperatureToRaw两个“宏定义函数”将普通意义上的电压和温度值转换为寄存器中存储的值。

轻负载情况下,博主测试使用的Zynq7010在刚上电时在40℃以下,工作一段时间后会到达50~60℃之间。二VCCPAUX正常会在1.79V处浮动。我们据此设置阈值,来观察效果。


2.XADC中断初始化

初始化部分使用XScuGic_Connect和XScuGic_Enable函数设置UART中断,和前面的PL中断和定时器中断类似,不再详述。XADC中断也是一种SPI,查看第7篇中的表格。
在这里插入图片描述
其中断号为39,在头文件中宏定义。


3.报警功能设置

这部分包括两步:使能对应的中断(XAdcPs_IntrEnable函数)和设置对应的报警功能(XAdcPs_SetAlarmEnables函数)。XADC共支持8种不同的中断Alarm0~6和过温中断(过温用XAdcPs_SetOverTemp函数设置,而不是XAdcPs_SetAlarmThreshold函数)。

下表给出了各种中断宏定义(XAdcPs_IntrEnable使用的参数)和报警宏定义(XAdcPs_SetAlarmEnables使用的参数)之间的对应关系。

中断宏定义报警宏定义中断
XADCPS_CFR1_ALM_TEMP_MASKXADCPS_INTX_ALM0_MASKAlarm0-温度
XADCPS_CFR1_ALM_VCCINT_MASKXADCPS_INTX_ALM1_MASKAlarm1-VCCINT
XADCPS_CFR1_ALM_VCCAUX_MASKXADCPS_INTX_ALM2_MASKAlarm2-VCCAUX
XADCPS_CFR1_ALM_VBRAM_MASKXADCPS_INTX_ALM3_MASKAlarm3-VBRAM
XADCPS_CFR1_ALM_VCCPINT_MASKXADCPS_INTX_ALM4_MASKAlarm4-VCCPINT
XADCPS_CFR1_ALM_VCCPAUX_MASKXADCPS_INTX_ALM5_MASKAlarm5-VCCPAUX
XADCPS_CFR1_ALM_VCCPDRO_MASKXADCPS_INTX_ALM6_MASKAlarm6-VCCPDRO
XADCPS_CFR1_OT_MASKXADCPS_INTX_OT_MASK过温

我们这里只使用自定义温度和VCCPAUX,因此只设置Alarm0和Alarm5。


4.中断处理函数

中断处理函数的大致流程如下:

  1. 获取中断状态标志,检查触发的是哪种中断;
  2. 根据不同的中断类型,执行不同的操作,Alarm0中断则温度报警,Alarm5则VCCPAUX报警;
  3. 清除中断标志状态;

为防止超出设定的阈值后就无限进入中断,检测到一次报警便使用XAdcPs_IntrDisable函数禁用掉该中断。

但我发现当禁用了VCCPAUX中断后,虽然不会无限进入了,但是触发了温度中断后,还会再次打印出VCCPAUX的值。这说明应该是VCCPAUX超出阈值后,Alarm5仍会置位对应的中断标志位,只不过不会进入中断状态了。博主一般不会太仔细研究底层的寄存器功能结构,如果你知道背后的工作机制,一定要留言告诉我。


总结

本文介绍了XADC的报警功能和中断使用示例。本文以两种报警中断为例,使用其它XADC中断时方法类似,很容易修改。

在Vivado中使用XADC Wizard(Xilinx Analog-to-Digital Converter Wizard)是设计中实现对模拟信号进行采集和监测的重要步骤。XADC Wizard是Xilinx提供的一个IP核配置工具,用于生成XADC的硬件描述和相关接口逻辑。 ### 使用XADC Wizard的步骤 1. **打开Vivado并创建工程** 启动Vivado Design Suite并创建一个新的工程,选择对应的目标器件(例如Artix-7、Kintex-7或UltraScale系列)。 2. **添加IP核** 在Block Design界面中,点击“Add IP”按钮,在IP目录中搜索“XADC Wizard”,然后将其添加到设计中。 3. **配置XADC Wizard参数** 双击添加的XADC Wizard IP核,进入配置界面。主要配置选项包括: - **通道选择**:可以选择使用片上传感器(温度、电压、电流)或外部模拟输入通道。 - **采样率设置**:XADC的ADC采样率可以设置为1 MSPS(百万样本每秒)或更低,具体取决于设计需求。 - **接口模式**:可以选择使用AXI Lite接口进行寄存器配置和状态读取,或者使用独立的DRP(Dynamic Reconfiguration Port)接口。 - **中断报警功能**:可以启用过温或过压报警功能,用于触发中断或外部响应机制。 4. **生成IP核并连接接口** 完成配置后,点击“Generate”生成IP核。生成后,XADC Wizard会自动将必要的接口信号添加到Block Design中,包括时钟、复位、AXI Lite接口等。需要将这些信号正确连接到处理器(如Zynq或MicroBlaze)或其他控制逻辑。 5. **综合实现** 完成Block Design后,进行综合、实现并生成比特流文件。最后将设计下载到FPGA硬件中进行验证。 ### XADC的典型应用场景 - **片上温度监测**:通过XADC内置的温度传感器,可以实时监测FPGA芯片的温度变化,用于热管理或系统保护。 - **供电电压监测**:XADC内置的电压传感器可以检测芯片内部供电电压,确保系统在安全范围内运行。 - **外部模拟信号采集**:通过多路复用器,XADC可以对多个外部模拟信号进行采样,适用于传感器数据采集系统。 ### 示例代码:读取XADC寄存器值(AXI Lite接口) 以下是一个简单的AXI Lite接口读取XADC寄存器值的示例代码,假设XADC的AXI Lite接口已经连接到MicroBlaze软核处理器: ```c #include "xil_io.h" #define XADC_BASE_ADDR 0x40000000 // 假设XADC AXI Lite接口的基地址为0x40000000 u32 read_xadc_register(int reg_offset) { return Xil_In32(XADC_BASE_ADDR + reg_offset); } int main() { u32 temperature = read_xadc_register(0x200); // 读取温度寄存器值 u32 vccint = read_xadc_register(0x204); // 读取VCCINT寄存器值 u32 vccaux = read_xadc_register(0x208); // 读取VCCAux寄存器值 // 打印结果 xil_printf("Temperature: 0x%x\r\n", temperature); xil_printf("VCCINT: 0x%x\r\n", vccint); xil_printf("VCCAux: 0x%x\r\n", vccaux); return 0; } ``` ### 相关文档参考资料 XADC Wizard的详细使用说明可以在Xilinx官方文档中找到,尤其是《Xilinx Analog-to-Digital Converter (XADC) User Guide》(文档编号UG480)中详细描述了XADC的寄存器配置、接口协议和使用示例[^1]。此外,《Vivado Design Suite User Guide: Using IP in Your Design》(文档编号UG994)也提供了关于如何在Vivado中使用IP核的通用指南。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值