尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

FPGA内置XADC实现多路电源监测:Vivado配置与Verilog实战

发布时间:2026/9/27 1:18:13

资讯中心
01
ARTICLE

FPGA内置XADC实现多路电源监测:Vivado配置与Verilog实战

FPGA内置XADC实现多路电源监测:Vivado配置与Verilog实战
做嵌入式或者FPGA开发的同学肯定都遇到过这个场景板卡好不容易跑起来了结果某个模块死活不工作查了半天发现是某路电源电压不对。更麻烦的是如果板子上有十几路电源总不能用万用表一路一路戳万一碰到旁边的芯片引脚造成短路那损失就大了。我在调试带Zynq和Kintex的板卡时就常想要是FPGA自己能实时告诉我每一路电源的电压值就好了。其实完全可行Xilinx FPGA内部集成的XADC模块天生就是为了干这个的配合Vivado里的XADC Wizard IP核它能用12位分辨率同时监测多路外部电压、内部核心电压和芯片温度。这篇实战记录我就把完整的配置流程、Verilog读写逻辑、以及我把整个项目跑通后总结的调试经验全部整理出来给后面要做的朋友排排坑。这篇内容适合正在用7系列或者UltraScale系列FPGA、需要在Vivado里完成板级电源监测、温度监控或者想搞懂XADC内部机理的开发者。我的方案用的是7系列Zynq代码逻辑在纯FPGA工程里也同样适用。为了照顾不同基础我会先从XADC的结构讲起再做IP配置最后给工程代码和排查技巧即使你之前完全没用过XADC这篇也能让你顺利上手。1. 为什么用XADC做电源监测而不是外挂ADC芯片很多朋友第一反应是FPGA外面接一个ADC芯片不就行了吗用I2C或者SPI去读又不是什么难事。这个想法没问题但如果从系统设计的角度看XADC有它不可替代的优势也正是这些优势让它在多数板级电源监测场景里成为首选。1.1 XADC的硬核底子12位SAR ADC加片上传感器XADC模块是内嵌在7系列及UltraScale系列FPGA内部的一个硬核由两个12位、采样率最高1MSPS的SAR型ADC组成这个双ADC结构很有意思它可以支持两路信号同步采样在需要同时比较电压和电流或者两路输入相位关系的场景里非常有用。XADC内部还有一个多路复用器可以切换接入不同的模拟输入通道。7系列FPGA的XADC可用的输入通道大概分两类一类是专用模拟输入引脚VP/VN这一类是差分输入精度和稳定性最好通常用来接关键电压另一类就是辅助模拟输入通道VAUXP[0..15]/VAUXN[0..15]一共16对差分通道这一组是FPGA普通IO复用的需要在约束文件里显式声明灵活性很高。我在做多路电源监测时就是把这些辅助通道当作多路电压表的输入口一路一路测过去。1.2 内部监控通道对调试有多方便除了外部模拟通道XADC还自带一组内部监控通道可以测量当前的FPGA芯片温度、VCCINT内部核心电压、VCCAUX辅助电压、VCCBRAM块RAM供电电压等。不要小看这几个内部指标在调试系统稳定性的时候它们能帮你快速定位是不是供电不足或者芯片过热。比如说之前我遇到过一次FPGA逻辑运行一段时间后随机出错的问题用外部仪器怎么抓都抓不到后来就是靠XADC的温度数据发现核心温度快到90度了散热片贴合有问题这才找到根因。1.3 和外挂ADC对比省下的成本远超想象用外置ADC不是不行但它意味着硬件上要加芯片、加参考电压源、加信号调理电路PCB布局要多占面积软件上还要自己写通信协议如果选用带SPI接口的ADCFPGA里还得写一套SPI从机逻辑。一套下来少说一两天工作量。而XADC是FPGA内部自带的做设计时只要配置好IP核用AXI4-Lite或者DRP接口去读数据几乎不占什么额外资源。精度上12位ADC对大多数板级电源监测完全够用了外置ADC若是要精度更高成本也上去了。衡量一下系统里电源轨数量多时外置ADC芯片成本和PCB面积直线上升而XADC几乎零成本。而且XADC数据可以直接进逻辑做运算、触发告警、驱动风扇控制这在电源管理上非常灵活。这才是它真正的价值所在它不是一个被动的传感器而是能和你的控制逻辑无缝集成。2. Vivado中XADC IP核配置全流程拆解在Vivado里XADC通过一个名为XADC Wizard的IP核来配置。我在实践中发现很多刚开始接触这个IP的人会被里面的各种选项卡弄晕尤其是ADC Setup和Channel Sequencer部分选项多说明又少搞得人一头雾水。我尽量把每一步都讲清楚告诉你这个配置为什么这么选。2.1 新建IP核XADC Wizard的Basic选项页打开Vivado在IP Catalog里搜“XADC”然后双击XADC Wizard。出来的第一页是Basic上来就有几个下拉框这里先别急着全改成自己想的按我下面这个思路来Component Name填一个不重复的模块名比如xadc_monitor这个其实就是生成的IP核文件名。Interface在“None”和“AXI4-Lite”之间选择。如果只是纯逻辑用DRP接口读数据选None就行如果想用Zynq的PS端通过AXI总线去读那就选AXI4-Lite。我做纯FPGA监测时选None后面全用DRP接口加状态机控制。Startup Configuration这里有个选项是“Enable XADC in startup sequence”一般保持默认即可。它的作用是在FPGA配置完成后自动启动XADC不需要逻辑来控制。有一个细节值得留意第七页的“Channel Sequencing”默认选项是“Automatic”模式这个模式下XADC内部会自动循环扫描所有使能的通道然后在DRP端口输出对应通道的数据。这个模式非常省事因为不需要你手动去切换通道地址它自己轮询。只要在Interrupt和Status寄存器里看看当前是哪个通道就可以把数据对号入座。2.2 ADC Setup配置采样模式和时钟频率是关键进入ADC Setup选项卡这里是决定XADC采集性能的地方重点看以下几个设置ADC Scheduling Mode在“Continuous”和“Event”之间选。Continuous就是连续不断地采样Event模式可以用外部信号触发采样。电源监测这种持续监测场景选Continuous最合适。Channel Sequencer这里要勾选你需要采集的通道。默认应该会选上“Temperature”和“VCCINT”两个内部通道你把VAUX0到VAUXN按照自己的硬件设计都勾选上。注意如果某个VAUX通道没连信号最好不要勾否则你会发现读出来的数值是随机的噪声。Simultaneous Sampling这个选项打开后两个ADC可以同时分别采两个通道适合瞬态对比。一般情况下关掉保持默认跳过这个选项因为电源监测对同步性要求不高。Clock SettingXADC的DRP接口需要一个时钟通常我们直接用系统时钟比如100MHz或者50MHz。这个时钟会直接作为XADC内部逻辑的工作时钟而且决定了XADC内部粗调的采样周期。说到时钟这里有个很关键的点。XADC本身是一个模拟为主的模块它对采样时钟的质量有一定要求。Vivado在IP核里会自动根据你输入的时钟频率来计算分频参数。我建议在100MHz下运行这是最常见的配置后面做跨时钟域处理也简单。2.3 Alarm选项卡让XADC自己报警省去逻辑判断很多教程不太提Alarm选项卡但它在电源电压监测里非常实用相当于给XADC设了几个电压阈值超出范围后它会拉高一个报警输出信号。比如说你监测的3.3V轨如果跌到3.0V以下你可以设置一个Upper报警阈值XADC一旦检测到超限alarm_out信号就会拉高直接连着板载LED灯都能看到变化。不过报警功能有个局限它只能对每个通道设置一个上限或下限阈值并不能像逻辑里那样做复杂的判定。所以我一般把它当作一个“硬件看门狗”来用真正的逻辑判定还是自己读DRP数据来处理这样更灵活。2.4 生成IP核与例化模板配置完成后点GenerateVivado会生成一个带例化模板的IP核。在Sources窗口里右键这个IP选择“Open IP Example Design”就能看到Vivado给的一个完整示例工程。这个示例工程值得好好看看它包含了DRP接口状态机和AXI接口例化对你理解接口时序帮助极大我第一次上手就是靠这个例程省了大量摸索时间。注意生成的IP核默认输出端口里有一个drdy信号这是数据准备好标志必须等它为高才能去读do总线上的数据。时序上DRP读取数据的等待周期和地址建立时间都要满足否则会读到脏数据。这个我在后面第4部分会展开说。3. 核心逻辑实现DRP接口读取与电压换算IP核配置好之后剩下的重头戏就是和XADC交互了。XADC内部有一组寄存器通过DRP接口可以写入控制字、读出状态和采样数据。我不推荐用AXI4-Lite因为对纯FPGA逻辑来说AXI接口的握手逻辑又啰嗦又占资源DRP接口反而直接高效。3.1 DRP接口时序详细解读DRP接口读时序是这样的先在daddr上给一个地址然后把den拉高一个周期表示这次传输使能。之后内部会花若干个时钟周期去准备数据等它准备好后drdy会被拉高一个周期在这个上升沿去采集do总线上的数据就完成了整个读操作。写时序类似把dwe拉高数据放到di总线上然后den拉高同样等待drdy回来。注意DRP接口的daddr位宽是7位但实际上XADC用到的地址空间没有那么大一个通道一个地址具体地址在XADC寄存器手册里有明确表格。咱们做电源监测只需要关心两个地址通道数据的地址和状态寄存器地址。这里我强烈建议你按下面的状态机来写因为实际测试发现如果den持续拉高不拉低XADC会继续输出上一轮的数据这时drdy也可能会一直保持高电平导致读到的数据是同一个地址重复的值。状态机的设计能从根本上避免这种情况。3.2 写一个通用的XADC读状态机接下来看代码。这个状态机是我在实际工程里用过的精简了无关部分但核心流程完整保留localparam IDLE 3d0; localparam READ_REQ 3d1; localparam WAIT_DRDY 3d2; localparam READ_DONE 3d3; localparam WRITE_REQ 3d4; reg [6:0] daddr_reg; reg den_reg; reg dwe_reg; reg [15:0] di_reg; reg [15:0] do_reg; wire drdy_wire; always (posedge clk or negedge rst_n) begin if (!rst_n) begin state IDLE; den_reg 1b0; dwe_reg 1b0; daddr_reg 7d0; end else begin case (state) IDLE: begin // 每个周期发起一次单通道读取 daddr_reg CH_ADDR; // 要读取的通道地址 den_reg 1b1; dwe_reg 1b0; state WAIT_DRDY; end WAIT_DRDY: begin den_reg 1b0; if (drdy_wire) begin do_reg do_wire; // 锁存数据 state READ_DONE; end end READ_DONE: begin state IDLE; // 回到IDLE继续下一轮 end default: state IDLE; endcase end end需要特别说明的是den_reg不能一直为高这就是我在代码里WAIT_DRDY状态里把它拉低的原因。DRP总线是典型的脉冲握手给出地址和使能后就要释放等待数据返回。如果你要扫描多个通道其实可以更省事。XADC自动序列器会把所有使能过的通道轮流采样并把当前对应的通道号输出到状态寄存器里。你只要在读数据之前先把状态寄存器读出来判断是哪个通道的数据然后再去读对应的数据寄存器。这样一次循环能把所有通道的数据都抓到。后面我会在“轮询多通道”这个环节给出详细代码段。3.3 数据格式与电压换算公式这是最容易错的地方XADC输出的数据格式是16位的{D[15:4], 4b0000}也就是12位有效位左对齐低4位永远是0。换算成实际电压值的公式如下对于单端输入比如VAUX通道接被测电压经过分压后的信号[ V_{实际} \frac{DNL_{12bit}}{4096} \times V_{满量程} ]其中( DNL_{12bit} ) 就是取16位数据的最高12位也就是do_reg[15:4]。而V_满量程对7系列FPGA来说通常是1V这是XADC内部参考电压决定的。举个例子如果你读到do_reg[15:4] 12h3FF也就是十进制1023那么电压就是1023 / 4096 × 1V ≈ 0.2498V。所以实际工程里的换算代码可以这样写wire [11:0] sample_12bit; wire [19:0] voltage_mV; assign sample_12bit do_reg[15:4]; // 电压值放大1000倍方便显示和比较 assign voltage_mV sample_12bit * 1000 / 4096;但要注意这个公式成立的前提是输入信号已经在FPGA模拟输入引脚的可接受范围内。对于VAUX引脚满量程一般是1V。如果你要监测3.3V电源轨硬件上就必须先用电阻分压把它降到1V以内否则你烧的不只是引脚可能整个FPGA都会报废。这一点做硬件的一定要在原理图阶段就考虑进去。3.4 用状态机实现多通道自动轮询如果你的板子上需要监测8路电源电压手动切地址就太傻了。我一般是让状态机自己轮询自动遍历一系列通道地址并把结果缓存到不同寄存器里。基本思路是定义一组只读寄存器里面存好通道地址表然后状态机每完成一次读操作就把地址索引加1循环执行localparam [6:0] CH_VAUX0 7h10; // 通道地址0x10 localparam [6:0] CH_VAUX1 7h11; localparam [6:0] CH_VAUX2 7h12; localparam [6:0] CH_VAUX3 7h13; localparam [6:0] CH_VAUX4 7h14; reg [6:0] ch_index; wire [6:0] ch_addr_list [0:4]; assign ch_addr_list[0] CH_VAUX0; assign ch_addr_list[1] CH_VAUX1; assign ch_addr_list[2] CH_VAUX2; assign ch_addr_list[3] CH_VAUX3; assign ch_addr_list[4] CH_VAUX4;在READ_DONE状态下判断ch_index是否为最后一个地址如果是就回到0否则加1。在IDLE状态下直接取ch_addr_list[ch_index]作为daddr。这样每5个读周期就完成一轮所有通道的遍历。需要注意的是XADC的采样结果在自动序列模式下是会自己更新的但不会那么快建议每个地址多读几次再取平均值能有效避免毛刺。3.5 硬件实测效果数据稳定性与精度这个方案我在一块Zynq-7020板卡上实测过用外部高精度万用表对照三个通道的数据xadc读数基本能在误差1%以内。如果XADC数据跳变比较明显大概率是输入信号噪声比较大。可以这样处理在逻辑里做一个简单的滑动平均滤波每读取16次数据取平均能明显减少随机抖动。或者在硬件上给模拟输入引脚加一个100nF的滤波电容实测也有奇效。4. 常见问题与排查技巧实录这块是整个项目里最容易让新手崩溃的部分因为我不仅把踩过的坑记录下来还做了问题速查表方便大家按图索骥快速定位自己遇到的问题。4.1 数据全零或固定值不变大概率是通道没使能我见过很多人上来直接读VAUX0结果数据一直是0或者是某个不变的固定值。排查方向主要有两个一是检查XADC Wizard的Channel Sequencer里有没有勾选对应通道如果没有勾选序列器不会去采样这个通道数据自然就是初始值。二是检查引脚约束辅助模拟通道是普通IO复用的必须在XDC文件里加上下面这行类似的约束告诉Vivado这些引脚是模拟输入set_property -dict {PACKAGE_PIN AB13 IOSTANDARD LVCMOS33} [get_ports {VAUXP[0]}] set_property -dict {PACKAGE_PIN AB12 IOSTANDARD LVCMOS33} [get_ports {VAUXN[0]}]不要忘掉这个约束和普通IO的约束是同一个地方只是引脚名字和复用功能要选对。如果你不加约束工具会把它们当普通管脚跑甚至会报错。4.2 DRP读时序不正确导致数据错位这个问题是我在实际调试的时候最容易踩的坑。现象是数据能读出来但有时候对不上号比如读VAUX0时实际拿到的却是VAUX1的数据。原因在于XADC在自动序列模式下会不断轮换采样通道如果你在IDLE状态发起读请求但没看状态寄存器的当前通道号那么拿到的数据就是之前采的那个通道而不一定是你请求的地址对应的通道。解决这个问题有两个办法第一禁用自动序列模式改成手动模式完全由自己的状态机指定通道并等待转换完成再读取。第二在自动序列模式下不要关心里面采的是什么而是每次读之前先读状态寄存器根据通道号来记录数据。第一种方法逻辑上更可控我推荐调试阶段先用第一种方式稳定后再换成自动序列模式做多通道轮询。4.3 模拟输入引脚烧了或者读值不靠谱复盘硬件设计如果VAUX引脚直接接到了超过1V的电压上轻则XADC读数不准重则直接损坏引脚。别忘了XADC模拟输入的绝对最大额定值很低哪怕是瞬间的过压也容易出问题。所以硬件设计时必须在每个模拟输入前加一个合适的分压电阻网络并且建议在靠近FPGA引脚的位置串联一个100Ω到1kΩ的限流电阻防止意外过流。另外模拟输入对地之间至少放一个100pF到1nF的滤波电容能有效滤掉数字开关噪声。模拟地和数字地最好单点连接避免大的数字地电流在模拟地路径上产生压降给测量结果带来偏移误差。4.4 Vivado里仿真XADC能看到的景象在纯逻辑仿真里XADC IP核不会自己产生模拟输入但会有个简单的行为模型。我建议你在测试平台里把vp_in和vn_in分别接一个斜坡电压或者正弦波然后在Testbench里跑100us看看读取的数据是否能实时跟随输入变化。这样做可以对XADC的功能有直观认识。4.5 常见问题速查表现象可能原因解决办法数据一直为零通道没有在Sequencer里使能勾选对应VAUX通道数据固定不变引脚约束缺失或者通道未连接检查XDC约束与硬件接线数据随机跳动大输入噪声大或者GND连接不好增加RC滤波检查模拟地读到的通道错位自动序列模式切换了通道手动模式或读状态寄存器的通道号数据带固定偏移分压电阻精度不足用1%精度电阻并做校准温度数据偏高芯片长时间高负载运行检查散热并通过内部传感器监控DRP读写失败den信号保持高电平未释放按脉冲方式操作DRP接口5. XADC功能扩展一次到位做好电源监测系统只读电压数据其实还不够真正的系统级电源监测还要考虑怎么把数据用起来。比如说可以引一路PWM输出根据温度传感器数据自动调节风扇转速或者当监测到的某路电压低于阈值时通过一个中断信号让整个系统进入安全的掉电顺序。这些扩展功能XADC都能无缝支持。5.1 用阈值报警实现板级硬件保护在IP核里设置好每一路电源轨的上下限阈值后XADC会在硬件层面做比较任何一种电源电压越界alarm_out信号都会拉高。这个信号可以直接接在板卡上一个LED上也可以接在电源控制电路中做保护。关键优势是报警判断是在XADC内部的模拟比较器完成的完全不占FPGA逻辑资源延迟极低比逻辑轮询要快得多。5.2 配合UART把监测数据打到PC上很多项目不仅仅要FPGA自己知道电压值还想在调试界面上实时看到。这时候可以加一个UART发送模块把XADC读出的数据按字节发送到PC串口。我的实现思路是在READ_DONE状态里加一个发送使能信号调用一个简单的UART_TX模块把电压值换算成ASCII码字符串发出去PC端用串口助手打开即可。这个功能在板卡调试时非常实用省了接示波器和万用表的麻烦。5.3 从7系列到UltraScale的移植注意点如果你打算把代码从7系列移植到UltraScale系列要特别小心。UltraScale的XADC模块在命名和寄存器地址上有一些调整但整体架构不变。更关键的是UltraScale把XADC和内部电源管理区分得更细部分供电监控由SYSMON模块完成。不过Vivado里的XADC Wizard在UltraScale工程下会自动适配你先按新器件重新生成IP核再做小范围代码调整即可不需要大面积重写。调试经验总结我在实际项目中把XADC从零到一完整调试通之后最大的体会是XADC其实并不难难的是对它的接口时序和硬件约束细节是否足够清楚。只要记住几个核心点通道使能要勾选、模拟输入不能超出范围、DRP读写要按脉冲来剩下的大部分问题都能迎刃而解。最后再分享一个小技巧在做PCB布线时模拟输入引脚对应的FPGA管脚区域附近不要走高速数字信号线比如DDR、LVDS这些它们耦合过来的噪声会让你XADC测量结果波动得怀疑人生。我当时就是把这个因素忽略了结果调试时数据抖来抖去后来重新调整了布局才解决。现在布板时我每次都会专门检查一遍模拟输入周围的环境这个习惯帮我少走了很多弯路。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。