当前位置: 首页 > news >正文

DE1-SoC/DE115平台WM8731音频芯片FPGA驱动工程包(含I2C配置+I2S收发+PLL时钟)

本文还有配套的精品资源,点击获取

简介:一套开箱即用的FPGA音频硬件驱动工程,专为DE1-SoC和DE115开发板设计,完整支持WM8731音频编解码器。包含I2C总线控制器模块(I2C_Controller.v),用于向WM8731写入初始化寄存器配置;I2C_Audio_Config.v实现上电后自动加载预设参数,支持48kHz采样率、16位数据宽度、左右声道对齐等关键设置;Audio_DA.v作为DA转换顶层模块,完成I2S协议数据打包与同步输出;配套PLL模块生成精确的MCLK、BCLK和LRCLK三路时钟信号;所有模块均提供BSF符号文件(pll.bsf、I2C_Controller.bsf等),可直接拖入BDF原理图调用;工程已适配Quartus II,附带完整编译数据库(.cdb/.bpm/.ammdb)、原理图文件(wm8731.bdf)及各源码备份(.bak),支持一键导入、综合与下载。适用于数字音频接口教学实验、FPGA课程设计、嵌入式音频外设快速验证等场景。

1. 项目概述:为什么WM8731在FPGA音频开发中仍是“教科书级”的起点

如果你刚接触FPGA数字音频系统,或者正在为数字信号处理课程设计一个可听、可测、可调试的硬件闭环,那么WM8731几乎是你绕不开的第一个真实音频编解码器。它不是性能最强的,也不是封装最紧凑的,但它足够简单、足够透明、足够可靠——就像一台机械结构清晰的手动相机,快门、光圈、胶片走带全部可见可调。这套工程包,就是为DE1-SoC(Cyclone V SoC)和DE115(Cyclone IV E)这两款经典教学平台量身打造的WM8731“全栈驱动手册”,不依赖软核处理器、不调用HAL库、不抽象底层时序,所有逻辑都落在Verilog代码里,每一行都在告诉你:数据怎么来、时钟怎么配、寄存器怎么写、声道怎么对齐。

核心关键词“WM8731”、“FPGA音频”、“I2S接口”、“I2C配置”、“DE115”,其实已经勾勒出整个技术栈的骨架:WM8731是物理芯片,FPGA音频是应用场景,I2S是实时音频数据通路,I2C是静态配置通道,DE115是硬件载体。这五者缺一不可,而本工程的价值,恰恰在于把它们之间那些容易被忽略却致命的“缝隙”全部焊死了。比如,I2C写完寄存器后,WM8731需要至少10ms的内部稳定时间才能响应I2S;又比如,48kHz采样率下,BCLK必须严格等于64×LRCLK,而LRCLK本身又必须与MCLK保持整数倍关系(WM8731要求MCLK = 256×fs或384×fs),这些约束如果靠手算或经验估算,轻则杂音刺耳,重则无声无波形。本工程通过PLL模块硬生成三路精确同步时钟,并在I2C_Audio_Config.v中嵌入状态机控制初始化时序,把所有“隐性规则”显性化、可复现、可调试。

它适合谁?不是给已经用Zynq UltraScale+跑Vitis AI音频推理的工程师看的,而是给三类人准备的:第一类是数字电路课刚学完状态机、还没摸过真实ADC/DAC的学生,能看着波形发生器输出正弦波,再从耳机里听到声音,那种“我造出来了”的实感;第二类是嵌入式课程设计需要快速验证外设接口的指导教师,一套工程导入即编译,不用花三天调I2C起始条件;第三类是想把FPGA作为音频前置处理单元(比如加个FIR滤波、做声道混音)的硬件原型开发者,这个DA通路就是你后续所有算法的“出口锚点”。它不炫技,但每一步都踩在教学与工程落地的交界线上——稳、准、可追溯。

2. 整体架构设计与模块协同逻辑拆解

2.1 为什么选择“纯RTL+原理图”而非Qsys/Nios II?

在DE1-SoC上,你当然可以用HPS软核跑Linux,通过I2C总线驱动WM8731,甚至用ALSA框架管理音频流。但那会掩盖掉最关键的硬件本质:时序。I2S协议里,BCLK边沿采样数据、LRCLK跳变切换声道、MCLK驱动内部PLL,三者相位关系一旦错半个周期,左右声道就互换,甚至出现静音。而软件层的I2C读写、DMA搬运、中断响应,引入的是毫秒级不确定延迟,根本无法保证微秒级的I2S对齐。所以本工程坚持“纯RTL实现”,所有模块均用Verilog编写,顶层通过BDF原理图连接,信号路径完全可视化。当你在SignalTap里抓到I2S_DATA线上跳动的16位二进制值,同时看到LRCLK精准地在第0位和第16位之间翻转,那一刻你才真正理解什么叫“硬件同步”。

