基于FPGA的实时音频处理系统设计:从Verilog实现到仿真验证

二牛学FPGA
文章2026-04-26
74

Quick Start

  1. 在Vivado 2021.1中新建工程,器件选择xc7a35tcsg324-1(Artix-7)。
  2. 创建顶层模块top.v,例化I2S控制器、FIR滤波器与PWM输出模块。
  3. 编写I2S接收模块i2s_receiver.v,从WM8731编解码器接收24位立体声数据,采样率48 kHz。
  4. 实现16阶低通FIR滤波器fir_filter.v,系数采用汉明窗设计,截止频率8 kHz,直接型结构。
  5. 编写PWM输出模块pwm_output.v,将滤波后的16位音频数据转换为1位PWM信号,载波频率384 kHz(8×48 kHz)。
  6. 编写测试平台tb_top.v,生成48 kHz采样率的1 kHz正弦波测试激励,通过文本文件读写波形数据。
  7. 运行行为仿真(100 ms),观察i2s_data_outpwm_out波形,确认滤波后波形无混叠且幅度正确。
  8. 综合、实现,检查时序余量(setup slack > 0),生成比特流并下载至Nexys4 DDR板卡。
  9. 将耳机插入板载音频输出接口,播放1 kHz测试音,验证声音清晰无失真。
  10. 预期结果:仿真中滤波后波形平滑,上板后听到纯净1 kHz音调,无高频噪声。

前置条件与环境

项目推荐值说明/替代方案
器件/板卡Xilinx Artix-7 xc7a35tcsg324-1(Nexys4 DDR)其他Artix-7板卡(如Basys3)需调整引脚约束
EDA版本Vivado 2021.1Vivado 2019.1及以上均可,注意IP版本兼容
仿真器Vivado Simulator(xsim)ModelSim/Questa(需编译库)
时钟/复位板载100 MHz时钟,异步复位(低有效)可改用PLL生成12.288 MHz音频主时钟
接口依赖WM8731音频编解码器(I2S + I2C配置)其他I2S编解码器(如ADAU1361)需调整时序
约束文件XDC文件:定义时钟周期、I/O标准(LVCMOS33)、输入延迟手动编写或使用板卡官方约束模板
外设3.5 mm耳机/音箱,Micro-USB供电与下载线

目标与验收标准

  • 功能点:实现48 kHz采样率、16位量化、8 kHz低通滤波的实时音频处理,通过PWM驱动耳机输出。
  • 性能指标:FIR滤波器通带纹波<40 dB;PWM载波频率384 kHz,无 audible 噪声。
  • 资源消耗:LUT < 800,FF < 600,DSP48E1 < 20,BRAM < 2(基于xc7a35t)。
  • 时序约束:主时钟100 MHz,建立时间余量>0.1 ns,保持时间余量>0 ns。
  • 验收方式:仿真波形显示输入正弦波经滤波后高频分量被抑制;上板后播放1 kHz测试音,示波器测量PWM输出占空比变化与音频信号一致。

实施步骤

工程结构与顶层设计

// top.v - 顶层模块
module top (
    input wire clk_100m,
    input wire rst_n,
    // I2S接口(连接WM8731)
    input wire i2s_bclk,
    input wire i2s_lrclk,
    input wire i2s_din,
    output wire i2s_dout,
    // PWM输出(驱动耳机)
    output wire pwm_out
);
// 例化I2S接收、FIR、PWM模块
// 注意:时钟域划分:i2s_bclk域(I2S接收)、clk_100m域(FIR与PWM)
// 使用异步FIFO或双触发器同步跨时钟域信号
endmodule

工程结构src/(RTL文件)、sim/(测试平台)、constrs/(XDC约束)、ip/(如需PLL或FIFO IP)。

常见坑:I2S时钟(bclk)与系统时钟(100 MHz)不同源,必须做跨时钟域处理(双触发器同步或异步FIFO)。

排查:若仿真中数据错位,检查i2s_lrclk边沿对齐与数据位宽(24位 vs 16位)。

关键模块:I2S接收与发送

// i2s_receiver.v - I2S从机接收(左对齐24位)
module i2s_receiver (
    input wire bclk,
    input wire lrclk,
    input wire din,
    output reg [23:0] left_data,
    output reg [23:0] right_data,
    output reg data_valid
);
// 使用移位寄存器在bclk上升沿采集数据
// lrclk为低时左声道,高时右声道
// data_valid在24位接收完成后拉高一个bclk周期
endmodule

注意:WM8731默认格式为I2S(MSB对齐,左声道在lrclk下降沿后一个bclk开始),需根据数据手册调整移位时机。

常见坑:忘记处理lrclk边沿导致声道混淆;数据位宽不匹配(24位 vs 16位)导致截断或符号扩展错误。

排查:仿真中打印lrclkdin波形,检查数据对齐。

关键模块:FIR滤波器

