XADC 简介
ZYNQ SoC 的 XADC 模块包括两个 12 位的模数转换器,转换速率可以达到 1MSPS(每秒一百万次采样)。它带有片上温度和电压传感器,可以测量芯片工作时的温度和供电电压。
在 7 系列的 FPGA 中,XADC 提供了 JTAG 和 DRP(dynamic reconfiguration port)接口,用于访问其内部的状态和控制寄存器。在 ZYNQ-7000 SoC 器件中,XADC 增加了一个 PS-XADC 接口,用于 PS 中的软件控制 XADC 模块。
XADC 模块的系统框图如下所示:
在图中 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 接口之间进行仲裁。
XADC 实验
- 开发工具:Vivado2017.4
- 验证平台:黑金ZYNQ7035
硬件设计
XADC 为硬核模块,不需要对 PL 进行配置。PS 端只需完成 UART、DDR 等基础配置就可以。
软件设计
本实验通过 PS-XADC 接口实现,创建基础 SDK 工程即可,添加源代码:
- xadc.h
/** * Copyright (c) 2022-2023,HelloAlpha * * Change Logs: * Date Author Notes */ #ifndef __XADC_H__ #define __XADC_H__ #define USING_XADC #ifdef USING_XADC #include "xparameters.h" #include "xadcps.h" #define XADC_DEVICE_ID XPAR_XADCPS_0_DEVICE_ID struct Xadc_Data { float temp; // Temperature float vccint; // PL kernel voltage float vccaux; // PL auxiliary voltage float vccbram; // PL BRAM voltage float vccpint; // PS kernel voltage float vccpaux; // PS auxiliary voltage float vccpdro; // PS DDR voltage uint16_t raw_temp; uint16_t raw_vccint; uint16_t raw_vccaux; uint16_t raw_vccbram; uint16_t raw_vccpint; uint16_t raw_vccpaux; uint16_t raw_vccpdro; }; typedef struct Xadc_Data XadcData_t; int XadcPs_Init(XAdcPs *XadcInstancePtr, uint16_t DeviceId); void XadcPs_GetData(XAdcPs *XadcInstancePtr, XadcData_t *XadcData); #endif #endif
- xadc.c
/** * Copyright (c) 2022-2023,HelloAlpha * * Change Logs: * Date Author Notes */ #include "xadc.h" #ifdef USING_XADC int XadcPs_Init(XAdcPs *XadcInstancePtr, uint16_t DeviceId) { int Status; XAdcPs_Config *XadcConfigPtr; XadcConfigPtr = XAdcPs_LookupConfig(DeviceId); if (NULL == XadcConfigPtr) { return XST_FAILURE; } Status = XAdcPs_CfgInitialize(XadcInstancePtr, XadcConfigPtr, XadcConfigPtr->BaseAddress); if (Status != XST_SUCCESS) { return XST_FAILURE; } XAdcPs_SetSequencerMode(XadcInstancePtr, XADCPS_SEQ_MODE_SAFE); return Status; } void XadcPs_GetData(XAdcPs *XadcInstancePtr, XadcData_t *XadcData) { XadcData->raw_temp = XAdcPs_GetAdcData(XadcInstancePtr, XADCPS_CH_TEMP); XadcData->temp = XAdcPs_RawToTemperature(XadcData->raw_temp); XadcData->raw_vccint = XAdcPs_GetAdcData(XadcInstancePtr, XADCPS_CH_VCCINT); XadcData->vccint = XAdcPs_RawToVoltage(XadcData->raw_vccint); XadcData->raw_vccaux = XAdcPs_GetAdcData(XadcInstancePtr, XADCPS_CH_VCCAUX); XadcData->vccaux = XAdcPs_RawToVoltage(XadcData->raw_vccaux); XadcData->raw_vccbram = XAdcPs_GetAdcData(XadcInstancePtr, XADCPS_CH_VBRAM); XadcData->vccbram = XAdcPs_RawToVoltage(XadcData->raw_vccbram); XadcData->raw_vccpint = XAdcPs_GetAdcData(XadcInstancePtr, XADCPS_CH_VCCPINT); XadcData->vccpint = XAdcPs_RawToVoltage(XadcData->raw_vccpint); XadcData->raw_vccpaux = XAdcPs_GetAdcData(XadcInstancePtr, XADCPS_CH_VCCPAUX); XadcData->vccpaux = XAdcPs_RawToVoltage(XadcData->raw_vccpaux); XadcData->raw_vccpdro = XAdcPs_GetAdcData(XadcInstancePtr, XADCPS_CH_VCCPDRO); XadcData->vccpdro = XAdcPs_RawToVoltage(XadcData->raw_vccpdro); } #endif
- app_xadc.c
/** * Copyright (c) 2022-2023,HelloAlpha * * Change Logs: * Date Author Notes */ #include "xadc.h" #ifdef USING_XADC #include "stdio.h" #define kprintf printf /** * xil_printf does not support printing floating point numbers */ static XAdcPs Xadc; static XadcData_t xadc_data; int xadc_read_data(void) { XadcPs_GetData(&Xadc, &xadc_data); kprintf("On Chip Temperature: %f C \r\n", xadc_data.temp); kprintf("PL Kernel Voltage: %f V \r\n", xadc_data.vccint); kprintf("PL Auxiliary Voltage: %f V \r\n", xadc_data.vccaux); kprintf("PL BRAM Voltage: %f V \r\n", xadc_data.vccbram); kprintf("PS Kernel Voltage: %f V \r\n", xadc_data.vccpint); kprintf("PS Auxiliary Voltage: %f V \r\n", xadc_data.vccpaux); kprintf("PS DDR Voltage: %f V \r\n", xadc_data.vccpdro); return 0; } int app_xadc_init(void) { int Status = XST_SUCCESS; Status = XadcPs_Init(&Xadc, XADC_DEVICE_ID); if (Status != XST_SUCCESS) { return XST_FAILURE; } return Status; } #endif
主函数种首先调用 app_xadc_init()
对 XADC 初始化,需要读取时调用 xadc_read_data()
即可。
实验现象
参考资料
- UG585
- 正点原子 ZYNQ 领航者
- 黑金 ZYNQ7035
更多内容
- CSDN博客:@Hello阿尔法
- 哔哩哔哩:@Hello阿尔法
- 知乎:@Hello阿尔法
- 更多 ZYNQ 相关源码也可以在这里 Github ZYNQ-SPACE 找到。