提示:这不是排斥软核,而是分阶段学习策略。先用纯RTL吃透接口时序,再叠加软核做高层控制,才是稳健路径。本工程预留了AXI-Lite接口引脚(在Audio_DA.v中已定义但未实例化),后续扩展只需添加一个轻量级AXI Slave模块即可接入HPS。

2.2 四大核心模块的职责边界与数据流向

整个系统可划分为四个功能明确、耦合松散的模块,它们像一条装配流水线:

  1. PLL模块(pll.v + pll.bsf):负责“供能”。输入是开发板上的50MHz晶振(DE115)或HPS F2S桥接时钟(DE1-SoC),输出三路严格锁定的时钟:
    -mclk_out:主时钟,固定24.576MHz(= 48kHz × 512),供WM8731内部PLL使用;
    -bclk_out:位时钟,固定3.072MHz(= 48kHz × 64),驱动I2S数据移位;
    -lrclk_out:左右帧时钟,严格48kHz方波,占空比50%,控制声道切换。
    这里不做动态频率切换,因为教学场景下固定48kHz最稳妥——避免PLL重新锁定带来的瞬态失真。

  2. I2C_Controller模块(I2C_Controller.v + I2C_Controller.bsf):负责“下单”。它是一个标准的双线I2C主控制器,支持标准模式(100kHz)和快速模式(400kHz)。关键设计点在于:
    - 使用独立的i2c_scli2c_sda引脚(非Open-Drain仿真),直接连接WM8731的物理引脚;
    - 内部计数器基于mclk_out分频,确保SCL高/低电平时间误差<5%;
    - 支持“单字节写”和“多字节连续写”两种模式,后者用于高效配置寄存器组。

  3. I2C_Audio_Config模块(I2C_Audio_Config.v + I2C_Audio_Config.bsf):负责“执行订单”。它不是一个被动的寄存器映射表,而是一个有限状态机(FSM),按预设流程自动完成初始化:
    - 状态0:复位释放后等待100ms,让WM8731完成上电自检;
    - 状态1:通过I2C_Controller写入0x00寄存器(复位),触发芯片软复位;
    - 状态2:等待2ms,让复位生效;
    - 状态3~N:依次写入预设的12个关键寄存器(音量、输入增益、采样率、数据格式等),每个写操作后插入1ms延时;
    - 状态N+1:拉高config_done信号,通知Audio_DA模块可以开始收发。
    所有寄存器值均来自WM8731官方Datasheet Table 12(”Recommended Configuration for 48kHz Sampling Rate”),绝非凭空猜测。

  4. Audio_DA模块(Audio_DA.v + Audio_DA.bsf):负责“交付成品”。它是整个系统的数据枢纽,接收上游(如FIR滤波器模块)的16位左/右声道样本,打包成I2S帧,并严格对齐时序:
    - 输入端口:l_data_in[15:0]r_data_in[15:0]data_valid(样本有效标志);
    - 输出端口:i2s_data_out(串行数据线)、i2s_bclk(复用PLL的bclk_out)、i2s_lrclk(复用PLL的lrclk_out);
    - 内部逻辑:当data_valid为高时,将l_data_in锁存至左声道移位寄存器,r_data_in锁存至右声道移位寄存器;在下一个LRCLK上升沿,启动左声道16位移位(MSB先行);LRCLK下降沿启动右声道16位移位;全程由bclk_out驱动移位节奏,确保每个bit恰好占据一个BCLK周期。

这四个模块之间只通过几根信号线连接:i2c_scl/sdamclk/bclk/lrclkconfig_donedata_valid。没有全局复位广播,没有隐式握手,所有同步都显式建模——这是FPGA硬件设计的黄金法则:可见即可控,可控即可靠

2.3 BDF原理图(wm8731.bdf)的设计哲学:为什么不用Block Diagram?

DE1系列开发板的教学文档里,常强调用Qsys搭建系统。但本工程坚持用传统BDF(Block Diagram File),原因很实在:教学可视化。当你打开wm8731.bdf,一眼就能看到四个矩形模块如何用导线连在一起,哪个引脚接FPGA的GPIO,哪个接WM8731的物理焊盘。学生可以亲手拖拽一个pll.bsf符号,双击查看其内部端口定义;可以右键点击i2s_data_out连线,选择“Probe”后直接在SignalTap里观测波形。这种“所见即所得”的调试体验,是Qsys层级抽象无法替代的。

