简介:一份围绕FPGA实现Buck型开关电源数字控制的研究论文,重点探讨Buck变换器建模、DPID算法设计及多软件联合仿真方法。文档面向电力电子、数字控制方向的科研人员和学生,尤其适合正在学习Verilog HDL与FPGA数字电源控制的读者。压缩包内包含1个docx格式的论文文档,容量仅139KB,全文结构清晰,涵盖开关电源概述、Buck变换器工作模式、关键模块设计及Simulink实现等章节。该资源已有167人学习下载。论文详细介绍了小信号模型的数学建模、Verilog硬件描述语言编程架构、DPID控制算法的限幅防溢出处理,以及通过HDL Verifier实现ModelSim与MATLAB/Simulink联合仿真的高效路径,并总结了多软件协同开发在数字控制研究中的优势,可帮助读者系统理解Buck型数字开关电源从理论建模、参数设计到仿真验证的全流程,对跨学科学习具有较高参考价值。
1. 用FPGA做Buck数字控制,核心是建一条低延迟的闭环通路
把这个标题拆开看:Buck是功率级拓扑,FPGA是控制器载体,数字控制方法才是真正要解决的问题。在服务器电源、通信电源和车载电源里,模拟PWM控制器正在被数字方案替换,FPGA的并行处理能力让它在高开关频率、多路交错和复杂保护逻辑面前比MCU更有优势。这套东西的“研究”属性体现在建模、仿真、验证的闭环上:不是把PID公式塞进Verilog就完事,而是要打通ADC采样、误差计算、PWM调制、死区控制这条完整的数据通路。适合两类人:一类是从模拟电源转数字控制的硬件工程师,另一类是接了电源类项目的FPGA工程师。前者需要补FPGA时序思维,后者需要补Buck环路知识。
2. Buck数字控制的系统架构与控制模式选型
2.1 同步Buck和异步Buck的驱动差异,数字控制怎么适配
Buck电路工作原理本身不复杂,一个开关管、一个续流器件、一个LC滤波器。异步Buck用二极管续流,压降大,效率低,但驱动简单;同步Buck用低边MOSFET代替二极管,效率高,但需要一对互补PWM信号,而且必须插入死区,防止上下管直通。FPGA做数字控制时,这两者的适配难度不在算法,而在PWM输出端的时序处理。
对同步Buck,我一般会在FPGA内部生成一路PWM,然后通过死区生成模块拆成两路互补信号。死区时间的典型值在50ns到200ns之间,具体取决于MOSFET的关断延迟和驱动芯片的传播延迟。这个值不能设得太大,太大影响效率;也不能设得太小,太小有直通风险。死区设置的另一个隐蔽问题是:高边关断和低边开通的延迟不对称,所以数字控制里最好把高边关断到低边开通、低边关断到高边开通的死区分开配置。
module deadtime_generator #( parameter DT_H2L = 8'd10, // 高边关到低边开的死区 parameter DT_L2H = 8'd12 // 低边关到高边开的死区 )( input logic clk, input logic rst_n, input logic pwm_in, output logic pwm_h, output logic pwm_l ); logic [7:0] cnt; logic pwm_d1, pwm_d2; always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) begin pwm_d1 <= 1'b0; pwm_d2 <= 1'b0; cnt <= 8'd0; end else begin pwm_d1 <= pwm_in; pwm_d2 <= pwm_d1; if (pwm_d2 != pwm_d1) cnt <= pwm_in ? DT_H2L : DT_L2H; else if (cnt > 0) cnt <= cnt - 1'b1; end end assign pwm_h = pwm_in & (cnt == 0); assign pwm_l = ~pwm_in & (cnt == 0); endmodule这段代码的思路是:检测PWM边沿变化后启动倒计时,倒计时期间输出保持原状态,倒计时结束才切换另一路输出。cnt的是在两个边沿分别加载不同的死区值,正对应高边和低边不对称的延迟特性。这里把死区生成放在FPGA内部而不是外部驱动芯片里,好处是参数可以直接通过寄存器在线修改,调试时不用换元件。
2.2 电压模式、峰值电流模式与滞环控制的FPGA适配度
数字控制方法选型是整个项目的分水岭。最常见的三种方案是电压模式、峰值电流模式和滞环控制,它们的FPGA实现难度和动态响应差别很大。
电压模式是单环控制,ADC只采样输出电压,误差经过补偿器输出占空比。结构最简单,适合作为第一版跑通闭环的方案。峰值电流模式是双环控制,外环是电压环,内环是电流环,需要实时检测电感电流,每个开关周期都要做一次比较。FPGA实现电流内环的难点在于:电感电流的上升沿只有几百纳秒,比较器必须在极短时间内判断是否翻转PWM,这要求ADC或高速比较器的延迟极低,时序约束也紧得多。滞环控制不需要补偿器,输出电压低于下限就开高边,高于上限就关,动态响应最快,但开关频率不固定,EMI和滤波器设计都更麻烦。
| 控制模式 | 环路数量 | 需要采样的信号 | FPGA实现成本 | 动态响应 | 典型应用 |
|---|---|---|---|---|---|
| 电压模式 | 单环 | 输出电压 | 低 | 一般 | 通用Buck、初次验证 |
| 峰值电流模式 | 双环 | 输出电压、电感电流 | 高 | 快 | 大电流DC-DC、服务器电源 |
| 滞环控制 | 无补偿器 | 输出电压(或输出纹波) | 低 | 最快 | LED驱动、对频率不敏感场景 |
如果从零开始做,我的建议是:先用电压模式把整条链路跑通,确认ADC采样、PID计算、DPWM输出没有问题,再往内环加电流控制。直接上峰值电流模式,出问题时很难定位是功率级的原因还是数字采样延迟的原因。
2.3 控制环路的时序预算:ADC采样、PID计算、DPWM更新之间的延迟
数字控制器和模拟控制器的本质区别在于延迟。模拟PWM比较器可以在纳秒级响应误差变化,数字控制器必须经过采样、量化、计算、更新PWM寄存器这一串流水线,每一步都消耗时间。这个延迟就是数字控制环路的一个固有极点,直接限制了可用的环路带宽。
以一个开关频率为100kHz的Buck为例,开关周期是10us,ADCPID计算和PWM更新必须在一个周期内完成,否则控制量跟不上开关动作。用FPGA做这件事的优势在于流水线结构:ADC数据到达后,PID的乘加操作可以在几个时钟周期内完成,而不是像MCU那样一条一条指令取指执行。常见做法的时序预算分配如下:
| 开关频率 | 开关周期 | ADC转换预留 | PID计算预留 | PWM更新与死区 | 环路总延迟 |
|---|---|---|---|---|---|
| 100kHz | 10us | 4us | 1us | 200ns | 约5.2us |
| 500kHz | 2us | 800ns | 400ns | 150ns | 约1.35us |
| 1MHz | 1us | 300ns | 150ns | 50ns | 约0.5us |
环路总延迟占开关周期的比例越接近一半,相位裕度损失越严重。所以FPGA实现时要用pipeline结构:误差计算、比例项、积分项放在不同的时钟节拍完成,而不是等所有数据准备好后一步算完。另外注意,DPWM的占空比更新时机也很关键,更新太早会造成次谐波振荡,更新太晚相当于增加了PWM调制延迟。
3. FPGA内部模块划分:从ADC接口到DPWM的实现路径
3.1 顶层模块划分与关键信号定义
数字控制器的FPGA内部一般分为五个模块:采样接口、参考电压与误差计算、PID补偿器、DPWM调制器、保护与状态机。顶层设计时要把模拟域和数字域的边界划清楚,ADC输出的数据和PWM输出的驱动信号各自独立,调试时方便用ILA单独抓一路。
典型端口定义如下:
| 信号名称 | 方向 | 位宽 | 说明 |
|---|---|---|---|
| clk | input | 1 | 系统时钟,100MHz或更高 |
| rst_n | input | 1 | 异步复位,同步释放 |
| adc_dout | input | 16 | ADC串行或并行数据输出 |
| adc_convst | output | 1 | 启动ADC转换信号 |
| pwm_h | output | 1 | 高边驱动PWM |
| pwm_l | output | 1 | 低边驱动PWM |
| fault_in | input | 1 | 过流、过温保护输入 |
实际项目中,ADC接口可能是SPI、并行LVDS或者JESD204B,具体取决于所选ADC型号和采样速率。低速场合用SPI接口的ADS7950或并行接口的AD7606就可以;采样速率超过5MSPS时,就开始考虑LVDS接口。FPGA的LVDS接收端内部有专门的硬件资源,可以在几百兆赫兹下稳定接收数据,但约束要写好。
3.2 ADC数据同步与跨时钟域处理,避免亚稳态
ADC的采样时钟和FPGA系统时钟往往不是同一个源,数据跨时钟域进入FPGA时,寄存器的建立时间和保持时间可能不满足,触发亚稳态。标题里提到的“FPGA复位信号亚稳态”只是亚稳态问题的一种场景,实际上所有跨时钟域信号都有这个风险。
我一般会在每个ADC数据位进入FPGA后先打两拍,然后才参与计算。这是最简单的防亚稳态手段,代价是增加两个时钟周期的延迟。如果ADC吞吐率很高,数据是连续流式的,就要用异步FIFO做缓冲,FIFO的读写指针用格雷码跨时钟域同步。这里有一个常见错误:有人认为只有复位信号需要关心亚稳态,其实任何输入信号都可能有此问题,只不过复位引发的问题更直接,常被单独拿出来讲。
3.3 定点PID的SystemVerilog实现,考虑饱和与积分限幅
PID参数在FPGA里用定点数表示,不直接写浮点。选择Q格式时,需要考虑电压采样值和占空比值的动态范围。比如ADC是16位,输出电压反馈值范围0到65535,参考电压设定在中间值32768附近,误差范围在-32768到32767之间。PID输出要映射到DPWM的占空比寄存器,通常也用16位。
module pi_controller #( parameter AW = 16, // ADC采样值位宽 parameter MW = 32, // 乘累加结果位宽 parameter Q = 16 // 定点数小数位数 )( input logic clk, input logic rst_n, input logic [AW-1:0] v_ref, input logic [AW-1:0] v_fb, input logic sample_valid, output logic signed [MW-1:0] duty_out ); localparam signed [15:0] KP = 16'd5243; // Q16格式,实际约0.08 localparam signed [15:0] KI = 16'd3277; // Q16格式,实际约0.05 localparam signed [31:0] SAT_MAX = 32'h00FF_FFFF; localparam signed [31:0] SAT_MIN = 32'hFF00_0000; logic signed [AW:0] err; logic signed [MW-1:0] p_term; logic signed [MW-1:0] i_term; logic signed [MW-1:0] i_acc; assign err = $signed({1'b0, v_ref}) - $signed({1'b0, v_fb}); always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) begin p_term <= '0; i_term <= '0; i_acc <= '0; duty_out <= '0; end else if (sample_valid) begin p_term <= err * $signed(KP); i_term <= err * $signed(KI); if (i_acc + i_term > SAT_MAX) i_acc <= SAT_MAX; else if (i_acc + i_term < SAT_MIN) i_acc <= SAT_MIN; else i_acc <= i_acc + i_term; duty_out <= (p_term + i_acc) >>> Q; end end endmodule这里p_term和i_term的计算使用并行乘法器,在同一个时钟周期内完成。积分累加器i_acc加了上下限饱和,防止占空比饱和后积分项继续增大,造成恢复时的大超调,也就是抗积分饱和。duty_out最终的右移Q位把定点数还原成整数占空比。这个模块的输入输出都是寄存器输出,时序上是干净的。带宽整定时可以通过外接寄存器动态修改KP和KI,不用重新综合,但需要建立一组寄存器映射用来在调试时写参数。
3.4 DPWM调制器:计数器比较模式与占空比锁存
DPWM的实现方式有计数器比较和CDCM(基于延迟链)两种。计数器比较模式的分辨率受系统时钟频率限制,假设系统时钟100MHz,PWM频率100kHz,那么每个开关周期有1000个计数单位,占空比分辨率大约是0.1%,即10位精度。对大多数Buck应用够用。如果开关频率到1MHz,计数单位只剩100个,分辨率掉到1%,环路会产生极限环振荡,就要考虑延迟链方案。
计数器比较模式的关键在占空比更新时机。下文代码中duty_reg只在计数器溢出时更新,确保一个PWM周期内占空比保持恒定。如果duty随时可写入DPWM组合逻辑,载波中途翻转会在开关波形上产生毛刺,严重的会引起功率管误导通。
module dpwm #( parameter N = 16 )( input logic clk, input logic rst_n, input logic [N-1:0] duty, // PID输出的占空比 input logic update_en, // 允许更新标志 output logic pwm_out ); logic [N-1:0] counter; logic [N-1:0] duty_reg; always_ff @(posedge clk or negedge rst_n) begin if (!rst_n) begin counter <= '0; duty_reg <= '0; end else begin if (counter == {N{1'b1}}) begin counter <= '0; if (update_en) duty_reg <= duty; end else counter <= counter + 1'b1; end end assign pwm_out = (counter < duty_reg); endmoduleupdate_en信号通常由控制状态机产生,在ADC采样转换完成后拉高一个时钟周期,这样PID输出到DPWM的更新正好落在PWM周期起始处。输出pwm_out再接到前面提到的死区生成模块,配合成互补PWM对。整个链路从ADC采样到PWM更新的总延迟是固定的,这个固定延迟在环路建模中可以用一个纯延时环节近似。
4. 参数设计与时序约束:让Bucket环路稳定而不振荡
4.1 采样频率与开关频率的关系怎么定
数字控制器的采样频率通常等于开关频率,即在每个开关周期内采样一次输出电压。采样时刻必须避开功率管开关动作产生的振荡和振铃,所以ADC触发信号一般由PWM计数器在特定计数值处产生,而不是用固定速率自由运行。
以100kHz开关频率为例,PWM计数器在中间点触发ADC转换,此时高边刚关断,续流管导通,开关节点电压处于相对稳定的状态。如果在这个点附近还有振铃,就是硬开关带来的振铃耦合到采样电路上,常见处理是在ADC前端加RC滤波,截止频率设置在开关频率的5到10倍,用来滤掉振铃而不过度衰减有效信号。Buck电路元件选型在这个过程中联动影响采样:输出电容的ESR过高会让采样毛刺变大,ESR过低又会让环路稳定所需的零点频率偏移,这两者要平衡。
开关频率与ADC吞吐率的对应关系:单次采样一周期,100kHz需要100kSPS,500kHz需要500kSPS,1MHz需要1MSPS。注意所有数字电源的ADC吞吐率需求都不高,难的是保持转换延迟一致性,也就是每次触发到数据有效的时间要稳定,不能有时长时短,否则环路延迟就不是固定的,补偿器会失配。
4.2 反馈通道与PWM通道的延迟预算分配
把整个闭环从ADC到PWM拆成时间轴,有以下关键延迟节点:
| 延迟链节点 | 产生位置 | 典型时间 |
|---|---|---|
| ADC采样保持与转换延迟 | ADC芯片内部 | 0.5us - 3us |
| FPGA输入同步打拍 | 跨时钟域处理 | 2-3个系统时钟 |
| PID计算流水线 | FPGA逻辑 | 3-5个系统时钟 |
| PWM寄存器锁存等待 | 等待PWM周期边界 | 0 - 1个开关周期 |
| 死区延迟 | FPFA内死区生成 | 50ns - 200ns |
PID计算流水线是固定的时钟周期数,不管有多少个乘法器并行,总能在几个时钟周期内出结果。真正不可控的是PWM寄存器锁存等待,它要等到计数器溢出才能更新占空比,这个等待时间平均是半个开关周期。这个等待时间占整个环路延迟的比例很大,所以常见做法是把DPWM的更新点对齐到ADC触发点后固定几个时钟周期,让整个环路延迟变成确定值,补偿器根据这个确定的延迟来设计。
4.3 时序约束怎么写,输入延迟与跨时钟域约束
FPGA工程中时序约束是数字电源和普通逻辑项目最大的区别。普通逻辑只要保证时钟频率能满足即可,数字电源还要精确约束ADC数据和PWM输出的时序。
create_clock -name sys_clk -period 10.000 [get_ports clk] create_clock -name adc_clk -period 25.000 [get_ports adc_clk] set_input_delay -clock adc_clk -max 8.0 [get_ports {adc_data[*]}] set_input_delay -clock adc_clk -min 2.0 [get_ports {adc_data[*]}] set_false_path -from [get_clocks adc_clk] -to [get_clocks sys_clk]set_input_delay的值由ADC芯片的数据手册给出,max和min分别对应数据在时钟沿后多长时间到达。如果不写这两个约束,综合工具会认为数据在时钟沿时刻到达,优化结果与实际不匹配。set_false_path加在ADC异步时钟域和系统时钟之间,告诉工具这两个时钟域之间的路径不需要分析——因为已经在逻辑层做了同步打拍或FIFO处理。
此外,复位信号也要做约束。异步复位、同步释放是数字电源项目里的标配,复位释放时正好落在时钟上升沿附近会触发亚稳态,同步化处理后可以避免恢复时间违例。约束上与普通时钟约束相同,但代码里要用两级同步器,不能把外部复位直接接到所有触发器的异步复位端。
4.4 用仿真验证闭环响应,开环先过再闭口
写testbench验证PID模块时,要把系统建模为被控对象模型,而不是只检查PID的输出值。简单的Buck系统模型可以用一个状态空间方程描述,在testbench里用离散时间步进模拟输出电压对占空比的响应。
`timescale 1ns/1ps module tb_pi_controller; logic clk; logic rst_n; logic sample_valid; logic [15:0] v_ref; logic [15:0] v_fb; logic signed [31:0] duty_out; pi_controller dut (.*); // 模拟Buck功率级:一阶惯性并叠加延迟 // vout += (duty_out - vout) * 0.1 real vout; real duty_real; always #50 begin duty_real = $itor(duty_out) / 65536.0; vout = vout + (duty_real * 12.0 - vout) * 0.08; v_fb = $rtoi(vout / 12.0 * 65535.0); end initial clk = 0; always #5 clk = ~clk; initial begin rst_n = 0; v_ref = 16'd32768; v_fb = 16'd30000; vout = 5.5; #100 rst_n = 1; repeat (20) begin #100 sample_valid = 1; #10 sample_valid = 0; end #1000 $finish; end endmoduletestbench里用一个real类型的变量模拟输出电压,每50ns更新一次。这个模型是简化的,但仿真出来的PID输出趋势与真实环路一致,足以用来验证模块功能。真正上板前还要做两个检查:第一,开环状态下给固定占空比,输出电压是否稳定在期望范围内;第二,闭环后从轻载切重载,观察输出电压跌落幅度和恢复时间是否符合预期。
4.5 上板调试:用ILA抓PID输出和PWM占空比
FPGA调试数字电源最常用的工具是Vivado或Quartus里的逻辑分析仪核,在设计中插入ILA观察内部信号。抓取要点是把v_fb、err、duty_out、pwm_out同时接进去,触发条件设为err的绝对值超过某个阈值,这样能捕捉到负载突变瞬间的环路响应。
抓到的波形中,如果duty_out出现大幅振荡而且频率在1kHz到10kHz之间,说明环路增益过大,比例项增益要下调。如果负载突变后duty_out长时间饱和在最大值,积分项饱和限制可能太紧,需要放宽SAT_MAX。如果v_fb上叠加了周期性毛刺,而且毛刺频率等于开关频率,说明ADC采样时刻没有避开开关动作,要调整PWM计数器中间点触发的具体计数值。ILA采样时钟用系统时钟,采样深度不低于4096,确保能在单次触发中覆盖整个瞬态恢复过程。
5. 应用扩展:多相交错BucK与数字均流
5.1 多相交错如何降低输出纹波
单相Buck在输出大电流时,电感体积和输出电容需求都会变大。多相交错Buck的基本思路是N个Buck单元并联,每个单元的PWM相位错开360/N度,各相电流纹波在输出端部分抵消。四相设计可以将有效纹波频率提升到开关频率的4倍,输出电容的容值和体积显著下降。
FPGA实现交错PWM非常自然。每个DPWM模块独立运行,各相计数器的初始值分别设为周期的0/N、1/N、2/N……即可产生错开相位差。
5.2 数字均流:每相独立电流环还是共电压环加均流支路
多相交错的难点在均流。由于各相元器件参数不完全一致,各相电感量和导通电阻有差异,占空比一样时各相电流并不相等。数字控制的常见做法是电压外环共用一路PID,输出一个总占空比基准,每相各加一个均流补偿项,该补偿项由本相电流与平均电流之差乘以系数生成,叠加到本相占空比上。
均流系数不宜过大,过大容易引起相间振荡。我一般从每千安培误差对应调整5%占空比起步,在满载条件下观察各相电流是否趋近。如果发现某相电流持续偏低,先检查该相PWM驱动波形是否有死区异常,不一定是均流环路的问题——功率级的Layout不对称也可能造成电流偏差。
5.3 验证技巧:触发条件设在PWM周期中间点
最后给一个实用技巧:抓取ILA波形验证环路响应时,把采样时钟取为系统时钟,但触发条件要精确设在PWM周期中间点。配置逻辑大致是:当计数器过中间值且err超出阈值时触发采样。这样同时能看到ADC采样点位置和该周期更新后的占空比值,判断补偿器是否在一个开关周期内完成了对扰动的首次修正。如果触发采样的数据里占空比更新滞后了两个以上周期,说明PID流水线等待事件过长,要把计算提前一拍或简化乘法器链路。
本文还有配套的精品资源,点击获取