// fir_filter.v - 16阶直接型低通FIR,系数对称
module fir_filter (
    input wire clk,
    input wire rst_n,
    input wire [15:0] data_in,
    input wire data_valid,
    output reg [15:0] data_out,
    output reg out_valid
);
// 系数(16个,使用signed 16位,Q1.15格式)
// 采用流水线加法树提高Fmax
// 每时钟处理一个乘法,16个周期输出一次结果
endmodule

原理:直接型结构,系数对称可减少乘法器数量(8个DSP48E1)。

时序:数据有效信号data_valid驱动状态机,每48 kHz采样率下滤波器有约2083个100 MHz时钟周期可用,无需流水线也可满足时序。

常见坑:系数未归一化导致输出溢出;乘法器位宽不足(建议32位累加后截断)。

排查:仿真中对比输入输出幅度,检查是否削顶。

关键模块:PWM输出

// pwm_output.v - 16位PWM调制器
module pwm_output (
    input wire clk,
    input wire rst_n,
    input wire [15:0] data_in,
    input wire data_valid,
    output reg pwm_out
);
// 计数器从0到65535循环,比较器输出
// data_in作为阈值,计数器小于阈值时pwm_out=1
// 载波频率 = clk / 65536 ≈ 1525 Hz(若clk=100 MHz)→ 不满足要求
// 改用8位PWM(载波384 kHz):计数器0~255,data_in高8位
endmodule

注意:16位PWM在100 MHz下载波仅1.5 kHz,会引入可听噪声;需降位宽至8位(384 kHz)或使用sigma-delta调制。

常见坑:PWM输出未加RC低通滤波导致高频噪声;占空比变化速率与音频采样率不匹配导致失真。

排查:示波器测量PWM波形,观察占空比是否随音频变化。

时序与约束

# top.xdc - 时序约束
create_clock -period 10.000 -name clk_100m [get_ports clk_100m]
set_input_delay -clock clk_100m -max 5.0 [get_ports i2s_bclk]
set_output_delay -clock clk_100m -max 4.0 [get_ports pwm_out]
# 异步时钟域约束(i2s_bclk到clk_100m)
set_clock_groups -asynchronous -group [get_clocks -include_generated_clocks clk_100m] -group [get_clocks -include_generated_clocks i2s_bclk]

常见坑:未声明异步时钟组导致Vivado分析错误路径,产生大量违例。

排查:综合后查看时序报告,关注setup/hold slack;若异步路径有违例,检查CDC同步器是否正确。

验证与仿真

// tb_top.v - 测试平台片段
initial begin
    // 生成1 kHz正弦波,采样率48 kHz,16位量化
    for (i = 0; i < 48000; i++) begin
        sample = $sin(2*3.14159*1000*i/48000) * 32767;
        #20833; // 48 kHz周期约20.833 μs
    end
end

仿真时长:至少100 ms(4800个采样点)以观察滤波效果。

验收点:滤波后波形无高频毛刺,幅度衰减符合预期。

排障指南

  • 仿真无输出:检查测试平台时钟与复位生成,确认rst_n在仿真开始时被释放。
  • 数据错位:核对I2S接收模块的移位时机与WM8731数据手册,确保lrclk边沿对齐正确。
  • PWM无变化:确认data_valid信号在滤波完成后被拉高,检查PWM计数器是否在正确频率下运行。
  • 上板后无声:检查XDC引脚约束与板卡原理图是否一致;用示波器测量PWM引脚是否有波形。
  • 时序违例:查看综合后时序报告,若异步路径有违例,确认CDC同步器(双触发器或异步FIFO)已正确例化。

扩展建议

  • 增加I2C配置:添加I2C控制器模块,在初始化时配置WM8731的采样率、增益等参数。
  • 多级滤波:级联多个FIR滤波器实现更陡峭的滚降特性,或切换不同系数实现均衡器功能。
  • Sigma-Delta调制:用二阶或三阶sigma-delta调制器替代PWM,降低带内噪声,提升音质。
  • 动态范围控制:加入AGC(自动增益控制)或限幅器,防止信号过载失真。
  • 多通道处理:扩展至多路音频输入输出,实现混音或空间音频效果。

参考与附录

  • WM8731数据手册(Cirrus Logic)
  • Vivado Design Suite User Guide: Synthesis (UG901)
  • Xilinx Artix-7 FPGA数据手册(DS181)
  • Nexys4 DDR板卡原理图与约束模板(Digilent)
  • 附录A:FIR滤波器系数生成脚本(MATLAB/Python)
  • 附录B:完整XDC约束文件示例

分类
技术分享
标签
fpgaVerilog实时音频处理
浏览 74
分享:

相关推荐

同频道 · 相近分类

暂无相关推荐

作者

二牛学FPGA查看主页

同分类阅读

文章

延伸阅读与实操

  • 文章 + 课程联动深度文章常对应体系课章节,可一键选课。
  • 学习产出可参考笔记与作业案例在学习产出广场持续更新。

探索全站