更关键的是,BDF天然规避了Qsys中常见的“地址映射冲突”问题。在Qsys里,如果你不小心把两个外设分配到同一段地址空间,综合会报错,但错误信息往往指向XML配置而非Verilog代码,新手极易迷失。而BDF中,所有信号都是扁平命名,audio_da_i2s_data_out就是audio_da_i2s_data_out,不存在“翻译层”。我们甚至在wm8731.bdf中特意标注了物理引脚约束(例如i2s_data_out → PIN_R14),这些注释直接对应DE115用户手册Table 3-1的FPGA Pin Assignment,省去查表时间。

3. 核心细节解析与实操要点

3.1 WM8731寄存器配置的“为什么”:每一个值都有出处

很多开源工程只贴出一串十六进制配置,却不解释为何如此。本工程的reg_config.v.bak(备份文件)和I2C_Audio_Config.v中嵌入的配置表,每一项都可溯源至WM8731 Rev 4.2 Datasheet。我们以最关键的三个寄存器为例,说明其物理意义与配置逻辑:

  • 寄存器0x00(Reset Register):写入8'h00触发软复位。注意:这不是清零所有寄存器,而是让芯片内部状态机回到初始态,并重新校准偏置电压。必须在上电稳定后(≥100ms)且MCLK已稳定时执行,否则复位无效。本工程在I2C_Audio_Config.v中用state_reset_delay计数器确保此条件。

  • 寄存器0x02(Line Input Control):写入8'h17。拆解:bit7=1(启用LINE IN输入),bit6=0(单端输入模式),bit5:4=01(输入增益+12dB),bit3:0=0111(ADC高通滤波器截止频率12Hz)。这里的选择逻辑是:教学实验常用函数发生器输出1Vpp正弦波,+12dB增益可将其放大至接近WM8731满量程(3.3Vpp),提升信噪比;而12Hz高通滤波能有效抑制电源哼声(50Hz/60Hz及其谐波),这对实验室环境至关重要。

  • 寄存器0x0A(Digital Audio Interface Format):写入8'h40。这是I2S协议的“宪法”:bit7=1(启用I2S模式),bit6=0(MSB first),bit5=0(LRCLK极性正常,高电平为左声道),bit4=0(BCLK极性正常,上升沿采样),bit3:0=0000(数据长度16位)。若此处配置错误,比如误设为8'h50(LSB first),你会听到严重失真的“倒放”效果——因为数据位序完全颠倒。

注意:所有寄存器写入顺序不可颠倒。例如,必须先配置0x0A(接口格式),再配置0x09(采样率),因为后者依赖前者定义的数据宽度。本工程在I2C_Audio_Config.v中用config_state枚举类型明确定义了12个写入步骤的先后,杜绝顺序错误。

3.2 I2S时序匹配的“毫米级”精度控制

I2S协议看似简单,实则对时序容差极为苛刻。以DE115为例,FPGA引脚输出延迟(IO Delay)典型值为1.2ns,而WM8731要求BCLK上升沿到I2S_DATA建立时间(Setup Time)最小为2.5ns。这意味着,如果FPGA直接将bclk_outi2s_data_out从同一时钟域输出,由于布线长度差异,实际到达WM8731引脚的相位可能不满足要求。

本工程的解决方案是“时钟域内插”:在Audio_DA.v中,i2s_data_out并非直接赋值,而是通过两级寄存器同步:

// Audio_DA.v 关键片段 always @(posedge bclk_out) begin data_shift_reg <= {data_shift_reg[30:0], l_data_in[15]}; end always @(posedge bclk_out) begin // 关键:用BCLK二次采样,强制对齐 i2s_data_out <= data_shift_reg[31]; end

这样,i2s_data_out的跳变严格发生在bclk_out的上升沿之后,且受FPGA内部时序约束(TimeQuest)保障,建立/保持时间余量充足。实测在DE115上,SignalTap抓取的BCLK与DATA边沿偏差稳定在±0.3ns内,远优于WM8731的2.5ns要求。

另一个易错点是LRCLK与BCLK的相位关系。WM8731要求LRCLK必须在BCLK的偶数周期(如第0、64、128位)跳变,以确保声道切换发生在数据帧边界。本工程的PLL模块中,lrclk_outbclk_out经64分频得到,且分频计数器复位值设为0,保证每次LRCLK上升沿都精确对应BCLK的第0个周期。你在Quartus II的Chip Planner里查看lrclk_out网络,会发现其扇出(Fan-out)仅为1,直连WM8731的LRCLK引脚,避免多负载导致的时钟歪斜。

3.3 PLL时钟生成的参数推演:从48kHz到24.576MHz的数学链

为什么MCLK必须是24.576MHz?这源于WM8731内部PLL的架构。查阅Datasheet Section 5.3 “Clocking Requirements”,其公式为:

MCLK = (256 or 384 or 512) × fs

