ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

ES8311音频Codec时钟树配置详解:MCLK、PLL与分频计算实战

ES8311音频Codec时钟树配置详解:MCLK、PLL与分频计算实战 做嵌入式音频项目最容易被忽略又最让新人头疼的就是 codec 的时钟树配置。ES8311 这颗低功耗音频编码芯片我前后在三个项目里用过每次出问题几乎都出在时钟上有时是播放变调有时是录音带噪声查到最后都是分频系数不对。这篇文章就把 ES8311 的时钟树配置和分频计算一次讲透从 MCLK 到内部 ADC/DAC 时钟再到 I2S 的 BCLK/LRCK全部用实际算例走一遍。如果你是刚接触音频 codec 的嵌入式开发或者已经在用 ES8311 但还在靠抄别人的初始化数组碰运气这篇应该能帮你把“为什么这么配”这块补上。看完之后拿到一块新板子、一个非常规 MCLK 频率你也能自己算出来该怎么写寄存器。1. 先看懂ES8311的时钟拓扑MCLK从哪来、分频到哪去1.1 MCLK到内部时钟树的三段路径ES8311 的时钟系统说简单很简单说复杂也挺复杂关键是看你从哪个粒度去理解。我习惯把它拆成三段看第一段是外部输入的 MCLK这颗芯片的 MCLK 通常由主控 SoC 提供常见频率有 12.288MHz、24.576MHz、22.5792MHz、11.2896MHz也有直接给 19.2MHz 或 13MHz 这种非音频专用晶振的系统。MCLK 进来之后不是直接拿去用而是要经过一段“时钟管理”逻辑决定是走 PLL 还是走直通。第二段是芯片内部的时钟源选择。ES8311 允许你选择直接从 MCLK 分频得到 ADC/DAC 的工作时钟也允许先把 MCLK 送进内部 PLL倍频/分频到一个更合适的频率然后再分频。这一步是时钟树配置的核心也是大多数人抄初始化数组却不知道所以然的地方。第三段是分频输出。从 PLL 或 MCLK 得到的那个“干净”的高频时钟会被分配到 ADC 时钟路径和 DAC 时钟路径经过各自的分频器最终变成 ADC 调制器、DAC 调制器和数字滤波器的时钟。弄懂这三段后面对各种配置就会清晰很多。很多人出问题就是因为直接把三段混在一起以为只要设一个 MCLK 频率就完事了。实际上ES8311 手册里时钟相关的寄存器之所以有那么多位域正是因为三段路径分别可配。1.2 从机模式与主机模式下分频责任在哪里还有一个很容易踩坑的点ES8311 在 I2S 总线上可以工作在从机模式也可以工作在主机模式。这两种模式下BCLK 和 LRCK 的产生方式完全不同时钟配置的关注点也不一样。从机模式下BCLK 和 LRCK 由主控 SoC 提供ES8311 只需要在外部 MCLK 的帮助下产生自己 ADC/DAC 内部需要的工作时钟。也就是说LRCK 的频率就是采样率 fs这个 fs 是主控给的ES8311 内部时钟树要做的是保证 MCLK 分频出来的一路时钟能在时序上稳定地和 BCLK/LRCK 匹配。此时你在寄存器里配的 ADC/DAC 分频主要影响的是内部调制器工作频率而不是直接决定 LRCK。主机模式下ES8311 自己产生 BCLK 和 LRCK 输出给外部 Codec 或 MCU。这时MCLK 或 PLL 的输出频率就必须分频得到准确的 BCLK 和 LRCK。比如你要输出 48kHz 采样率、32bit 槽位的 I2S 数据BCLK 应该是 48kHz × 64 3.072MHzLRCK 就是 48kHz。这些都需要靠内部时钟树精确分频得到。很多项目里ES8311 默认配置成从机模式结果有人拿了一份“主机模式”的初始化代码去改改了半天下不来。所以拿到一个配置表先搞清楚它的 I2S 主从模式是什么再讨论分频计算才有意义。1.3 抓住一个核心等式所有分频都在为 fs 服务无论从机还是主机也不管开不开 PLLES8311 的时钟树最终目的只有一个让 ADC 和 DAC 的工作时钟与采样率 fs 保持严格的倍频关系。数字音频系统里fs 就是采样率比如 48000Hz、44100Hz。ADC 调制器和数字滤波器通常需要工作在 fs 的整数倍上比如 64 倍、128 倍、256 倍、512 倍。这个倍数关系一旦不是整数音频数据就会产生采样点错位表现就是变调、杂音、或者两个字难听。所以你拿到一个 MCLK 频率后最开始要做的不是翻寄存器而是算一个除法MCLK / fs。如果结果是 256、512、1024 这类支持的值直通就行如果不是那就要考虑启用 PLL或者干脆换一颗合适的 MCLK。2. 不开PLL的直通路径MCLK整除采样率时的计算2.1 什么时候能走直通ES8311 的 PLL 不是必须要开。如果你的系统 MCLK 已经是音频领域的标准频率比如 12.288MHz、24.576MHz、11.2896MHz、22.5792MHz那这些频率和常用的 48kHz、44.1kHz 采样率之间天然就是整数倍关系完全可以关闭 PLL直接走 MCLK 分频路径。这样做的好处很明显省电启动快时钟抖动也更小。PLL 本质上是一个反馈环路从锁定到稳定需要时间而且是额外的功耗来源。对于 ES8311 这种主打超低功耗的芯片能不开 PLL 就不开这是我在实际项目里的一个原则。判断能不能直通最简单的办法就是做除法同时确认倍数在芯片支持的范围内。ES8311 手册里通常会给出一个很直观的表格列出不同 MCLK 频率和不同采样率下可以配置的倍率关系但核心逻辑就是那一个。2.2 实例12.288MHz MCLK配48kHz采样拿最常见的组合来算MCLK 12.288MHz目标 fs 48kHz。除一下12,288,000 / 48,000 256。这个 256 意味着芯片可以从 MCLK 直接分频得到 ADC/DAC 工作时钟而不需要 PLL 参与。很多 codec 方案里256fs 是 ADC/DAC 调制器的一个标准工作频率ES8311 也不例外。如果系统里 I2S 是 16bit 双声道BCLK 通常是fs × 32 1.536MHz如果 I2S 按 32bit 槽位发BCLK 就是fs × 64 3.072MHz。这些 BCLK 频率也都是从同一个 MCLK 分频出来的比如 12.288MHz / 8 1.536MHz12.288MHz / 4 3.072MHz分频关系非常干净。所以在直通模式下你只需要把“MCLK 分频到 ADC/DAC 时钟”的分频系数配对再把 I2S 格式配对整个音频链路就能跑起来。我见过很多初始化数组里写 PLL 配置的机会其实根本用不上那里面的 PLL 参数全是无效配置。2.3 不能整除的场景识别反过来如果你拿到的 MCLK 是 12MHz想配 48kHz除法结果是12,000,000 / 48,000 250。250 虽然也是整数但通常在 ES8311 的直通分频路径里并不支持这种任意整数倍而且 250 和 256 差一点直接把 MCLK 当作 12.288MHz 去配置最终实际采样率会变成12,000,000 / 256 46,875Hz也就是 46.875kHz。这种问题非常隐蔽因为代码逻辑上看起来“一切正常”I2C 写入成功寄存器回读正确I2S 信号也有但播放出来的声音就是比正常慢一点点音调偏低。如果你用频率计去量 BCLK会发现它也不是标准的 1.536MHz而是偏低的频率。所以我的建议是拿到一个 MCLK先别急着写代码花五分钟把各种可能采样率下的MCLK / fs算一遍看看结果是不是 256、512 这种规整的数。不是的话直接进入 PLL 方案不要在直通路径上硬配。3. PLL场景的完整算例19.2MHz MCLK生成48kHz时钟3.1 PLL参数与公式拆解很多主控平台不会专门给音频 codec 一颗 12.288MHz 的晶振而是共用系统主晶振比如 19.2MHz、24MHz、26MHz。这时候就要依靠 ES8311 内部 PLL把 MCLK 转换成一个和 fs 有整数倍关系的工作时钟。PLL 的基本思想是先把输入频率分频到一个比较小的值也就是“参考频率”然后再通过倍频环路乘上一个系数得到输出频率。通用的公式可以写成f_pll_out f_mclk × N / M其中 M 是输入分频系数N 是倍频系数。实际芯片里可能还有额外的输出分频、后分频等但核心逻辑就是通过一组整数比例让输出频率落在期望的音频时钟频率上。一个特别要注意的坑很多芯片寄存器里的 M、N 字段存的是“减一”后的编码值。比如你算出来 M 25寄存器里可能写的是 24也就是 0x18。所以我每次拿到一个新 codec都会先去看手册的寄存器描述确认是“直接值”还是“编码值”否则写进去的配置频率可能整整差了一倍或者差一个计数。3.2 算例19.2MHz到24.576MHz的整数分频组合我选一个真实项目里用过的组合来演示MCLK 19.2MHz目标 fs 48kHz。先定目标。ES8311 内部 ADC/DAC 工作时钟比较常用的一个档位是 512fs也就是512 × 48,000 24,576,000Hz即 24.576MHz。我们要做的就是让 PLL 输出 24.576MHz。计算倍频比f_pll_out / f_mclk 24.576MHz / 19.2MHz 1.281.28 换算成分数就是128 / 100 32 / 25。这就好办多了直接用 M 25、N 32 就能得到19.2MHz × 32 / 25 24.576MHz这个组合非常漂亮因为 25 和 32 都是常规分频器能处理的整数。如果你觉得 VCO 工作在 24.576MHz 偏低担心超出 PLL 锁相环的 VCO 范围可以再整体放大四倍变成 M 100、N 128那么 PLL 输出就是 98.304MHz再经过内部 4 分频回到 24.576MHz。具体选哪组取决于 ES8311 手册里 PLL 模块的 VCO 频率范围。有些芯片要求 VCO 至少工作在 50MHz 以上那就不能用 24.576MHz 直接输出。所以在配置 PLL 之前先翻手册确认三个边界输入 MCLK 允许的范围、PLL 参考频率允许的范围、VCO 输出频率允许的范围。把这三条线找出来再选 M、N就不会写出一个看起来合理但芯片根本不接受的配置。3.3 分频系数约束与校验清单算完 M、N 不等于配置结束还要检查整个时钟链路能否落到正确的 BCLK 和 LRCK 上。我每次都会列一个校验清单PLL 输出频率是否在手册规定的 VCO 范围内。如果太高就在 PLL 后面加输出分频如果太低就整体放大 M、N 再分频回来。PLL 参考频率是否在可接受范围内。比如 MCLK / M 得到的参考频率不能太低否则环路滤波器很难锁定。一般芯片会给出几百 kHz 到几 MHz 的参考范围。最终送给 ADC/DAC 的工作时钟是否是 fs 的整数倍。PLL 输出 24.576MHz分频到 512fs、256fs 或者 128fs都能对应上。I2S 主从模式下BCLK/LRCK 是否也需要从这一路时钟分频出来。如果需要那么 PLL 输出的频率还得能整除 BCLK 和 LRCK。我自己在实际调试中还会把计算结果写成一个注释留在初始化代码旁边。比如// MCLK 19.2MHz // fs 48kHz // f_pll_out 19.2MHz * 32 / 25 24.576MHz // 512fs 24.576MHz这样过了几个月再回头维护代码或者同事接手项目一眼就能看懂当初为什么配这些值不用重新推一遍。4. 寄存器落地用I2C把分频结果写进ES83114.1 时钟相关寄存器通常长什么样ES8311 的时钟配置集中在芯片的时钟管理寄存器区。不同批次、不同驱动版本的命名可能略有差异但核心的位域大致包括PLL 使能开关、MCLK 分频选择、PLL 的 M 和 N 参数、ADC 时钟分频、DAC 时钟分频。有的版本里还会有 BCLK/LRCK 极性控制、I2S 格式选择等。有一个现象很常见很多人从网上抄来一份初始化数组直接往 I2C 总线里灌结果有声音但就是不对。原因往往是网上的版本针对的是另一颗 CPU、另一个 MCLK 频率或者另一批芯片封装。ES8311 的驱动流程里时钟配置只是其中一步后面还跟着模拟电源、ADC/DAC 通路、输出音量等配置。时钟配错了后面的配置再对也白搭。我在落地时的做法是把初始化数组按“模块”拆开每 3 到 4 个寄存器一组用注释标清楚这组是干什么的。这样一旦音频信号异常我可以单独把时钟组拎出来验证不需要对着 50 多行的数组抓瞎。4.2 从复位到起振的完整初始化顺序ES8311 的初始化顺序我以为要遵循“先复位、再时钟、后通路”的节奏。第一步是复位。很多 codec 芯片的复位寄存器不仅是软复位用也是让内部所有状态回到默认值的关键一步。如果上电后没有复位就直接写配置有些寄存器可能处于未知状态导致后续配置部分生效。第二步是配置时钟树。先确定 MCLK 是否已经有输入然后设置 PLL 的 M、N 参数选择 ADC/DAC 时钟源是 PLL 还是 MCLK再设置分频系数。这一步和上一步之间最好加一点延时给内部电路一个稳定时间。第三步是配置 I2S 数字接口格式包括主从模式、位宽、帧格式、BCLK/LRCK 极性。第四步才是配置模拟通路比如 ADC 输入选择、DAC 输出音量等。很多人喜欢把时钟配置放在最后以为先把音量打开就能听到声音结果怎么调都是噪声。实际上数字音频系统里时钟是骨架模拟通路是血肉骨架不对血肉再完整也立不起来。4.3 一段可以直接改用的C配置函数下面这段代码是伪初始化框架用于演示时钟配置的落地方式。寄存器名需要用你手上那颗 ES8311 数据手册的偏移地址替换这里重点看结构和计算结果的映射。#include stdint.h /* I2C读写函数由你的平台提供 */ uint8_t es8311_i2c_read(uint8_t reg); void es8311_i2c_write(uint8_t reg, uint8_t val); /* 这里按19.2MHz MCLK、48kHz采样、PLL输出24.576MHz配置 */ #define MCLK_HZ 19200000 #define FS_HZ 48000 #define PLL_M 25 #define PLL_N 32 #define PLL_OUT_HZ 24576000 static void es8311_clock_config_for_48k(void) { /* 复位所有寄存器回到默认状态 */ es8311_i2c_write(ES8311_RESET_REG, 0x1F); /* 选MCLK作为PLL输入源 */ es8311_i2c_write(ES8311_CLK_SEL_REG, ES8311_MCLK ...); /* 写PLL的M/N参数 */ /* 注意如果手册说明寄存器里是N-1、M-1要在这里先减一 */ es8311_i2c_write(ES8311_PLL_M_REG, PLL_M - 1); es8311_i2c_write(ES8311_PLL_N_REG, PLL_N - 1); /* 使能PLL */ es8311_i2c_write(ES8311_PLL_EN_REG, 0x01); /* 等待PLL锁定 */ delay_ms(10); /* 配置ADC/DAC时钟源为PLL输出并分频到512fs */ /* 512 * 48000 24.576MHz */ es8311_i2c_write(ES8311_ADC_CLK_DIV_REG, ES8311_512FS ...); es8311_i2c_write(ES8311_DAC_CLK_DIV_REG, ES8311_512FS ...); }这个函数写完不是结束我通常会在后面加一个检查逻辑延时 10 毫秒后读取 PLL 的 lock 状态位。如果硬件反馈 PLL 没有锁定那要么是 M、N 参数算错了要么是输入的 MCLK 根本没起来。4.4 写完后一定要做的回读与状态检查寄存器写进去不代表芯片就按照写的值工作了。I2C 写时序有误、电压不稳、MCLK 信号质量差都可能导致寄存器实际内容和预期不一致。我在项目调试中最常用的方法就是回读。把配置相关的寄存器全部读一遍和预期值做对比。尤其注意 PLL lock 状态位。很多 ES8311 的寄存器描述里会有一个 PLL 锁定标志位如果在使能 PLL 后这个位一直是 0先不要怀疑音频通路回去查 MCLK 信号是否正常、M/N 配置是否在手册允许范围内。还有一个经验不要只回读一次要隔几十毫秒再读第二次。PLL 锁定需要时间如果第一次读还没锁上第二次读锁上了那一般只是时序问题如果两次都读不到 lock那就不是时序问题而是配置本身有硬伤。5. 时钟配置错了会怎样音质表现与定位手段5.1 声音慢放、变调、爆音分别对应哪种时钟问题音质问题是一个很直观的“时钟错误指示器”但很多人不知道怎么看。根据我踩过的坑大概可以分成三类第一类是声音变调但能听清楚内容。这种情况最常见的根因是实际采样率和预期采样率不一致。比如你预期 48kHz实际 LRCK 只有 46.875kHz声音就会整体变慢、音调偏低。反过来如果实际采样率高于预期声音会变尖。这个时候重点查 MCLK 频率和分频系数的匹配关系。第二类是持续的爆音、啪嗒声、沙沙声。这种往往不是分频系数差一点的问题而是时钟本身不稳定或者 PLL 没有真正锁定。PLL 在某些非法的 M/N 配置下会输出一个接近目标但不是目标频率的信号音频链路里就会有明显的周期性噪声。第三类是完全没有声音或者只有上电一瞬间的一点刺啦声。这种情况可能是 ADC/DAC 的时钟路径彻底没通比如分频器被配到了一个非法值或者某个时钟使能位没打开。先别急着查模拟通路回到时钟寄存器翻一遍很多“无声”其实是时钟没亮。5.2 用示波器和逻辑分析仪快速判定实际时钟软件上读寄存器很重要但硬件量测更直接。示波器探头点几下比纠结半天寄存器靠谱得多。在从机模式下优先量 BCLK 和 LRCK。BCLK 应该在示波器上看到一个稳定的方波用示波器的频率测量功能直接读出频率。如果读出来不是 1.536MHz、3.072MHz 这类预期值那就是主控侧时钟有问题。如果主控给的 BCLK 正常再量 LRCK正常情况下 LRCK 就应该等于采样率。如果 LRCK 是 46.875kHz而程序里写的是 48kHz那问题大概率出在 MCLK 分频上。如果是主机模式ES8311 自己产生 BCLK/LRCK那就要量 ES8311 的 MCLK 引脚和输出引脚。MCLK 引脚有波形但幅度很低可能是信号质量问题MCLK 没波形那就是主控侧压根没输出。逻辑分析仪比示波器好在可以解码 I2C。把 SCL、SDA、MCLK、BCLK、LRCK 一起抓下来既能确认 I2C 写入的寄存器值又能看到时钟频率。我一般用逻辑分析仪验证“写入是否正确”用示波器验证“时钟是否稳定”。5.3 一次“LRCK变成了46.875kHz”的排查复盘有一次客户反馈一款设备播放音频时声音偏低。量 LRCK发现实际频率是 46.875kHz而系统需求是 48kHz。打开原理图一查主控输出给 ES8311 的 MCLK 是 12MHz不是常见的 12.288MHz。最初同事直接照抄了另一块板上“MCLK 12.288MHz、fs 48kHz”的初始化数组。那块板上 MCLK 是 12.288MHz除以 256 正好是 48kHz。但换到 12MHz MCLK 后寄存器里配的是 256 分频实际算出来就是 12,000,000 / 256 46,875Hz。音频系统以这个 LRCK 为基准采样播放的自然就不是标准 48kHz 速度。排查链路其实不长听感判断出“变调”问题示波器量 LRCK 发现频率不对回头看 MCLK 是 12MHz算了一下除法马上就知道问题出在哪。解决方案有两种一是主控把 MCLK 改成 12.288MHz二是维持 12MHz MCLK启用 PLL把 12MHz 变换成 24.576MHz然后再分频到 512fs。这个案例给我最大的启发是画原理图之前就应该先确认音频 MCLK 选什么频率。如果主控只能用 12MHz 这种非音频时钟就必须在设计阶段就把 ES8311 的 PLL 方案考虑进去而不是等板子打回来了再在软件里想办法。不同类型时钟错误对应的检查方向我整理了一张表方便现场排查时对照故障现象最可能的时钟原因首选排查动作声音变调、音调明显偏低/偏高实际 fs 与预期不一致示波器量 LRCK 频率和采样率对比持续爆音、沙沙声PLL 未锁定、MCLK 质量差读 PLL lock 位示波器量 MCLK 波形完全无声ADC/DAC 时钟路径未开启回读时钟相关寄存器确认分频字段左右声道有串扰BCLK 频率异常导致数据错位量 BCLK核对 I2S 位宽配置上电后有噪声但随后安静PLL 锁定时间不足软件未等待增加 PLL 锁定延时再初始化后续寄存器这张表是我在支持同事调音频问题时最常用的工具。很多时候不用想太复杂照着现象先锁定方向再回到时钟树算一遍问题基本就能圈定在一个很小的范围内。最后分享一个我自己的习惯每次拿到一套新的 ES8311 初始化配置我都会在代码里留一个“配置来源注释”写上 MCLK 是多大的晶振、目标采样率是多少、PLL 目标输出频率是多少、M/N 是怎么算出来的。几个月后如果出了问题或者换了硬件平台沿着这段注释去核对能省下大把时间。音频 codec 的时钟树配置看着是寄存器操作本质上是数字信号处理的整数运算。把 MCLK、fs、BCLK、LRCK、PLL 之间的关系理清楚ES8311 这颗芯片就不再有神秘感了。
返回列表