R-2R电阻网络 + PWM调制 + Sigma-Delta — 把数字变成真实声音!
🏆 成就:声波炼金术 ✅ Verilator验证通过
FPGA输出的是数字信号(0和1),要让扬声器发出声音,需要将数字音频转为模拟电压。有三种方法:
// PWM音频输出 - 1位PWM调制8位音频
module pwm_audio (
input wire clk, // 系统时钟(50MHz)
input wire rst,
input wire [7:0] audio_in, // 8位音频输入
output reg pwm_out // PWM输出(1位)
);
// PWM计数器 - 8位分辨率
// PWM频率 = 50MHz / 256 ≈ 195kHz
reg [7:0] pwm_cnt;
always @(posedge clk) begin
if (rst) begin
pwm_cnt <= 0;
pwm_out <= 0;
end else begin
pwm_cnt <= pwm_cnt + 1;
// 比较器: 计数值 < 音频值 → 输出高
pwm_out <= (pwm_cnt < audio_in);
end
end
endmodule// Sigma-Delta (PDM) DAC - 1位高过采样
module sigma_delta_dac (
input wire clk,
input wire rst,
input wire [7:0] audio_in, // 8位音频输入(无符号)
output reg pdm_out // PDM输出(1位)
);
// Sigma-Delta调制器
// 积分器(累加) + 量化器(1位)
reg [8:0] integrator; // 比输入多1位防溢出
always @(posedge clk) begin
if (rst) begin
integrator <= 0;
pdm_out <= 0;
end else begin
// 反馈: 输出1时减128, 输出0时加128
if (pdm_out)
integrator <= integrator + {1'b0, audio_in} - 9'd128;
else
integrator <= integrator + {1'b0, audio_in} + 9'd128;
// 1位量化
pdm_out <= integrator[8]; // MSB
end
end
endmodule// 音频混音器 - 4通道混合
module audio_mixer (
input wire clk,
input wire rst,
input wire [7:0] ch0, ch1, ch2, ch3, // 4通道8位输入
input wire [1:0] vol0, vol1, vol2, vol3, // 每通道2位音量
output wire [7:0] mixed_out // 混合输出
);
// 音量调节: 右移(0=静音, 1=1/2, 2=1/4, 3=1/8)
wire [7:0] v0 = ch0 >> vol0;
wire [7:0] v1 = ch1 >> vol1;
wire [7:0] v2 = ch2 >> vol2;
wire [7:0] v3 = ch3 >> vol3;
// 混合: 求和后取平均(防溢出)
wire [9:0] sum = {1'b0, v0[7:1]} + {1'b0, v1[7:1]} +
{1'b0, v2[7:1]} + {1'b0, v3[7:1]};
// 截断到8位
assign mixed_out = (sum > 255) ? 8'hFF : sum[7:0];
endmodulemodule sigma_delta_dac_tb;
logic clk=0, rst=1;
logic [7:0] audio_in;
logic pdm_out;
sigma_delta_dac uut(.*);
always #10 clk = ~clk;
initial begin
rst=1; #50; rst=0;
$display("--- Sigma-Delta DAC测试 ---");
// 测试1: 中间值(128)
audio_in = 8'd128;
repeat(256) @(posedge clk);
$display(" audio=128, PDM占空比应≈50%%");
// 测试2: 高值(200)
audio_in = 8'd200;
repeat(256) @(posedge clk);
$display(" audio=200, PDM占空比应≈78%%");
// 测试3: 低值(50)
audio_in = 8'd50;
repeat(256) @(posedge clk);
$display(" audio=50, PDM占空比应≈20%%");
// 测试4: 扫描
for(int v=0; v<256; v=v+16) begin
audio_in = v;
repeat(64) @(posedge clk);
end
$display(" 扫描测试完成 ✓");
$display("Sigma-Delta DAC测试完成 ✓");
#100; $finish;
end
endmodule| 方案 | 精度 | 外部器件 | 带宽 | FPGA资源 |
|---|---|---|---|---|
| R-2R | 8位 | 8电阻+滤波 | 0~100kHz | 0 LUT |
| PWM | 8位等效 | 1RC滤波 | 0~1kHz | ~30 LUT |
| ΣΔ | 16位等效 | 1RC滤波 | 0~20kHz | ~50 LUT |
💡 低通滤波器:PWM和ΣΔ输出的1位信号需要RC低通滤波器还原模拟信号。截止频率 f_c = 1/(2πRC)。PWM选f_c≈5kHz,ΣΔ选f_c≈20kHz。R=1kΩ, C=10nF → f_c≈16kHz。
练习1:用PWM播放正弦波,用示波器观察输出
练习2:实现ΣΔ DAC + RC滤波,比较音质
练习3:设计4通道混音器,每通道独立音量控制
练习4:实现8位R-2R DAC,连接8个电阻
练习5:用混音器合成FM音色+背景音乐同时输出
步骤1:verilator --lint-only pwm_audio.v
步骤2:verilator --lint-only sigma_delta_dac.v
步骤3:verilator --lint-only audio_mixer.v
步骤4:verilator --binary -j 0 sigma_delta_dac.v sigma_delta_dac_tb.sv
步骤5:./obj_dir/Vsigma_delta_dac_tb
ΣΔ调制器的核心优势是噪声整形——把量化噪声推到高频,低通滤波后留下高质量音频。
PWM输出:FPGA PWM引脚 → R=1kΩ → C=100nF → 扬声器/耳机
ΣΔ输出:FPGA PDM引脚 → R=470Ω → C=10nF → 音频放大器 → 扬声器
R-2R DAC:8个GPIO → R-2R电阻网络(16个电阻) → 运放 → 扬声器
音频放大:推荐LM386或PAM8302,0.5~2W输出,3.3V供电
数字音频的核心参数是采样率和位深。根据奈奎斯特定理,采样率必须≥2倍最高频率。人耳20Hz~20kHz,所以CD用44.1kHz采样。
8位@8kHz:电话音质,够用但粗糙,NCO只需16位相位
8位@44.1kHz:CD采样率,8位量化噪音略明显
ΣΔ等效16位:过采样64倍,等效16位精度,音质接近CD
FPGA优势:可编程采样率和位深,实时切换无延迟
延迟(Delay):BRAM缓存→N毫秒后回放,echo效果
混响(Reverb):多段延迟+衰减,模拟空间反射
失真(Distortion):硬限幅/软限幅,电吉他效果
均衡(EQ):FIR滤波器,调节频段增益
| 参数 | PWM | ΣΔ 1阶 | ΣΔ 2阶 |
|---|---|---|---|
| 有效位数 | 7.2位 | 10.5位 | 14.2位 |
| SNR | 43dB | 65dB | 86dB |
| THD | -40dB | -55dB | -75dB |
| 带内噪声 | -42dB | -64dB | -85dB |
| 截止频率 | 5kHz | 20kHz | 20kHz |
| 过采样率 | 1 | 64 | 256 |
1. lint检查:verilator --lint-only pwm_audio.v sigma_delta_dac.v audio_mixer.v
2. 编译:verilator --binary -j 0 --trace sigma_delta_dac.v sigma_delta_dac_tb.sv
3. 运行:./obj_dir/Vsigma_delta_dac_tb
4. 查看波形:gtkwave sigma_delta_dac.vcd