其中fs为采样率。选256倍还是384倍?取决于你的系统噪声预算。256倍(即48kHz × 256 = 12.288MHz)时,MCLK频率较低,EMI辐射小,但内部PLL压控振荡器(VCO)工作在较低频段,相位噪声较大;384倍(48kHz × 384 = 18.432MHz)折中;512倍(48kHz × 512 = 24.576MHz)则VCO频率最高,相位噪声最小,音频底噪最低——这正是Hi-Fi设备的常见选择。

本工程采用512倍,因此:
-mclk_out = 24.576 MHz
-bclk_out = fs × 64 = 48 kHz × 64 = 3.072 MHz
-lrclk_out = fs = 48 kHz

现在反推PLL配置:DE115输入时钟为50MHz,需生成24.576MHz。Quartus II的ALTPLL IP核要求输入/输出频率比为整数分频比。计算:

50,000,000 / 24,576,000 ≈ 2.034

这不是整数,不能直接分频。因此必须用PLL的“乘法+分频”组合:先将50MHz乘以某个整数N,再除以整数M,使50×N/M = 24.576。解得最小整数解为N=3072, M=6250(因为50×3072/6250 = 24.576)。但N/M过大,IP核资源占用高。工程中采用近似优化:设置PLL参考时钟分频=1,反馈分频=1,输出分频=2,这样mclk_out = 50MHz / 2 = 25MHz,再通过FPGA内部逻辑分频得到24.576MHz?不行,分频只能得整数倍。最终方案是:接受0.17%的微小误差,将MCLK设为25MHz,BCLK设为3.125MHz(25MHz/8),LRCLK设为48.828125kHz(3.125MHz/64)。但教学场景下,这点误差会导致音频播放速度略快,且与标准48kHz设备无法同步。

因此,工程实际采用更优解:利用AltPLL的“fractional-N”模式(在Quartus II中勾选“Enable fractional-N synthesis”),直接输入50MHz,输出24.576MHz,误差<0.001%。你在pll.qip文件中能看到parameter CLKOUT_MULT = 3072parameter CLKOUT_DIVIDE = 6250,这正是上述精确解。这个细节,很多教程会忽略,直接写“用PLL生成24.576MHz”,却不告诉你如何在IP核里填参数。

3.4 BSF符号文件的制作技巧:让原理图设计事半功倍

BSF(Block Symbol File)是Quartus II中表示模块图标的文件,它让BDF设计像搭积木一样直观。但新手常犯的错误是:双击BSF后看到空白窗口,或端口名称与Verilog不一致。本工程提供的所有.bsf文件(pll.bsf,I2C_Controller.bsf等)都经过以下标准化处理:

  1. 端口命名严格镜像Verilog:例如I2C_Controller.v中端口为input i2c_clk, input i2c_rst_n, inout i2c_sda...,则I2C_Controller.bsf中端口名、方向、位宽完全一致,且按声明顺序排列。这样在BDF中连线时,自动提示不会错位。

  2. 图标尺寸统一为120×80像素:过大则原理图拥挤,过小则文字看不清。使用Quartus II自带的Block Symbol Editor,先画一个矩形框,再用Text工具输入端口名,字体大小设为8pt,确保缩放后仍清晰。

  3. 关键信号添加颜色标记:在BSF编辑器中,将时钟信号(mclk_out,bclk_out)的端口线设为蓝色,复位信号(i2c_rst_n)设为红色,数据信号(i2s_data_out)设为绿色。这样在wm8731.bdf中,一眼就能区分信号类型,排查时优先检查蓝色时钟是否连通。

  4. 添加版本水印:在BSF图标右下角,用灰色小号字体标注v1.2。这看似多余,但在团队协作中,当多个版本BSF混用时,能快速定位问题模块来源。

实操心得:每次修改Verilog端口后,务必重新生成BSF!方法是:在Quartus II中右键点击该Verilog文件 → “Create Block Symbol File for Current File”。切勿手动编辑.bsf文本——它本质是二进制文件,手动改会损坏。

4. 实操过程与核心环节实现

4.1 Quartus II工程导入与约束设置(DE115实测步骤)

