ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

FPGA内部温度读取实战:XADC IP核与DRP接口详解

FPGA内部温度读取实战:XADC IP核与DRP接口详解 1. 为什么我要折腾FPGA内部温度读取这件事做FPGA开发的朋友大概率都遇到过这样一个场景板子跑了一段时间摸上去有点烫手但又不确定芯片结温到底到了多少度。尤其是7系列FPGA在高速收发器、DSP密集运算或者大功率逻辑同时翻转的时候结温上升非常快。如果散热设计不到位轻则时序违例、逻辑跑飞重则芯片直接降频甚至永久损伤。我以前做的一个图像处理项目板子塞在密闭机箱里夏天连续跑两个小时之后开始随机出错排查了半天才发现是结温超过了85°C触发了内部保护逻辑。那有没有办法在不外挂温度传感器的前提下直接读到FPGA芯片内部的真实温度答案是有的而且Xilinx 7系列及以后的FPGA内部都集成了一个叫做XADC的模块。XADC全称是Xilinx Analog-to-Digital Converter它是一个硬核IP独立于FPGA逻辑资源运行可以采集芯片内部的温度传感器、供电电压以及外部模拟输入通道。你不需要额外买任何器件只要在Vivado里把XADC IP核例化进去就能通过DRP接口把温度值读出来。这篇文章面向的是已经能跑通基本Vivado工程、对FPGA开发流程有初步了解的读者。不管你是刚入门想找个练手项目还是已经在做实际产品需要监控板卡健康状态XADC都是一个性价比极高的切入点。我会从IP核配置开始一步步讲到DRP接口的时序细节把每个参数为什么这么设、每个信号为什么这么接都讲清楚。读完你至少能拿到两样东西一个能直接跑的温度读取工程以及对DRP动态重配置接口的完整理解。2. XADC IP核的整体设计与选型思路2.1 为什么选XADC而不是外挂传感器先说选型逻辑。外挂一颗I2C温度传感器比如TMP102或者LM75成本也就几块钱精度也不错为什么要用内部XADC原因有三个。第一是位置优势。外挂传感器测的是PCB板面温度不是芯片结温。芯片结温通常比板面温度高10到20度尤其在小封装高功耗场景下差距更大。XADC测的是芯片内部温度传感器的值直接反映结温这对散热评估和热保护逻辑来说才是真正有意义的数据。第二是零额外硬件成本。XADC是FPGA内部的硬核不占用逻辑资源不需要额外的PCB面积和布线。对于已经量产或者空间受限的板卡来说这个优势非常明显。第三是响应速度。XADC的温度采样率可以配置最高能到每秒百万次采样级别远快于大多数外挂传感器的几十毫秒转换周期。做实时热保护的时候响应速度直接决定了你能不能及时降频或者关断。当然XADC也有局限。它的绝对精度大概在正负4度左右不如高精度外挂传感器。但如果你只是做温度趋势监控和过温保护这个精度完全够用。2.2 XADC的两种访问方式DRP和JTAGXADC的数据读取有两条路。一条是通过JTAG用Vivado自带的硬件管理器直接看温度波形不需要写任何逻辑代码。这种方式适合调试阶段快速验证但没法在产品里做自动化监控。另一条路就是DRPDynamic Reconfiguration Port动态重配置端口。你可以把它理解成XADC硬核对外暴露的一组寄存器读写接口FPGA逻辑通过这套接口去读XADC内部的状态寄存器和结果寄存器。DRP的好处是完全由逻辑控制你可以把读到的温度值送进状态机做判断、送进UART打印、送进DDR缓存做日志灵活性极高。这篇文章重点讲DRP方式因为这才是实际产品里真正用得上的方案。JTAG方式我会在调试技巧里顺带提一下。2.3 XADC IP核的配置策略在Vivado里例化XADC IP核的时候配置界面有几个关键选项需要想清楚。通道选择XADC有一个专用的温度传感器通道和一个专用的供电电压通道这两个是内部连接好的。另外还有16个外部模拟输入通道VP/VN和VAUXP/VAUXN如果你只做温度读取外部通道全部关掉减少不必要的逻辑。采样模式XADC支持单通道连续采样、多通道轮询采样、以及事件触发采样。只读温度的话选单通道连续采样就行这样温度寄存器会持续更新你随时读都是最新值。DRP时钟DRP接口需要一个独立的时钟频率范围是1MHz到50MHz。这个时钟跟你的系统时钟是分开的因为XADC硬核有自己的工作时钟域。我一般用25MHz不高不低时序好收敛。报警阈值XADC支持配置温度上下限报警。超过上限或者低于下限的时候ALM信号会拉高。这个功能做热保护非常方便你可以把ALM直接接到逻辑里触发降频或者风扇控制。校准XADC出厂时已经做过校准但如果你对精度要求高可以在配置里使能自动校准功能。校准需要一点时间但只在上电初始化阶段执行一次。3. DRP接口时序详解与核心信号解析3.1 DRP接口的信号组成DRP接口的信号不多但每一个都有明确的时序要求。先把信号列出来信号名方向位宽说明dclk输入1DRP时钟1-50MHzden输入1数据使能高有效dwe输入1写使能1为写0为读daddr输入7寄存器地址di输入16写数据do输出16读数据drdy输出1数据就绪高有效看起来很简单对吧但实际用的时候时序配合才是关键。很多人第一次用DRP读出来的数据不对十有八九是没搞清楚drdy和den之间的握手关系。3.2 DRP读操作的完整时序DRP读操作的时序可以拆成三个阶段。第一阶段发起请求。在dclk的上升沿你把den拉高dwe拉低daddr放上你要读的寄存器地址。注意den只需要拉高一个dclk周期不需要一直保持。XADC在检测到den为高的那个上升沿就会锁存地址和读写方向。第二阶段等待就绪。XADC收到请求后需要几个时钟周期去取数据。这段时间drdy是低的。你需要一个状态机在den拉高之后进入等待状态一直等到drdy拉高。第三阶段读取数据。drdy拉高的那个dclk周期do端口上就是有效的读数据。你需要在drdy为高的上升沿把do锁存进自己的寄存器。drdy也只会高一个周期错过就得重新发起请求。这里有个容易踩的坑den拉高之后不能马上又拉高。XADC处理一次请求需要时间如果你在drdy还没拉高之前又发起新的请求XADC会忽略掉或者返回错误数据。所以状态机必须严格等待drdy。3.3 DRP写操作的时序差异写操作和读操作的区别在于dwe拉高同时di端口上要放好写数据。写操作的drdy同样会在写完成之后拉高一个周期表示写入成功。但写操作在实际项目里用得少因为XADC的配置寄存器大部分在IP核配置阶段就设好了运行时很少需要动态改。温度读取只需要读操作。3.4 关键寄存器的地址和含义XADC内部有一组寄存器通过DRP地址访问。温度相关的寄存器主要有这几个地址十六进制名称说明0x00温度结果寄存器高12位有效单位是°C0x01供电电压结果VCCINT电压值0x40温度上限阈值超过此值ALM拉高0x41温度下限阈值低于此值ALM拉高0x42温度报警使能控制哪些通道触发ALM温度结果寄存器的数据格式需要特别注意。它是一个12位的二进制补码高12位有效低4位是0。换算公式是温度值°C 寄存器值 / 16比如你读到的寄存器值是0x0A50十进制是26402640/16165但这是原始值。实际上XADC温度寄存器的格式是高12位是有符号数单位是1/16°C。所以你需要先把低4位去掉然后判断符号位再做除法。更准确的换算方式是把读到的16位数据右移4位得到一个12位有符号数然后乘以0.0625就是摄氏度。比如右移后得到0x0A5十进制165165*0.062510.3125°C。这个温度明显偏低说明芯片刚上电还没热起来。4. 手把手实操从IP核配置到温度读取的完整流程4.1 Vivado工程创建与IP核例化打开Vivado新建一个工程选好你的FPGA型号。我手头用的是XC7A35T属于Artix-7系列XADC的用法在7系列里是通用的。在Flow Navigator里点IP Catalog搜索XADC找到XADC Wizard。双击打开配置界面。第一页是Basic Configuration。Interface Selection选DRP因为我们要用逻辑读。Startup Channel Selection选Single Channel然后在下拉里选Temperature。这样XADC上电后就只采温度通道其他通道不采减少干扰。第二页是ADC Setup。Acquisition Time和Conversion Time保持默认就行这些是模拟前端的时序参数默认值已经针对内部温度传感器优化过了。DRP Clock Frequency填25单位是MHz。这个频率决定了DRP接口的时序节奏。第三页是Alarm Setup。把Temperature Upper Alarm的阈值设成85Lower Alarm设成-40。这样结温超过85度或者低于零下40度的时候ALM信号会拉高。这两个值你可以根据实际芯片的工业级或商业级温度范围来调整。第四页是Channel Setup。只保留Temperature通道其他全部Disable。这样IP核占用的资源最少。配置完点OK生成IP核。Vivado会自动生成例化模板和相关的约束文件。4.2 顶层模块设计与DRP状态机实现接下来写顶层模块。核心是一个DRP读状态机我把它拆成四个状态IDLE、REQUEST、WAIT_DRDY、CAPTURE。module xadc_temp_reader( input wire clk, // 系统时钟 50MHz input wire rst_n, // 低电平复位 output wire [11:0] temp_raw, // 原始温度值 output wire [15:0] temp_celsius_x16 // 温度值单位1/16°C ); // DRP接口信号 wire dclk; wire den; wire dwe; wire [6:0] daddr; wire [15:0] di; wire [15:0] do; wire drdy; // 状态机定义 localparam S_IDLE 2d0; localparam S_REQUEST 2d1; localparam S_WAIT_DRDY 2d2; localparam S_CAPTURE 2d3; reg [1:0] state, next_state; reg den_reg; reg [6:0] daddr_reg; reg [15:0] temp_reg; // 分频产生25MHz DRP时钟 reg [1:0] clk_div; always (posedge clk or negedge rst_n) begin if (!rst_n) clk_div 2d0; else clk_div clk_div 1b1; end assign dclk clk_div[1]; // 状态机 always (posedge dclk or negedge rst_n) begin if (!rst_n) state S_IDLE; else state next_state; end always (*) begin next_state state; case (state) S_IDLE: next_state S_REQUEST; S_REQUEST: next_state S_WAIT_DRDY; S_WAIT_DRDY: if (drdy) next_state S_CAPTURE; S_CAPTURE: next_state S_IDLE; default: next_state S_IDLE; endcase end // 输出逻辑 always (posedge dclk or negedge rst_n) begin if (!rst_n) begin den_reg 1b0; daddr_reg 7h00; temp_reg 16h0000; end else begin case (state) S_IDLE: begin den_reg 1b0; daddr_reg 7h00; // 温度结果寄存器地址 end S_REQUEST: begin den_reg 1b1; daddr_reg 7h00; end S_WAIT_DRDY: begin den_reg 1b0; end S_CAPTURE: begin temp_reg do; end endcase end end assign den den_reg; assign dwe 1b0; // 只读 assign daddr daddr_reg; assign di 16h0000; // 温度换算右移4位得到12位有符号数 assign temp_raw temp_reg[15:4]; assign temp_celsius_x16 temp_reg; // 例化XADC IP核 xadc_wiz_0 u_xadc ( .dclk (dclk), .den (den), .dwe (dwe), .daddr (daddr), .di (di), .do (do), .drdy (drdy), .vp_in (1b0), .vn_in (1b0), .vauxp (16h0000), .vauxn (16hFFFF), .alarm (), .busy (), .channel (), .eoc (), .ot () ); endmodule这段代码的核心就是那个四状态状态机。IDLE状态准备地址REQUEST状态拉高den一个周期WAIT_DRDY状态等drdyCAPTURE状态锁存数据。整个循环不断重复温度寄存器就会持续更新。4.3 温度数据的换算与验证读到的temp_reg是16位原始数据。换算成摄氏度有两种方式。方式一直接右移4位得到12位有符号数然后乘以0.0625。在Verilog里可以这样写wire signed [11:0] temp_signed temp_reg[15:4]; wire signed [15:0] temp_celsius temp_signed * 16sd4; // 乘以4再除以64等效于乘以0.0625方式二用Vivado自带的浮点IP核做换算但那样太浪费资源。对于温度监控来说定点数完全够用。验证的时候你可以先把板子放在室温下跑读到的温度应该在25到35度之间。然后用手按住芯片表面温度会慢慢上升。如果读到的值一直是0或者一直是某个固定值不变说明DRP时序有问题重点检查drdy有没有正常拉高。4.4 上板实测与ILA抓波形代码综合实现之后生成比特流下载到板子上。用Vivado的ILA集成逻辑分析仪抓DRP接口的波形这是排查时序问题最直接的手段。在ILA里把dclk、den、drdy、do、daddr这几个信号加进去触发条件设成den的上升沿。抓到的波形应该长这样den拉高一个周期然后drdy在几个周期后拉高一个周期do上出现有效数据。如果drdy一直不拉高检查dclk是不是真的在翻转以及XADC IP核的复位有没有正确释放。我实测下来从den拉高到drdy拉高间隔大概是5到8个dclk周期。这个延迟是XADC内部逻辑决定的不同型号可能略有差异但不会差太多。5. 常见问题排查与避坑经验实录5.1 读到的温度值明显不对怎么办这是最常见的问题。温度值要么是0要么是负数要么是一个很大的数。排查思路按以下顺序来。第一步确认drdy有没有拉高。如果drdy从来没高过说明XADC根本没响应你的请求。检查dclk频率是不是在1到50MHz范围内检查XADC IP核的复位信号是不是一直有效。第二步确认daddr对不对。温度结果寄存器的地址是0x00但有些版本的IP核地址映射可能不同。在Vivado的IP核文档里查一下Address Map确认地址没错。第三步确认数据格式。温度寄存器的高12位有效低4位是保留位。如果你直接把16位数据当温度值用读出来会大16倍。比如实际25度你读到400那就是没做右移。第四步确认符号位。12位有符号数的最高位是符号位。如果温度是负的比如零下10度原始值是0xFF60右移4位得到0xFF6这是补码形式的-10。你需要做符号扩展才能得到正确的负温度。5.2 DRP时序不稳定的排查方法有时候温度能读出来但偶尔会跳变或者读到错误值。这种情况通常是时序余量不够。首先检查dclk和系统时钟的相位关系。如果dclk是从系统时钟分频来的确保分频逻辑不会产生毛刺。我一般用计数器分频不用组合逻辑分频。其次检查den的脉宽。den必须至少保持一个dclk周期不能更短。如果你的状态机跑在系统时钟域而dclk是分频出来的要确保den在dclk域里被正确同步。还有一个容易忽略的点XADC IP核的复位。XADC上电后需要一段时间初始化这段时间内DRP接口是不响应的。确保复位信号至少保持100个dclk周期等XADC完全就绪后再发起第一次读请求。5.3 温度跳变和滤波处理XADC读到的温度值会有小幅跳变这是正常的因为模拟前端有噪声。如果你需要平滑的温度曲线可以在逻辑里加一个滑动平均滤波器。比如连续读8次取平均值输出。这样温度曲线会平滑很多但响应速度会慢一点。做热保护的时候我一般用滑动平均加阈值判断既避免误触发又能及时响应真实的温度上升。5.4 常见问题速查表现象可能原因解决方法温度始终为0drdy未拉高检查dclk和复位温度值偏大16倍未右移4位对temp_reg做右移温度值为负数但实际不冷符号位处理错误做12位有符号数符号扩展温度偶尔跳变时序余量不足降低dclk频率或加滤波器ALM信号不触发阈值未配置检查IP核Alarm Setup综合报错DRC RTSTAT-2时钟约束缺失给dclk加create_clock约束5.5 几个我踩过的坑第一个坑是忘了给dclk加时序约束。Vivado在实现的时候会报DRC RTSTAT-2错误说时钟没有约束。解决办法是在XDC文件里加一行create_clock -period 40.000 -name dclk [get_ports dclk]。40ns对应25MHz。第二个坑是把XADC的复位和系统复位接在一起。系统复位可能很短但XADC需要更长的初始化时间。我后来单独做了一个复位计数器系统复位释放后再等100个dclk周期才释放XADC复位。第三个坑是用JTAG看温度的时候忘了切换通道。Vivado硬件管理器里默认显示的是供电电压需要在XADC面板里手动切到Temperature。这个不算逻辑问题但第一次用的时候容易懵。6. 进阶扩展把温度监控做成产品级功能6.1 多通道轮询与自动监控只读温度只是XADC的冰山一角。你可以配置XADC轮询多个通道同时监控温度、VCCINT、VCCAUX和外部模拟输入。轮询模式下XADC会自动按顺序采集各个通道你只需要按顺序读结果寄存器就行。这样一套逻辑就能把板卡的所有健康指标都监控起来。6.2 温度日志与上位机通信读到的温度值可以通过UART或者以太网送到上位机做成实时温度曲线。我在一个项目里用UART每秒钟发一次温度值上位机用Python脚本接收并画图连续跑了72小时做老化测试非常稳定。UART的波特率用115200就够了温度数据量很小。6.3 基于温度的自适应散热控制把温度值和PWM风扇控制结合起来温度低的时候风扇低速转温度高的时候风扇全速。这样既能保证散热又能降低噪声。实现方式是用温度值查表得到一个PWM占空比然后输出到风扇控制引脚。XADC的ALM信号也可以直接用来触发紧急降频响应速度比软件轮询快得多。6.4 温度补偿与时序余量分析FPGA的时序余量会随温度变化。高温下晶体管开关速度变慢建立时间和保持时间的余量都会缩小。如果你在做高速接口可以把XADC读到的温度值送到时序分析逻辑里动态调整IDELAY或者PLL的相位做温度补偿。这个用法比较进阶但在高速收发器场景下很有价值。6.5 关于XADC精度的一点实测数据我在室温25度的环境下用XC7A35T跑了连续1000次温度采样读到的值在26到28度之间波动平均27.2度。用外挂的TMP102测板面温度是24.5度。结温比板面高2.7度这个差距在合理范围内。当我把芯片跑满负载十分钟后XADC读到62度TMP102读到51度差距拉大到11度。这正好说明结温和板面温度的差距会随功耗增加而增大用XADC做热保护比外挂传感器更准确。最后再分享一个小技巧如果你只是想在调试阶段快速看温度不需要写任何逻辑代码直接在Vivado硬件管理器里打开XADC面板就行。但如果你要做产品级的温度监控DRP接口是唯一的选择。把状态机写对时序约束加好剩下的就是调参数和加滤波了。
返回列表