
1. 项目概述从数字世界到模拟世界的桥梁在电子系统设计的领域里我们常常需要处理两种截然不同的信号数字信号和模拟信号。数字信号是离散的用0和1表示易于存储、处理和传输而模拟信号是连续的真实世界中的声音、温度、压力、图像亮度等本质上都是模拟量。让这两种信号能够“对话”是无数电子设备得以工作的基础。数模转换器也就是我们常说的DAC正是这座关键的桥梁。它负责将我们编写的、由0和1组成的数字代码精准地还原成连续变化的电压或电流。这次我们不谈现成的DAC芯片如何使用而是要深入到更底层聊聊如何用FPGA来“设计”一个数模转换器。你可能会问FPGA本身就是数字逻辑器件怎么能产生模拟信号呢没错FPGA的IO引脚输出的是高电平如3.3V和低电平0V。但通过巧妙的数字调制技术和外围简单的模拟电路我们可以让FPGA输出一个“平均意义上”的模拟电压。这就像快速开关一盏灯通过控制亮和灭的时间比例人眼会感觉到不同的亮度。基于FPGA的DA设计核心就是利用这种“脉冲密度调制”的思想在数字域生成高精度的控制序列再通过一个低通滤波器“平滑”出我们想要的模拟波形。这对于需要灵活波形生成、低成本原型验证或集成特定调制算法的场景比如信号发生器、音频合成、电机控制、LED调光等具有独特的价值。无论你是FPGA的初学者想理解数模转换的底层逻辑还是有一定经验的工程师寻求定制化DA解决方案这个从源码出发的探索过程都能让你对信号系统的理解更深一层。2. 核心原理与方案选型为什么用FPGA做DA在开始动手写代码之前我们必须先搞清楚几个根本问题用FPGA实现DA的常见方法有哪些各自的原理是什么我们为什么要选择其中某一种这决定了整个项目的架构和最终性能。2.1 主流FPGA-DA实现方案对比FPGA本身不具备真正的模拟输出能力因此所有的方案都是“数字处理外围电路”的组合。主流方案有以下三种PWM脉冲宽度调制这是最直观、最简单的方法。FPGA产生一个固定频率的方波通过改变一个周期内高电平所占的时间比例占空比来调节输出信号的平均电压。经过一个低通滤波器后就能得到与占空比成正比的直流电压。它的优点是原理简单实现容易只需要一个计数器和一个比较器即可。但缺点也很明显输出波纹大动态范围有限且要输出复杂的交流信号非常困难需要极高的PWM频率和复杂的调制算法。Σ-Δ调制位流DAC这是一种过采样噪声整形技术。它通过将输入的高分辨率数字信号如16位转换为一位1-bit的高速位流。这个位流中“1”的密度代表了输入信号的幅度。然后同样通过一个低通滤波器即可恢复出高精度的模拟信号。它的优势在于能够用极低分辨率的数字内核1位实现高分辨率的模拟输出并且将量化噪声推向高频易于滤除。音频DAC芯片很多都采用此原理。在FPGA中实现Σ-Δ调制器需要设计数字滤波器如CIC、FIR和噪声整形环路难度较高但性能潜力大。R-2R梯形网络电阻网络DAC这是一种经典的直接转换架构。FPGA的多个并行IO引脚分别代表数字代码的不同位如8位。每个引脚通过一个电阻连接到运放的求和节点电阻值按二进制权重R, 2R, 4R...排列。当某个位为高电平时就会在输出端产生一个对应权重的电流总和即为模拟输出。这种方法理论上可以直接输出模拟电压无需复杂的调制。但是它对FPGA的IO引脚输出电压一致性、电阻精度和温漂要求极高在板级实现中很难达到高精度通常只在特定教学或低精度场景使用。2.2 我们的选择基于1位Σ-Δ调制的位流DAC综合考量实现的灵活性、可达到的精度以及FPGA的资源特性本次设计我们将采用1位Σ-Δ调制方案。为什么核心考量FPGA擅长高速、并行的数字信号处理。Σ-Δ架构将高精度的转换需求从难以保证的模拟器件精度如R-2R网络的电阻转移到了可以精确控制的数字逻辑和时序上。我们可以在FPGA内轻松实现一个时钟频率高达上百MHz的Σ-Δ调制器通过过采样和噪声整形用一位高速开关信号去“逼近”一个高精度的模拟值。外围电路仅需要一个简单的RC低通滤波器成本低易于实现。方案优势高分辨率潜力通过提高过采样率OSR理论上可以获得16位甚至24位的有效分辨率。对模拟部分要求低仅需一个运放和几个阻容元件构成滤波器对元件精度要求相对宽松。强大的灵活性波形生成算法完全在FPGA内部通过数字逻辑实现可以轻松产生正弦波、三角波、任意波形甚至实现复杂的数字调制如FM、AM。资源消耗可控核心调制器逻辑非常简单主要资源消耗在可能需要的数字插值滤波器中可以根据性能需求灵活调整。面临的挑战带内噪声噪声整形会将量化噪声推向高频但仍有部分会落在信号带宽内影响信噪比SNR。时钟抖动敏感Σ-Δ调制器对时钟的抖动非常敏感时钟抖动会直接转化为输出噪声。滤波器设计输出滤波器的设计至关重要它决定了最终信号的带宽、建立时间和纹波水平。确定了核心架构接下来我们就深入到数字核心部分看看如何在FPGA中构建这个Σ-Δ调制器。3. 数字核心设计Σ-Δ调制器的FPGA实现我们的目标是设计一个能够将16位有符号数字样本转换为1位高速位流的Σ-Δ调制器。这里我们选择实现一个经典且稳定的二阶Σ-Δ调制器它在复杂度、稳定性和性能之间取得了很好的平衡。3.1 二阶Σ-Δ调制器数学模型与结构一个二阶Σ-Δ调制器可以看作是两个积分器加一个量化器比较器的反馈环路。其数学模型可以用差分方程表示但在FPGA里我们更关心它的数字硬件结构。一个常用的二阶误差反馈结构EFM如下图所示概念性描述输入X[n] -- 加法器1 -- 积分器1寄存器1 -- 加法器2 -- 积分器2寄存器2 -- 量化器比较器 -- 输出Y[n]1位 ^ | ^ | ^ | | | | | | (反馈回路) | (反馈回路) | | | | | | --- 减Y[n] ---- --- 减Y[n] ---- | | | ---------------------------------------------------------------反馈系数通常为2在FPGA中我们将其转化为具体的数字电路。积分器用累加器实现量化器就是一个与0比较的操作对于有符号数输出1表示正0表示负但实际我们常用1和-1表示以便于计算。Verilog实现核心代码段解析module sigma_delta_2nd_order #( parameter DATA_WIDTH 16, // 输入数据位宽 parameter ACC_WIDTH 20 // 累加器位宽需大于DATA_WIDTH以防止溢出 )( input wire clk, // 系统时钟高频如100MHz input wire rst_n, // 异步低电平复位 input wire signed [DATA_WIDTH-1:0] data_in, // 有符号输入样本 output reg dac_out // 1位输出 ); // 内部信号声明 reg signed [ACC_WIDTH-1:0] acc1; // 第一级积分器累加器 reg signed [ACC_WIDTH-1:0] acc2; // 第二级积分器 wire signed [ACC_WIDTH-1:0] feedback; // 反馈量 // 将1位输出映射为有符号数用于反馈计算 assign feedback (dac_out 1b1) ? (1 (DATA_WIDTH-1)) : -(1 (DATA_WIDTH-1)); always (posedge clk or negedge rst_n) begin if (!rst_n) begin acc1 0; acc2 0; dac_out 1b0; end else begin // 第一级积分acc1 acc1 (data_in - feedback) acc1 acc1 (data_in - feedback); // 第二级积分acc2 acc2 acc1 - feedback // 注意这里反馈系数为2所以减去了2倍的feedback。简化实现中常将2倍反馈合并到前级或后级。 // 一种稳定的实现是acc2 acc2 acc1 - feedback; // 然后量化dac_out (acc2 0) ? 1b1 : 1b0; // 但更标准的二阶反馈是acc2 acc2 acc1 - 2*feedback; // 为了简化且避免乘法我们可以调整反馈权重或使用移位。 // 以下是经过简化的稳定版本 acc2 acc2 acc1 - (feedback 1); // feedback左移1位等于乘以2 // 量化器 dac_out (acc2[ACC_WIDTH-1] 1b0) ? 1b1 : 1b0; // 判断最高位符号位 end end endmodule关键参数与设计要点时钟频率clk这是Σ-Δ调制器的采样频率Fs。它必须远高于目标输出信号的最高频率Fsignal其比值即为过采样率OSR Fs / (2 * Fsignal)。OSR越高理论上信噪比提升约9dB/倍频程对于二阶调制器。例如要输出20kHz的音频信号若要求OSR128则Fs需要达到128 * 2 * 20kHz 5.12MHz。实际中我们会使用FPGA的高频主时钟如50MHz或100MHz直接驱动调制器以获得极高的OSR。累加器位宽ACC_WIDTH必须足够大以防止运算溢出。通常比输入数据位宽DATA_WIDTH大4-8位是安全的。溢出会导致调制器不稳定输出出现极限环振荡。反馈系数上述代码中使用了简化的feedback 1来实现系数2。在更精确的模型中反馈系数需要仔细设计以确保调制器稳定。对于二阶调制器系数1 2是一个常见且稳定的选择。量化器我们简单地用第二级累加器的符号位作为1位输出。这是一种最简单的单比特量化。实操心得稳定性是第一位在调试Σ-Δ调制器时最先要检查的就是它是否稳定。一个不稳定的调制器其累加器值会不断增长直至溢出输出位流会呈现规律的、与输入无关的振荡模式如010101...。确保稳定性的关键点1) 累加器位宽足够2) 反馈系数设置正确可以从文献或成熟系数开始3) 输入信号幅度必须在调制器的输入范围内通常为满量程的80%-90%。可以先输入一个固定的中值直流码用示波器观察滤波后的输出是否是一个稳定的直流电压。3.2 测试信号生成正弦波查找表LUT为了测试我们的DAC我们需要在FPGA内部生成一个数字正弦波样本流并输入到Σ-Δ调制器。最常用的方法是使用查找表。module sin_lut #( parameter DATA_WIDTH 16, parameter LUT_DEPTH 256, // 查找表深度一个周期采样点数 parameter PHASE_WIDTH 8 // 相位累加器位宽与LUT_DEPTH对应 )( input wire clk, input wire rst_n, input wire [PHASE_WIDTH-1:0] freq_word, // 频率控制字 output reg signed [DATA_WIDTH-1:0] sin_out // 正弦波输出 ); // 正弦波查找表ROM reg signed [DATA_WIDTH-1:0] sin_rom [0:LUT_DEPTH-1]; initial begin // 使用系统任务$readmemh从文件加载ROM数据或直接初始化 // 这里为了示例用循环初始化一个正弦波表 integer i; for (i0; iLUT_DEPTH; ii1) begin sin_rom[i] $signed($rtoi( (2.0**(DATA_WIDTH-1)-1) * $sin(2.0 * 3.1415926 * i / LUT_DEPTH) )); end end // 相位累加器 reg [PHASE_WIDTH-1:0] phase_acc; always (posedge clk or negedge rst_n) begin if (!rst_n) begin phase_acc 0; sin_out 0; end else begin phase_acc phase_acc freq_word; // 相位累加 sin_out sin_rom[phase_acc[PHASE_WIDTH-1:PHASE_WIDTH-8]]; // 取高8位作为ROM地址 end end endmodule设计解析频率控制字freq_word它决定了相位累加器的步进大小从而控制输出正弦波的频率。输出频率Fout (freq_word * Fclk) / (2^PHASE_WIDTH * LUT_DEPTH)。通过改变freq_word可以实现频率可调。查找表深度与精度LUT_DEPTH越大一个周期内采样点越多生成的波形相位分辨率越高谐波失真越小。但也会消耗更多的Block RAM资源。通常256或512点是一个较好的平衡。幅度查找表中的数值范围应占满输入DAC的有效范围例如-32768到32767对于16位有符号数但需留出一定余量如90%以确保Σ-Δ调制器稳定。至此我们已经完成了数字部分的核心一个可以产生高速1位流、代表特定波形数据的Σ-Δ调制器。接下来我们需要为这个比特流搭建一个通往模拟世界的“出口”。4. 模拟输出级与滤波器设计数字部分产生的是一位高速开关信号0或1对应0V和3.3V。我们的目标是将这个包含目标信号和大量高频噪声的脉冲序列还原成干净、平滑的模拟电压。这全靠输出级的模拟电路。4.1 输出驱动与低通滤波器LPF最简单的输出级就是一个RC低通滤波器。FPGA的IO引脚直接通过一个电阻连接到滤波电容电容另一端接地。FPGA_IO ---- R -------- Vout (至示波器或后续电路) | C | GND元件参数计算 滤波器的截止频率Fc由公式Fc 1 / (2π * R * C)决定。设计目标滤除Σ-Δ调制器产生的高频噪声主要集中在Fs/2附近同时保留我们需要的信号带宽为Fsignal。设计准则截止频率Fc应设置在Fsignal和Fs/2之间。通常选择Fc比Fsignal高5-10倍以保证信号相移和衰减在可接受范围同时远低于Fs/2以充分抑制噪声。例如Fs100MHz,Fsignal20kHz我们可以选择Fc ≈ 200kHz。参数选择假设选择Fc 200kHz。先选取一个常见的电容值如C 100pF1pF10^-12F。则电阻R 1 / (2π * Fc * C) ≈ 1 / (6.28 * 200e3 * 100e-12) ≈ 7958 Ω。我们可以取一个接近的标准值如R 8.2kΩ。注意事项IO驱动能力与阻抗匹配FPGA的IO引脚有输出驱动电流限制通常为几mA到几十mA。当电阻R值太小时IO引脚在输出高电平时需要灌入较大的电流为电容充电可能导致输出电压下降、功耗增加甚至损坏IO。因此R不宜过小通常不小于1kΩ。另一方面R太大又会使得滤波器容易受到板级寄生电容和噪声干扰。8.2kΩ是一个在驱动能力和滤波效果之间折衷的常用值。此外如果后级电路输入阻抗不是很高需要考虑负载效应可能需要加入电压跟随器运放缓冲器。4.2 进阶设计有源滤波器与缓冲为了获得更好的驱动能力和滤波特性可以使用运放构成有源低通滤波器。一个简单的一阶有源低通滤波器Sallen-Key结构如下图所示FPGA_IO ---- R1 ------------ Vout | | C1 | | | GND | | OPAMP (接成电压跟随器或同相放大器) | ...其传递函数和截止频率计算与无源RC类似但运放提供了高输入阻抗和低输出阻抗隔离了前后级性能更优。对于更高阶的滤波要求更陡的滚降可以使用二阶、四阶等有源滤波器如Multiple Feedback或State-Variable结构。运放选型建议带宽运放的单位增益带宽应远高于信号频率Fsignal最好也高于滤波器截止频率Fc的10倍以上。压摆率如果需要输出大幅值的高频信号压摆率需要足够高以避免波形失真。电源电压与FPGA的IO电压如3.3V匹配选择单电源或轨到轨运放以充分利用动态范围。4.3 PCB布局与接地要点模拟电路的性能极度依赖于PCB设计。电源去耦在运放和FPGA的电源引脚附近务必放置一个0.1μF的陶瓷电容和一个10μF的钽电容或电解电容以滤除高频和低频噪声。地平面使用完整、连续的接地层。模拟地和数字地应在一点连接通常靠近电源入口处避免数字噪声串扰到敏感的模拟部分。信号走线连接滤波器电阻电容的走线应尽量短粗远离数字高速信号线如时钟线。滤波器输出到运放输入的走线也需要小心处理。参考电压如果Σ-Δ调制器的反馈计算是基于一个精确的参考电压Vref那么这个Vref的稳定性和纯净度至关重要可能需要使用专用的低噪声基准电压源芯片。数字部分产生精准的比特流模拟部分负责安静地执行“翻译”。两者配合一个基于FPGA的DA系统就初具雏形了。但在把它用起来之前我们还需要一套验证和测试的方法。5. 系统集成、测试与性能评估将Σ-Δ调制器、波形发生器和顶层的控制逻辑集成在一起就构成了一个完整的信号发生系统。测试是验证设计是否成功的关键。5.1 顶层系统集成与接口一个简单的顶层模块可能如下所示module fpga_dac_top #( parameter SYS_CLK_FREQ 100_000_000 // 系统时钟频率100MHz )( input wire clk, // 系统时钟 input wire rst_n, // 复位 input wire [7:0] sw, // 开关用于选择波形或频率 output wire dac_bit // 1位DA输出连接至外部滤波器 ); wire [15:0] freq_ctrl_word; wire signed [15:0] wave_data; // 根据开关设置生成频率控制字 freq_ctrl u_freq_ctrl(.clk(clk), .rst_n(rst_n), .sw(sw), .freq_word(freq_ctrl_word)); // 正弦波查找表发生器 sin_lut #(.DATA_WIDTH(16), .LUT_DEPTH(512), .PHASE_WIDTH(32)) u_sin_lut(.clk(clk), .rst_n(rst_n), .freq_word(freq_ctrl_word), .sin_out(wave_data)); // Σ-Δ调制器核心 sigma_delta_2nd_order #(.DATA_WIDTH(16), .ACC_WIDTH(20)) u_sigma_delta(.clk(clk), .rst_n(rst_n), .data_in(wave_data), .dac_out(dac_bit)); endmodule5.2 测试方案与仪器使用静态测试直流输出方法向Σ-Δ调制器输入一个固定的数字码例如0对应0V最大值对应Vref。用示波器测量经过低通滤波器后的输出电压。观察电压是否稳定纹波有多大改变输入码值输出是否线性变化工具数字万用表测量平均电压、示波器观察纹波。动态测试交流输出方法输入正弦波数字码。使用示波器观察时域波形。测量指标频率准确度测量输出正弦波的周期计算频率是否与设定值一致。幅度测量峰峰值电压。波形失真观察波形是否光滑有无明显的台阶或畸变。可使用示波器的FFT功能进行粗略的频谱分析查看基波幅度和谐波分量。工具示波器带FFT功能为佳。性能评估信噪比SNR这是衡量DAC精度的核心指标。需要在输出端连接一个低噪声放大器然后用音频分析仪或高性能的ADC采集卡进行测量。通过计算信号功率与噪声功率的比值得到SNR。对于我们的设计目标SNR能达到70-80dB相当于约12-13位有效精度就算非常成功了。总谐波失真THD衡量由于非线性引入的失真。也需要借助专业仪器分析输出频谱计算各次谐波分量总和与基波分量的比值。无杂散动态范围SFDR频谱中基波幅度与最大杂散非谐波分量幅度的差值。反映了系统对杂散噪声的抑制能力。实操心得示波器是调试的眼睛在初期调试时不要急于连接复杂的滤波器。可以先将FPGA的1位输出直接接到示波器上设置示波器为高分辨率采集模式或无限余辉模式。你应该能看到一个随输入信号变化的、密度不均匀的脉冲序列。输入一个中频正弦波时脉冲的疏密变化应该能直观反映出正弦波的包络。这能第一时间验证你的Σ-Δ调制器逻辑是否在工作。然后再接入RC滤波器观察波形如何从脉冲序列变为平滑的正弦波。通过调整R或C的值观察截止频率对输出波形平滑度和建立时间的影响这是一个非常直观的学习过程。5.3 常见问题与排查技巧实录在实际操作中你几乎一定会遇到下面这些问题。这里记录了我的排查思路和解决方法。问题现象可能原因排查步骤与解决方法输出为固定高/低电平无变化1. Σ-Δ调制器未正确复位或使能。2. 输入数据data_in恒定不变。3. 时钟未连接或频率异常。1. 检查复位信号时序确保上电后复位信号有效跳变。用内部逻辑分析仪如Xilinx的ILA抓取调制器内部累加器acc1、acc2的值看是否在变化。2. 检查波形发生器模块确认其有输出且数据在变化。可以先用一个简单的计数器作为输入测试。3. 检查时钟引脚约束和实际测量时钟频率。输出有脉冲但滤波后电压不对或波动大1. 滤波器截止频率Fc设置不当太高或太低。2. 电阻/电容值不准确或焊接问题。3. 电源噪声大或地线干扰。1. 重新计算Fc并用示波器观察滤波器前后的波形。如果Fc太高输出会有大量毛刺如果Fc太低信号幅度会被衰减高频成分丢失。尝试更换不同参数的RC。2. 用万用表测量实际电阻电容值。检查有无虚焊、短路。3. 用示波器探头直接测量FPGA的电源引脚和地引脚看是否有明显噪声。优化电源设计和PCB布局。输出正弦波有明显台阶或失真1. 正弦波查找表LUT深度不足量化误差大。2. Σ-Δ调制器不稳定出现极限环振荡。3. 运放压摆率不足或带宽不够。1. 增加LUT_DEPTH如从256提高到512或1024。确保LUT中的数据是完整的正弦周期采样。2. 检查调制器累加器是否溢出。可以暂时减小输入信号的幅度如使用满量程的50%看失真是否改善。调整反馈系数微调feedback 1中的移位量或改用乘法器。3. 换用更高带宽和压摆率的运放。降低输出信号的频率和幅度进行测试。输出噪声大SNR低1. 过采样率OSR太低。2. 时钟jitter抖动过大。3. 模拟部分电源/地噪声严重。4. 滤波器性能不佳。1. 提高系统时钟Fs如果FPGA支持或降低输出信号带宽Fsignal以提高OSR。2. 使用FPGA内部的高质量时钟管理器如PLL生成低抖动的时钟驱动调制器。检查时钟源质量。3. 强化电源滤波使用线性稳压器为模拟部分单独供电。检查地回路。4. 使用高阶有源滤波器如四阶巴特沃斯替代简单RC滤波器。不同频率下输出幅度不一致滤波器不是理想的“砖墙”其幅频特性在截止频率附近就开始衰减。这是低通滤波器的固有特性。如果要求带内平坦度需要1) 将滤波器截止频率Fc设置得远高于最高信号频率2) 使用具有更平坦通带特性的滤波器类型如贝塞尔滤波器3) 在数字域进行预补偿均衡。调试是一个“假设-验证-修正”的循环过程。从最简单的配置开始逐步增加复杂度每步都进行验证就能有效地定位和解决问题。6. 优化与扩展方向一个基础版本工作稳定后我们可以从多个维度对其进行优化和功能扩展使其更实用、性能更强。6.1 数字插值滤波器Interpolation Filter我们的波形发生器如正弦波LUT通常运行在一个相对较低的频率Fdata比如48kHz。而Σ-Δ调制器需要工作在很高的频率Fs比如6.144MHzOSR128。直接上采样会导致镜像频谱。因此需要在数据源和调制器之间插入一个数字插值滤波器。作用先将数据从Fdata内插到Fs同时滤除由于上采样产生的镜像频率成分。实现通常采用多级实现例如先通过2倍插值的半带滤波器再通过CIC积分梳状滤波器进行高倍率插值。CIC滤波器结构简单无需乘法器非常适合FPGA实现。好处能显著提高最终输出的信噪比和带内信号质量。6.2 高阶Σ-Δ调制器与多位量化我们实现的是二阶1位调制器。为了提高性能可以考虑提高阶数三阶、四阶甚至五阶调制器可以提供更强的噪声整形能力在相同OSR下获得更高的SNR。但阶数越高稳定性设计越复杂需要更精细的系数设计。多位量化将1位量化器改为2位、3位或更多位。这可以降低量化噪声功率并且对时钟抖动的敏感性也会降低。但需要外围的多位DAC如温度计码DAC或通过时间交织等方式实现增加了模拟电路的复杂性。6.3 应用于特定场景这个基础的FPGA-DA框架可以轻松适配各种场景音频播放将解码后的PCM音频数据如来自I2S接口送入插值滤波器和Σ-Δ调制器即可驱动一个简单的耳机放大器或扬声器。直接数字频率合成DDS我们已经实现了一个简单的DDS正弦波LUT相位累加器。可以扩展其功能增加频率调制FM、相位调制PM等用于通信系统。电机控制产生精密的PWM或模拟电压信号用于控制直流电机、步进电机或伺服驱动器的速度与位置。可编程电源通过反馈环路需ADC采样输出电压可以实现一个数字控制的稳压电源。从一行行代码和一个个电阻电容开始构建起一个能够将数字思想转化为模拟现实的系统这个过程充满了挑战也极具成就感。它迫使你同时思考数字域的逻辑时序和模拟域的连续响应对“信号与系统”的理解不再停留在课本公式上。当你第一次在示波器上看到由自己编写的Verilog代码产生的、光滑的正弦波时那种感觉是无与伦比的。这个项目最大的价值或许不在于它达到了多高的性能指标而在于它提供了一条清晰的路径让你可以亲手触摸到数字与模拟世界的边界并按照自己的意愿去塑造它。