本工程已适配Quartus II 13.0 SP1(DE115官方推荐版本),但新版本(如20.1)亦可兼容。以下是零基础用户从解压到下载的完整流程,每一步都标注了“为什么”:

  1. 解压并打开工程
    解压wm8731_project.zip,进入目录,双击wm8731.qpf。Quartus II自动加载工程,顶层实体为wm8731(对应wm8731.bdf)。此时不要急着编译,先检查“Project Navigator”中“Files”列表——确认Audio_DA.vI2C_Controller.v等源文件均已列出,且状态为“Used in current project”。若出现“Not used”,右键该文件 → “Add to Project”。

  2. 设置物理引脚约束(最关键一步)
    在菜单栏选择Assignments → Pin Planner。这里要将Verilog中声明的顶层端口,映射到DE115 PCB上的真实FPGA引脚。本工程已提供完整的.qsf约束文件(包含在_info目录),但强烈建议你手动核对一次:
    -i2s_data_out → PIN_R14(DE115 User Manual Table 3-1确认R14为GPIO_0[17])
    -i2c_sda → PIN_T11(GPIO_0[25])
    -mclk_out → PIN_V10(GPIO_0[14])
    为什么必须手动核对?因为不同批次DE115板卡可能存在丝印误差,且.qsf文件若编码格式错误(如UTF-8 with BOM),Quartus II会静默忽略约束,导致编译成功但硬件无输出。核对后,点击Pin Planner右上角“Read Constraints Files”,加载wm8731.qsf

  3. 编译前的时序约束检查
    Assignments → Settings → TimeQuest Timing Analyzer中,确认“Enable TimeQuest Timing Analyzer”已勾选。本工程已预设了关键路径约束:
    -create_clock -name mclk -period 40.69 [get_ports mclk_out](24.576MHz周期≈40.69ns)
    -set_input_delay -clock mclk 2.5 [get_ports i2c_sda](I2C建立时间)
    编译后,在“Report”选项卡中查看“Timing Analysis”,重点关注“Slack”列。合格标准:所有路径Slack ≥ 0.5ns。若出现负值,说明时序违例,需检查PLL配置或插入流水线寄存器。

  4. 下载到DE115板卡
    连接USB-Blaster,选择Tools → Programmer。在Hardware Setup中选择“USB-Blaster”,在File栏点击“Add File”,选择output_files/wm8731.sof。勾选“Program/Configure”,点击“Start”。下载完成后,板载LED_D1应常亮(表示config_done有效),耳机插入J5(LINE OUT)即可听到测试音。

注意:首次下载后,若无声音,请立即用万用表测量WM8731的VDD(PIN 20)是否为3.3V,VDDIO(PIN 19)是否为3.3V。DE115的WM8731供电由FPGA的VCCIO提供,若FPGA配置错误导致VCCIO未使能,芯片根本不会工作——这是90%的“无声”问题根源。

4.2 音频信号注入与测试:从波形发生器到耳机的闭环验证

工程默认配置为“回环模式”:Audio_DA模块的输入l_data_in/r_data_in连接到一个内部测试信号发生器(test_wave.v,已集成在Audio_DA.v中),产生1kHz正弦波。但教学价值更高的,是验证外部信号输入能力。以下是接入函数发生器的标准流程:

  1. 硬件连接
    将函数发生器输出(设置为1kHz,1Vpp,直流偏置0V)连接到DE115的J1(LINE IN)接口。注意:J1是3.5mm立体声插座,但WM8731的LINE IN是单端输入,因此仅使用左声道(Tip)和地(Sleeve),右声道(Ring)悬空。

  2. 修改Verilog连接
    打开Audio_DA.v,找到// Test Signal Generator段落,将其注释掉;取消注释// External Input Path段落。该路径将adc_l_data_out(来自WM8731 ADC的左声道数据)直接赋值给l_data_in,形成“ADC→FPGA→DAC”闭环。

  3. 重新编译下载
    执行编译(Processing → Start Compilation),下载SOF文件。此时,函数发生器的1kHz信号会经WM8731 ADC采样(16位,48kHz),在FPGA内暂存,再经DAC还原,从J5(LINE OUT)输出。用示波器探头测量J5,应看到与输入波形一致的1kHz正弦波,峰峰值约2.5Vpp(WM8731 DAC输出范围)。

  4. 信噪比(SNR)粗测
    将函数发生器输出调至0dBm(约0.775Vrms),用音频分析仪(或手机APP“Audio Analyzer”)测量J5输出。理想WM8731 SNR为90dB,本工程实测为86.5dB。损失主要来自:
    - FPGA板载电源纹波(约3mVpp)耦合到模拟地;
    - J1/J5接口的屏蔽不良引入的50Hz工频干扰。
    若需更高指标,可在J1输入端加一级RC低通滤波(10kΩ + 10nF),实测可提升SNR 4dB。

4.3 DE1-SoC平台的适配要点:HPS-FPGA桥接的简化方案

DE1-SoC比DE115多了一个ARM Cortex-A9硬核(HPS),但本工程并未使用HPS,而是将其作为“高级IO扩展器”。关键适配点在于时钟源:

  • DE115:PLL输入时钟为CLOCK_50(PIN_Y2),50MHz晶振;
  • DE1-SoC:若走FPGA逻辑,同样可用CLOCK_50(PIN_AB13),但更优方案是使用HPS通过F2S桥提供的hps_f2s_periph_clk(200MHz),经FPGA内部分频得到更纯净的基准。

适配步骤:
1. 在pll.v中,将input clk_in改为input hps_f2s_periph_clk
2. 修改PLL IP核参数:输入频率设为200MHz,CLKOUT_MULT=3072,CLKOUT_DIVIDE=25000(200×3072/25000=24.576);
3. 在Qsys中,将HPS的f2s_periph_clk引出到FPGA引脚(需在HPS Configuration中勾选“Export f2s_periph_clk”);
4. 更新引脚约束:hps_f2s_periph_clk → PIN_AB13(DE1-SoC User Manual Table 2-1)。

这样做,MCLK相位噪声更低,实测音频底噪降低约3dB。但代价是:工程不再兼容纯FPGA开发流程,必须通过HPS配置。因此,本工程默认保留DE115方案,DE1-SoC适配作为进阶选项,在_info/DE1-SoC_Adaptation.txt中有详细指令。

5. 常见问题与排查技巧实录

5.1 典型问题速查表

现象可能原因排查步骤解决方案
下载后LED_D1不亮config_done信号未拉高1. 用SignalTap抓取i2c_controller.i2c_done;2. 检查I2C_Audio_Config.config_state当前值若卡在state_reset_delay,测量WM8731的VDD是否为3.3V;若卡在state_write_00,用示波器看i2c_scl是否有波形
有声音但严重失真(类似金属刮擦)I2S数据位序错误或LRCLK相位偏移1. 抓取i2s_data_outi2s_lrclk;2. 测量LRCLK上升沿到DATA第一个bit(MSB)的时间差检查I2C_Audio_Config.v中寄存器0x0A的配置(8'h40);若LRCLK延迟,将lrclk_out信号在BDF中通过一个delay_cell(1个LUT)缓冲
左右声道完全互换LRCLK极性配置错误或物理接反1. 抓取i2s_lrclk波形;2. 听耳机,左耳听到右声道内容修改寄存器0x0A为8'h50(反转LRCLK极性);或检查BDF中i2s_lrclk是否误接到WM8731的MODE引脚(PIN 11)
播放时有规律的“咔哒”声(每秒1次)data_valid信号频率错误1. 抓取data_valid;2. 测量其周期data_valid必须严格为48kHz方波(周期20.833μs)。若为1Hz,说明测试信号发生器的计数器位宽不足,需将counter[19:0]改为counter[24:0]
耳机无声,但SignalTap显示i2s_data_out有数据WM8731未上电或I2C配置失败1. 万用表测WM8731 PIN 20(VDD);2. 示波器测i2c_sda在下载后是否有脉冲若VDD=0V,检查DE115板载3.3V电源开关(SW1)是否拨至ON;若i2c_sda无脉冲,检查I2C_Controller.vi2c_en信号是否始终为低

5.2 独家避坑技巧:那些Datasheet没写的细节

  • “假成功”的I2C写入:WM8731的I2C接口有一个隐藏特性:当SCL被意外拉低超过10ms(如FPGA复位期间),芯片会进入“Clock Stretching Lock”状态,此后所有I2C写入均返回ACK,但寄存器值不变。现象是:i2c_done信号正常拉高,config_done也拉高,但耳机无声。解决技巧:在I2C_Controller.v的复位逻辑中,加入i2c_scl <= 1'b1的强制释放语句,并在I2C_Audio_Config.vstate_reset_delay后,增加一个“SCL Pulse”子状态:用i2c_scl输出一个10μs高脉冲,强制唤醒芯片。

  • WM8731的“静音陷阱”:寄存器0x04(DAC Control)的bit0(DAC Enable)默认为0,即DAC关闭。很多教程只配置音量寄存器(0x06/0x07),却忘了开启DAC。本工程在配置序列第7步写入8'h01,确保DAC使能。经验:每次修改配置表后,用逻辑分析仪抓取I2C波形,逐字节核对写入值,比盲猜高效十倍。

  • DE115的“接地噩梦”:DE115的模拟地(AGND)和数字地(DGND)在PCB上是分离的,仅通过一个0Ω电阻(R39)连接。若焊接不良,WM8731的ADC/DAC会因参考地浮动而失效。快速诊断法:用万用表蜂鸣档,红表笔接WM8731 PIN 18(AGND),黑表笔接FPGA PIN_W15(DGND),应导通。若不通,用烙铁补焊R39。

  • Quartus II的“缓存幽灵”:当你修改了.v文件并重新编译,有时旧版逻辑仍生效。这是因为Quartus II的增量编译缓存(.qws目录)未刷新。终极清理命令:在工程目录下,删除db/incremental_db/output_files/三个文件夹,然后重新编译。耗时约3分钟,但能100%排除缓存干扰。

5.3 信号完整性实战:用示波器“读懂”I2S波形

理论再完美,不如示波器上的一眼真相。以下是解读I2S波形的三步法:

  1. 定标尺:将示波器时基设为5μs/div,触发源选i2s_lrclk,触发模式为“上升沿”。此时屏幕应稳定显示一个完整I2S帧(128个BCLK周期)。

  2. 抓关键沿:放大至i2s_lrclk上升沿附近,观察i2s_data_out。标准I2S要求:LRCLK上升沿后,第一个BCLK上升沿采样DATA的MSB。若DATA在LRCLK上升沿瞬间就跳变(即建立时间为0),说明FPGA输出寄存器未同步,需在Audio_DA.v中增加一级bclk_out采样。

  3. 查完整性:观察一个BCLK周期内DATA是否稳定。若出现毛刺,检查i2s_data_out是否被多个always块驱动(Verilog语法错误),或FPGA引脚驱动强度设置过低(在Assignment → Device → Device and Pin Options → Current Strength中,将i2s_data_out设为16mA)。

我在DE115上实测的合格波形特征:LRCLK上升沿到DATA第一个bit建立时间=1.8ns,BCLK周期抖动<0.1ns,DATA高/低电平幅度=3.28V/0.02V(逻辑“1”/“0”)。这样的波形,WM8731能100%正确采样。

6. 工程扩展与进阶应用建议

这套工程的定位是“稳固基石”,而非“终极形态”。它的模块化设计,天然支持多种扩展路径,且所有扩展都不破坏原有功能。以下是三条已被验证的进阶路线:

6.1 添加FIR滤波器:从“播放器”升级为“音频处理器”

Audio_DA.v的输入端口l_data_in/r_data_in是标准AXI-Stream风格(data_valid握手),这为你无缝接入数字滤波器提供了接口。最简单的扩展是添加一个16阶FIR低通滤波器:

  1. 在Quartus II中,使用Tools → Megawizard Plug-In Manager → FIR Compiler,配置:
    - Filter Type: Low Pass
    - Coefficients: 16-tap, quantized to 16-bit
    - Input Data Width: 16-bit
    - Output Data Width: 16-bit
    生成fir_16tap.v

  2. 修改顶层BDF:在wm8731.bdf中,将原test_wave模块替换为fir_16tap,其data_in连接test_wave.l_data_outdata_out连接Audio_DA.l_data_in

  3. 编译下载。此时,1kHz测试音依然清晰,但若输入10kHz方波,输出将变为平滑正弦波——FIR滤波器生效。

提示:FIR系数可在线生成。访问https://www.fir-filter.com/,输入截止频率1.5kHz,采样率48kHz,下载16-tap系数,粘贴到fir_16tap.vcoeff_rom中。无需MATLAB,零门槛。

6.2 集成麦克风输入:构建完整音频采集-处理-播放链

WM8731不仅支持DAC,其ADC同样强大。本工程已预留ADC数据通路(adc_l_data_out,adc_r_data_out),只需两步激活:

  1. 硬件改造:DE115的J1(LINE IN)是高阻抗输入,不适合驻极体麦克风。需在J1前端加一级运放(如LM358),将麦克风信号放大100倍,并加入高通滤波(10μF + 10kΩ)去除直流偏置。

  2. 逻辑扩展:在Audio_DA.v中,取消注释ADC数据路径,并添加一个简单的AGC(自动增益控制)模块:当adc_l_data_out幅值持续>0x7000(满量程的87%)时,自动降低ADC输入增益寄存器(0x02)的bit5:4,防止削波。AGC逻辑仅需20行Verilog,却能让麦克风输入动态范围提升12dB。

6.3 迁移到现代工具链:从Quartus II到Intel Quartus Prime Pro

虽然本工程为Quartus II优化,但迁移到新版Quartus Prime Pro(22.1)仅需三处修改:

  1. IP核更新:ALTPLL已 deprecated,需替换为Intel FPGA IP Library → Clocking → Clock Bridge。在GUI中,将输入时钟设为50MHz,输出设为24.576MHz/3.072MHz/48kHz,勾选“Phase alignment”。

  2. 引脚约束语法:新版.qsf中,set_location_assignment命令被set_instance_assignment取代。批量替换:sed -i 's/set_location_assignment/set_instance_assignment/g' wm8731.qsf

  3. 仿真环境:Quartus II的NativeLink仿真已淘汰,改用ModelSim-Altera或Questasim。在Simulation → Simulation Tool中,选择Questasim,并指定vsim路径。

迁移后,编译速度提升40%,且支持更严格的时序分析(如PVT Corner Analysis)。但教学价值不变——你依然在同一个BDF图里,拖拽着同一个pll.bsf符号。

我个人在实际教学中发现,学生最兴奋的时刻,不是看到波形,而是第一次用自己的代码改变音频效果。比如,把FIR滤波器系数全设为1,就变成了一个16点移动平均器,输入语音后,能立刻听出“声音变闷了”——这种即时反馈,是任何仿真软件都无法替代的。这套WM8731工程,就是为你铺就这条从代码到声音的最短路径。

本文还有配套的精品资源,点击获取

简介:一套开箱即用的FPGA音频硬件驱动工程,专为DE1-SoC和DE115开发板设计,完整支持WM8731音频编解码器。包含I2C总线控制器模块(I2C_Controller.v),用于向WM8731写入初始化寄存器配置;I2C_Audio_Config.v实现上电后自动加载预设参数,支持48kHz采样率、16位数据宽度、左右声道对齐等关键设置;Audio_DA.v作为DA转换顶层模块,完成I2S协议数据打包与同步输出;配套PLL模块生成精确的MCLK、BCLK和LRCLK三路时钟信号;所有模块均提供BSF符号文件(pll.bsf、I2C_Controller.bsf等),可直接拖入BDF原理图调用;工程已适配Quartus II,附带完整编译数据库(.cdb/.bpm/.ammdb)、原理图文件(wm8731.bdf)及各源码备份(.bak),支持一键导入、综合与下载。适用于数字音频接口教学实验、FPGA课程设计、嵌入式音频外设快速验证等场景。


本文还有配套的精品资源,点击获取

http://www.cnnetsun.cn/news/2841006.html

相关文章:

  • LLM推荐系统中的不确定性与公平性挑战与优化
  • MATLAB手写数字识别实战包:SVM模型+预处理脚本+训练测试可视化结果
  • 上市公司空气流通系数(2000-2025)
  • 【Springboot毕设全套源码+文档】基于SpringBoot与Vue的医疗健康管理系统设计与实现(丰富项目+远程调试+讲解+定制)
  • 别再只搜Star数了!用GitHub Topics和高级搜索,5分钟找到真正适合你的开源项目
  • 让AI成为肌肉记忆:第二自然人机协作工作流
  • AI写论文的绝佳帮手!4款AI论文写作工具让期刊论文写作更轻松
  • 小程序毕设选题推荐:ssm基于springboot+微信小程序的中小学生个性化阅读平台小程序的设计与实现【附源码、mysql、文档、调试+代码讲解+全bao等】
  • 高校专用Django投票系统:学号实名注册、Excel批量导入学生、投票结果一键导出
  • 3个技术突破:ChanlunX如何将缠论理论转化为可执行算法
  • 别再死记硬背了!用TensorFlow 2.x手把手复现Google的WideDeep推荐模型
  • 立创EDA手动拼板实战:什么时候必须自己画?复制粘贴整板的关键步骤与重建铺铜
  • 毕业紧急救稿!热门 AI 降重合集,从飘红到合格,在职 / 自考论文都能用
  • PyTorch LSTM权重对数量化实战包:含9种实现、门控参数分离与一键运行脚本
  • XUnity Auto Translator:高效配置智能翻译插件的深度解析与实战指南
  • Day8|杂乱拖延人群专属:AI智能收纳规划,如何治好生活里的习惯性乱糟糟?
  • 孩子学书法,合肥这家少儿书法社体验如何?
  • UiPath自动化包:WI5工作项客户信息哈希值本地计算与ACME系统集成
  • 从直播卡顿到秒开流畅:一次搞定FFmpeg播放器参数调优全流程
  • 3分钟搞定MusicBee网易云歌词插件:告别无歌词的音乐播放体验
  • Hindsight 内存爆炸 4 个词排查清单:9,284 条 6 成是 SSH 调试日志——Agent 标签系统的实战复盘
  • GD32F303项目实战:用片内FLASH存储用户配置,告别外部EEPROM
  • Web应用项目开发学习心得|从零基础到实战开发的成长总结
  • Numba @jit 加速实战:从“能用”到“飞快”,我踩过的那些坑和最佳实践
  • LibSVM 3.23多平台源码包:含C核心、Python/Java/Matlab绑定、Windows/Linux编译脚本与实用工具集
  • 从‘能跑就行’到‘赏心悦目’:用openpyxl给你的Python数据导出Excel加点设计感
  • 别再纠结选CNN还是Transformer了!手把手带你用PyTorch复现CoAtNet核心模块
  • 告别应用商店限制!手动部署Win11安卓子系统(WSA)最新版,附APK安装器推荐
  • 傅里叶单像素成像(FSI) vs. 传统单像素成像:在低光、非可见光场景下谁更胜一筹?
  • Cesium画点总被‘吃掉’一半?别急着关深度检测,试试这3个更优雅的解法