議詳解:從時(shí)序原理到調(diào)試實(shí)戰(zhàn))
1. 項(xiàng)目概述1.1 為什么嵌入式開(kāi)發(fā)繞不開(kāi)I2S如果你做過(guò)音頻相關(guān)的嵌入式開(kāi)發(fā)不管是用單片機(jī)驅(qū)動(dòng)一個(gè)簡(jiǎn)單的語(yǔ)音播放模塊還是在應(yīng)用處理器上接一顆高性能音頻Codec遲早會(huì)碰上I2S這個(gè)名字。第一次接觸的人容易被它和I2C搞混——就差一個(gè)字母但完全是兩回事。I2C是低速控制總線(xiàn)用來(lái)讀寫(xiě)寄存器、掛傳感器I2S是音頻數(shù)據(jù)總線(xiàn)專(zhuān)門(mén)用來(lái)傳輸數(shù)字音頻流。我最早做音頻項(xiàng)目時(shí)就在I2S的時(shí)序配對(duì)上卡了整整一個(gè)下午那個(gè)印象太深了所以決定把這篇文章寫(xiě)出來(lái)把I2S協(xié)議的家底一次性講清楚。簡(jiǎn)單來(lái)說(shuō)I2S全稱(chēng)是Inter-IC Sound Bus也叫Integrated Interchip Sound是飛利浦在1986年提出的一種數(shù)字音頻設(shè)備之間的總線(xiàn)標(biāo)準(zhǔn)。它解決的問(wèn)題非常純粹讓兩個(gè)芯片之間能穩(wěn)定、同步地傳輸連續(xù)的PCM音頻數(shù)據(jù)。幾乎所有你能想到的音頻芯片都支持I2S接口——Codec、DAC、ADC、DSP、藍(lán)牙音頻模塊、HDMI音頻提取板甚至高檔CD轉(zhuǎn)盤(pán)內(nèi)部也都是I2S在跑。這篇博文寫(xiě)給誰(shuí)剛接觸音頻協(xié)議的嵌入式新手被MCLK、BCLK、WS、DATA四根線(xiàn)繞暈的工程師以及想自己動(dòng)手改裝或調(diào)試I2S信號(hào)硬件的發(fā)燒友。1.2 I2S在整條音頻鏈路里的位置要理解I2S的作用你得先看清楚它在音頻系統(tǒng)里扮演的角色。一個(gè)完整的數(shù)字音頻鏈路通常分三段源頭是音頻數(shù)據(jù)中間是傳輸/處理末端是回放或采集。I2S干的是中間那段。舉個(gè)例子你手機(jī)里存著一首44.1kHz、16bit的WAV文件CPU從存儲(chǔ)讀出數(shù)據(jù)后需要把這些數(shù)字信號(hào)送到DAC芯片去轉(zhuǎn)成模擬電壓DAC才能推動(dòng)耳機(jī)發(fā)聲。CPU和DAC之間傳遞PCM數(shù)據(jù)走的就是I2S。如果源頭不是CPU而是藍(lán)牙模塊或數(shù)字麥克風(fēng)情況也類(lèi)似。藍(lán)牙模塊解出音頻數(shù)據(jù)后通過(guò)I2S把數(shù)據(jù)喂給后級(jí)的DAC或功放數(shù)字麥克風(fēng)則直接把采集到的PCM數(shù)據(jù)按幀輸出到I2S總線(xiàn)上??傊甀2S負(fù)責(zé)在“產(chǎn)生PCM數(shù)據(jù)的一端”和“消費(fèi)PCM數(shù)據(jù)的一端”之間建立一座同步的橋梁。沒(méi)有它音頻芯片之間就只能靠并行的低速接口慢慢挪效率和實(shí)時(shí)性都跟不上。注意I2S傳的是純粹的PCM數(shù)字音頻數(shù)據(jù)不負(fù)責(zé)音量調(diào)節(jié)、音效處理也不帶任何控制信息。想要控制Codec的寄存器比如AGC、EQ、增益通常還得搭配I2C或SPI接口。這兩者在硬件設(shè)計(jì)上經(jīng)常是“控制面”和“數(shù)據(jù)面”的分工關(guān)系。2. 核心細(xì)節(jié)解析與實(shí)操要點(diǎn)2.1 三根線(xiàn)與第四根線(xiàn)——SCK、WS、SD和MCLKI2S最基本的形態(tài)只有三根線(xiàn)這也是飛利浦原始標(biāo)準(zhǔn)的核心。第一根叫位時(shí)鐘有的叫BCLK有的叫SCKSerial Clock還有的寫(xiě)成BITCLK都是一個(gè)東西。它每來(lái)一個(gè)脈沖就對(duì)應(yīng)傳輸一位音頻數(shù)據(jù)。位時(shí)鐘的頻率很好算采樣率乘以位深再乘以聲道數(shù)。常見(jiàn)的組合44.1kHz采樣率、16bit、雙聲道立體聲BCLK就是44.1k × 16 × 2 1.4112MHz如果是24bit、192kHz、雙聲道那就是192k × 24 × 2 9.216MHz。這個(gè)公式很關(guān)鍵后面配置主控的I2S外設(shè)時(shí)全靠它來(lái)推算分頻系數(shù)。第二根叫幀時(shí)鐘又叫WSWord Select、LRCLK它是整個(gè)I2S的“指揮棒”。WS拉高表示當(dāng)前在傳右聲道的數(shù)據(jù)拉低表示在傳左聲道的數(shù)據(jù)WS翻轉(zhuǎn)一次就代表完成了一個(gè)采樣點(diǎn)。所以在常見(jiàn)的雙聲道配置下WS的頻率就等于采樣率本身44.1kHz的音頻WS就是44.1kHz的方波。這也意味著WS從低到高再回到低完成一個(gè)周期的時(shí)間內(nèi)總共傳了64個(gè)BCLK周期在16bit雙聲道配置下而實(shí)際有用的數(shù)據(jù)位只有32個(gè)剩下的一半是BCLK“閑置”的。這是初學(xué)I2S最容易忽略的地方——BCLK可以比“數(shù)據(jù)位寬×聲道數(shù)”跑得更快幀的邊界由WS決定而不是由BCLK個(gè)數(shù)決定。第三根是數(shù)據(jù)線(xiàn)叫SDSerial Data有的芯片叫DOUT、DIN、SDA方向取決于你是發(fā)送方還是接收方。發(fā)送端在BCLK的上升沿把數(shù)據(jù)一位一位擺到SD上接收端在BCLK的下降沿去采樣這樣雙端都在同一個(gè)邊沿動(dòng)作就不會(huì)產(chǎn)生競(jìng)爭(zhēng)。這是I2S有別于很多同步串行協(xié)議的地方——它不是用上升沿發(fā)、上升沿收而是發(fā)送和接收錯(cuò)開(kāi)了半個(gè)周期。這個(gè)小細(xì)節(jié)決定了信號(hào)能在較長(zhǎng)的PCB走線(xiàn)上保持穩(wěn)定。第四根線(xiàn)MCLK也叫主時(shí)鐘是很多人最容易忽略、偏偏也是最容易讓人栽跟頭的一根線(xiàn)。MCLK的用途是給Codec內(nèi)部的Δ-Σ調(diào)制器和數(shù)字濾波器提供一個(gè)高頻參考時(shí)鐘一般是采樣率的整數(shù)倍常見(jiàn)的是256×fs或512×fs。比如44.1kHz采樣率配256倍MCLK就是11.2896MHz。如果你的主控I2S外設(shè)沒(méi)有獨(dú)立的MCLK輸出引腳那接Codec時(shí)就得想辦法從外部晶振或主控的定時(shí)器/PWM借一個(gè)主時(shí)鐘過(guò)去。很多入門(mén)級(jí)MCU只有三根I2S線(xiàn)這會(huì)導(dǎo)致某些Codec芯片尤其是中高端的比如CS4398、ES9038這類(lèi)沒(méi)法正常工作——它們對(duì)MCLK有硬性要求。提醒MCLK不便宜很多低端方案為了省成本會(huì)直接用BCLK給Codec當(dāng)MCLK用或者用BCLK的兩倍頻。這種做法在低采樣率、低位數(shù)場(chǎng)景可能能跑通但在高采樣率、高保真場(chǎng)景下效果會(huì)很差失真大、底噪高。如果你要追求音質(zhì)MCLK該給就給別省。2.2 四種信號(hào)格式除了標(biāo)準(zhǔn)I2S還有左對(duì)齊、右對(duì)齊和DSP純粹的飛利浦I2S幀格式是WS變化沿先來(lái)緊接著延遲一個(gè)BCLK周期后數(shù)據(jù)最高位MSB才出現(xiàn)在SD上。也就是說(shuō)數(shù)據(jù)位相對(duì)于WS翻轉(zhuǎn)沿存在一個(gè)BCLK的“偏移”。這個(gè)特性非常關(guān)鍵決定了主控和Codec能不能正確對(duì)齊數(shù)據(jù)。但實(shí)際應(yīng)用中你會(huì)發(fā)現(xiàn)滿(mǎn)世界不止這原始的一種格式。最常見(jiàn)的有四種標(biāo)準(zhǔn)I2SPhilips格式數(shù)據(jù)在WS翻轉(zhuǎn)后的下一個(gè)BCLK上升沿開(kāi)始輸出MSB先行。左對(duì)齊Left Justified數(shù)據(jù)在WS翻轉(zhuǎn)的同時(shí)立刻輸出MSB沒(méi)有那一個(gè)BCLK的延遲。因?yàn)镸SB對(duì)齊到幀起點(diǎn)所以叫“左對(duì)齊”。右對(duì)齊/日立格式Right Justified數(shù)據(jù)的LSB貼住幀的結(jié)尾也就是說(shuō)數(shù)據(jù)在幀內(nèi)是“靠右”的。這種格式常見(jiàn)于一些日本廠(chǎng)商的老Codec芯片它要求接收端知道數(shù)據(jù)位寬是多少、才能算準(zhǔn)MSB從哪個(gè)時(shí)鐘開(kāi)始。DSP/PCM格式連續(xù)發(fā)送的多通道數(shù)據(jù)流早期用于DSP之間互傳多聲道數(shù)據(jù)現(xiàn)在在一些TDM多通道Codec上也常見(jiàn)。這里面最坑的就是“標(biāo)準(zhǔn)I2S的1-BCLK延遲”和“右對(duì)齊格式對(duì)位寬的強(qiáng)依賴(lài)”。我遇到過(guò)一塊Codec它的主控默認(rèn)配置成了左對(duì)齊結(jié)果放出來(lái)的聲音像是機(jī)器人在說(shuō)話(huà)全是高頻毛刺。最后把數(shù)據(jù)手冊(cè)逐行看了一遍才發(fā)現(xiàn)這顆芯片在I2S模式之外還分了一個(gè)Left-Justified模式數(shù)據(jù)時(shí)序差一個(gè)時(shí)鐘就全亂了。再看接收端的采樣點(diǎn)。以16bit數(shù)據(jù)、24BCLK幀長(zhǎng)度為例標(biāo)準(zhǔn)I2S模式下發(fā)送端在BCLK上升沿移出數(shù)據(jù)接收端在BCLK下降沿采樣。由于數(shù)據(jù)比WS晚了一個(gè)時(shí)鐘接收端如果想在下降沿采樣等效于它在數(shù)據(jù)穩(wěn)定后的后半段去讀取剛好躲開(kāi)了數(shù)據(jù)的跳變區(qū)。這樣的時(shí)序設(shè)計(jì)非常適合長(zhǎng)距離板內(nèi)走線(xiàn)。2.3 位深與數(shù)據(jù)長(zhǎng)度的坑——16bit、24bit、32bit容器I2S本身不關(guān)心數(shù)據(jù)位深它只負(fù)責(zé)按BCLK一個(gè)個(gè)地搬移比特。但你的Codec和主控總得商量好“每幀里到底有多少位有效數(shù)據(jù)”。這就是一個(gè)巨大的坑BCLK的周期數(shù)可以大于實(shí)際的數(shù)據(jù)位寬。舉個(gè)例子某Codec支持32bit的BCLK/WS幀但實(shí)際有效數(shù)據(jù)只有24bit剩下的8bit是什么可能是補(bǔ)零也可能是填充狀態(tài)信息。如果你做主控時(shí)把“幀長(zhǎng)度”配置成16bit而Codec按32bit來(lái)解析幀那數(shù)據(jù)就會(huì)錯(cuò)位——你可能聽(tīng)到的是完全無(wú)法分辨的噪聲。配置I2S外設(shè)時(shí)有幾個(gè)參數(shù)是必須明確的幀長(zhǎng)度每幀多少個(gè)BCLK、數(shù)據(jù)位寬有效音頻數(shù)據(jù)多少位、以及數(shù)據(jù)在幀內(nèi)的對(duì)齊位置MSB先還是LSB先、延遲幾個(gè)時(shí)鐘。這些參數(shù)錯(cuò)一個(gè)輕則音量小或噪聲重則完全無(wú)聲。很多現(xiàn)代Codec支持“自動(dòng)檢測(cè)”主控給出的幀長(zhǎng)但那是建立在主控給出的BCLK必須和幀長(zhǎng)匹配的前提下。如果BCLK的數(shù)量和Codec預(yù)期的不一致檢測(cè)機(jī)制也會(huì)失效。成熟的驅(qū)動(dòng)工程師會(huì)把主控側(cè)和Codec側(cè)兩側(cè)的寄存器配置放在同一張表里核對(duì)逐項(xiàng)比對(duì)幀長(zhǎng)、位寬、是否帶MCLK、分頻系數(shù)。3. 實(shí)操過(guò)程與核心環(huán)節(jié)實(shí)現(xiàn)3.1 主從模式理解與接線(xiàn)實(shí)戰(zhàn)I2S系統(tǒng)和I2C一樣分主從但音頻總線(xiàn)的“主”通常指的是產(chǎn)生BCLK和WS的一方。常見(jiàn)的有兩種典型架構(gòu)。第一種是主控做主機(jī)Codec做從機(jī)。主控產(chǎn)生BCLK、WS、MCLKCodec被動(dòng)接收時(shí)鐘、輸出/接收數(shù)據(jù)。這種模式最簡(jiǎn)單適合MCU和Codec之間直接通信。接線(xiàn)也直觀主控的I2S_TX接Codec的DINCodec的DOUT接主控的I2S_RXBCLK、WS、MCLK并接。第二種是Codec做主機(jī)主控做從機(jī)。典型的應(yīng)用是音頻子卡、或者帶獨(dú)立晶振的高精度DAC。Codec自己掛一顆高精度晶振自己產(chǎn)生所有時(shí)鐘主控只負(fù)責(zé)在WS的邊沿上同步收發(fā)數(shù)據(jù)。這種方案的優(yōu)勢(shì)是時(shí)鐘抖動(dòng)更低音質(zhì)更好因?yàn)镃odec的時(shí)鐘源離DAC核心更近缺點(diǎn)是主控的I2S外設(shè)必須支持從機(jī)模式而且WS和BCLK都來(lái)自外部調(diào)試時(shí)必須讓主控側(cè)先鎖定外部時(shí)鐘稍有不對(duì)就會(huì)失步。接線(xiàn)時(shí)有個(gè)高頻易錯(cuò)點(diǎn)MCLK的走線(xiàn)盡量短、盡量粗別跟BCLK走得太近避免串?dāng)_。在雙面板上我習(xí)慣給I2S的幾根線(xiàn)都加地孔圍籠尤其MCLK和BCLK之間至少隔一個(gè)地走線(xiàn)。別覺(jué)得這是玄學(xué)音頻Codec對(duì)時(shí)鐘質(zhì)量極其敏感板子上BCLK的過(guò)沖會(huì)直接反映在DAC輸出的底噪上。3.2 時(shí)鐘配置的計(jì)算方法配置I2S時(shí)鐘是唯一繞不開(kāi)的數(shù)學(xué)環(huán)節(jié)。以STM32F4系列為例它的I2S外設(shè)通常掛在I2S2/I2S3上時(shí)鐘源可以選PLLI2S或者系統(tǒng)時(shí)鐘直出。PLLI2S的輸出頻率設(shè)計(jì)成256×fs的整數(shù)倍后再經(jīng)過(guò)I2S外設(shè)的分頻器得到BCLK和WS。實(shí)際算一下目標(biāo)采樣率fs48kHzCodec要求MCLK256×fs。那么MCLK頻率48k × 256 12.288MHzBCLK頻率48k × 32 × 2 3.072MHz按每幀32bit、雙聲道算I2S外設(shè)分頻比12.288MHz / 3.072MHz 4也就是BCLK MCLK/4如果你的主控PLL輸出正好是12.288MHz那就完美直接掛上。如果不能整出12.288MHz選一個(gè)接近的頻率但要注意Codec對(duì)MCLK頻率的容忍范圍一般高端Codec要求MCLK的誤差在±50ppm低端一些的在±200ppm。超過(guò)范圍DAC內(nèi)部的數(shù)字濾波器會(huì)表現(xiàn)出嚴(yán)重的時(shí)鐘抖動(dòng)反映在聽(tīng)感上就是聲音發(fā)飄、高頻毛糙。ES9038Q2M這顆DAC在I2S模式下MCLK必須是BCLK的整數(shù)倍我試過(guò)給它配64×fs3.072MHz也能出聲音但失真明顯高于256×fs。所以我的建議是如果你不確定優(yōu)先選256×fs如果Codec手冊(cè)里寫(xiě)了128/384/512等模式再根據(jù)主控PLL的能力靈活調(diào)整追求音質(zhì)就上512×fs但前提是主控能干凈地輸出高頻時(shí)鐘。3.3 一套可復(fù)用的I2S配置流程配置I2S外設(shè)我一般按下面的順序來(lái)少走很多彎路先查Codec數(shù)據(jù)手冊(cè)確認(rèn)目標(biāo)采樣率、位深、MCLK倍頻、I2S格式標(biāo)準(zhǔn)還是左對(duì)齊。算BCLK fs × 位深 × 聲道數(shù)再用推薦的MCLK倍頻算出MCLK目標(biāo)頻率。配置主控PLL讓MCLK盡量精確誤差在可接受范圍內(nèi)。配置I2S外設(shè)數(shù)據(jù)位寬、幀長(zhǎng)、主從模式、極性一般標(biāo)準(zhǔn)I2S是上升沿發(fā)送下降沿接收。先把MCLK和BCLK用示波器量出來(lái)確認(rèn)頻率正確、波形干凈再接上Codec。使能DMA或中斷收發(fā)先傳一段已知的靜音數(shù)據(jù)用邏輯分析儀抓SD線(xiàn)看幀邊界是否和數(shù)據(jù)手冊(cè)一致。最后才接Codec的I2C控制口配置Codec的內(nèi)部寄存器如輸入選擇、音量、DAC使能然后播測(cè)試音頻。這套流程里第5步和第6步是最容易省、但最不該省的。很多人直接燒錄程序聽(tīng)聲音聽(tīng)到噪聲就開(kāi)始懷疑Codec芯片壞了其實(shí)多半是I2S時(shí)序參數(shù)沒(méi)對(duì)齊。先把波形量出來(lái)再用邏輯分析儀看幀結(jié)構(gòu)基本能定位九成問(wèn)題。我實(shí)際測(cè)試時(shí)用邏輯分析儀抓過(guò)一塊損壞的Codec——SD線(xiàn)上有數(shù)據(jù)但WS頻率完全亂了最后發(fā)現(xiàn)是主控在從機(jī)模式下沒(méi)鎖定外部BCLK導(dǎo)致內(nèi)部FIFO溢出。這種問(wèn)題聽(tīng)是聽(tīng)不出來(lái)的只有抓波形才看得到。3.4 從零配置一個(gè)I2S播放器的關(guān)鍵代碼片段下面給一個(gè)STM32 WM8960 Codec的例子。WM8960是顆很常見(jiàn)的低功耗Codec支持I2S和左對(duì)齊模式MCLK可以用256×fs。假設(shè)fs44.1kHz位深16bit雙聲道MCLK 256 × 44100 11.2896MHzBCLK 16 × 2 × 44100 1.4112MHz分頻比11.2896 / 1.4112 8STM32F407的PLLI2S配置目標(biāo)是11.2896MHz。I2S2外設(shè)開(kāi)啟配置為主機(jī)、標(biāo)準(zhǔn)I2S、16bit數(shù)據(jù)幀長(zhǎng)使用DMA發(fā)送。// 1. 配置PLLI2S輸出 11.2896MHz RCC_PLLI2SConfig(258, 0, 43); // 經(jīng)過(guò)計(jì)算得到分頻系數(shù) // 2. 使能I2S外設(shè)時(shí)鐘 RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2S2, ENABLE); // 3. 設(shè)置I2S2為主機(jī)、標(biāo)準(zhǔn)模式、16bit I2S_InitTypeDef I2S_InitStructure; I2S_InitStructure.I2S_Mode I2S_Mode_MasterTx; I2S_InitStructure.I2S_Standard I2S_Standard_Phillips; I2S_InitStructure.I2S_DataFormat I2S_DataFormat_16b; I2S_InitStructure.I2S_MCLKOutput I2S_MCLKOutput_Enable; I2S_InitStructure.I2S_AudioFreq I2S_AudioFreq_44k; I2S_InitStructure.I2S_CPOL I2S_CPOL_Low; I2S_Init(I2S2, I2S_InitStructure); // 4. 配置DMA發(fā)送 DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_Channel DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr (uint32_t)I2S2-DR; DMA_InitStructure.DMA_MemoryBaseAddr (uint32_t)audio_buffer; DMA_InitStructure.DMA_DIR DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_BufferSize BUFFER_SIZE; DMA_InitStructure.DMA_PeripheralInc DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize DMA_MemoryDataSize_HalfWord; DMA_Init(DMA1_Stream4, DMA_InitStructure); // 5. 使能I2S和DMA I2S_Cmd(I2S2, ENABLE); DMA_Cmd(DMA1_Stream4, ENABLE);這段代碼里I2S_CPOL_Low是標(biāo)準(zhǔn)I2S的時(shí)鐘極性選擇I2S外設(shè)在這里約定在BCLK的低電平期間發(fā)送數(shù)據(jù)在BCLK的邊沿采樣。如果你換成Left-Justified模式記得改I2S_Standard同時(shí)把數(shù)據(jù)幀對(duì)齊方式一并確認(rèn)STM32的HAL庫(kù)在這些細(xì)節(jié)上封裝得比較隱性一定要對(duì)照參考手冊(cè)。3.5 不同芯片的I2S接口異同不是所有芯片的I2S都長(zhǎng)得一模一樣到了實(shí)際項(xiàng)目里你會(huì)見(jiàn)到各種變體全雙工I2S有獨(dú)立的TX和RX數(shù)據(jù)線(xiàn)可以同時(shí)收發(fā)典型是STM32的I2S外設(shè)。半雙工I2S只有一根SD線(xiàn)時(shí)分復(fù)用做收發(fā)。有些低功耗藍(lán)牙芯片為了省引腳用半雙工。TDM多通道模式BCLK和WS不變但一個(gè)WS周期里塞進(jìn)了4路、8路甚至16路數(shù)據(jù)常見(jiàn)于多聲道Codec如TAS5754、陣列麥克風(fēng)如AC108。I2S over HDMIHDMI音頻提取板上用I2S把多通道LPCM音頻導(dǎo)出來(lái)本質(zhì)還是I2S只是數(shù)據(jù)流的組織方式和普通立體聲略有不同。PCM接口很多人把它和I2S混為一談其實(shí)PCM接口如Qualcomm的PCM接口通常以短幀同步信號(hào)SYNC代替WS幀長(zhǎng)可以是16bit或32bit數(shù)據(jù)位可以在128fs、256fs等時(shí)鐘下跑本質(zhì)上也是一種音頻串行總線(xiàn)但時(shí)序和I2S有細(xì)節(jié)差異。做兼容性設(shè)計(jì)時(shí)我的經(jīng)驗(yàn)是把I2S外設(shè)的極性、幀長(zhǎng)、數(shù)據(jù)位寬都做成可配置項(xiàng)不要寫(xiě)死任何一個(gè)參數(shù)。你永遠(yuǎn)不知道下一塊Codec喜歡什么格式。比如某國(guó)產(chǎn)Codec默認(rèn)就是24bit/32bit幀不改參數(shù)根本不出聲。4. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄4.1 問(wèn)題速查表現(xiàn)象可能原因排查方法完全無(wú)聲MCLK沒(méi)配置或頻率錯(cuò)誤示波器量MCLK確認(rèn)是否等于Codec要求的fs倍數(shù)完全無(wú)聲I2S數(shù)據(jù)方向接反核對(duì)TX/RX方向主控TX接Codec DIN主控RX接Codec DOUT有噪聲/爆音BCLK和WS極性不對(duì)檢查I2S外設(shè)的CPOL極性設(shè)置調(diào)反試試聲音變調(diào)采樣率配置錯(cuò)誤示波器量WS頻率確認(rèn)等于目標(biāo)fs音量異常低位深錯(cuò)位高bit被當(dāng)成低bit用邏輯分析儀抓幀核對(duì)MSB對(duì)齊位置左右聲道互換WS極性可能與預(yù)期相反嘗試把WS的級(jí)性取反或檢查左右聲道映射寄存器間歇性雜音DMA緩沖下溢/溢出調(diào)整DMA緩沖區(qū)大小或中斷優(yōu)先級(jí)聲音高頻失真MCLK不是fs的整數(shù)倍重新計(jì)算PLL分頻確保MCLK fs × 整數(shù)4.2 調(diào)試手法與工具體會(huì)I2S調(diào)試示波器和邏輯分析儀是兩件法寶。示波器用于量頻域和波形質(zhì)量MCLK的抖動(dòng)、BCLK的過(guò)沖、WS的上升沿是否干凈。邏輯分析儀則用于看時(shí)序邏輯數(shù)一下一個(gè)WS周期內(nèi)有多少個(gè)BCLK、MSB是否在預(yù)期位置、數(shù)據(jù)是否連續(xù)。我踩過(guò)的最深的坑是I2S外設(shè)的DMA配置看起來(lái)全對(duì)程序也沒(méi)報(bào)錯(cuò)但就是不出聲。后來(lái)用邏輯分析儀抓了SD線(xiàn)發(fā)現(xiàn)SD線(xiàn)上根本沒(méi)有任何翻轉(zhuǎn)DMA沒(méi)把數(shù)據(jù)送到外設(shè)。最后定位到問(wèn)題是DMA和外設(shè)的時(shí)鐘使能順序?qū)懛戳讼乳_(kāi)了I2S再開(kāi)DMA外設(shè)的FIFO沒(méi)有準(zhǔn)備好。這類(lèi)問(wèn)題在參考手冊(cè)上根本不會(huì)寫(xiě)只能靠經(jīng)驗(yàn)。另一個(gè)高頻問(wèn)題GPIO復(fù)用功能沒(méi)配置。很多MCU的I2S引腳是復(fù)用功能引腳如果你只開(kāi)了外設(shè)時(shí)鐘、忘了配置引腳的AFAlternate Function那BCLK和WS永遠(yuǎn)輸不出來(lái)。我建議大家寫(xiě)好配置后第一件事就是量主控引腳的BCLK和MCLK有波形再繼續(xù)往下調(diào)。4.3 發(fā)燒友改裝場(chǎng)景天籟CD機(jī)I2S飛線(xiàn)熱詞里出現(xiàn)了“天籟CD機(jī)I2S飛線(xiàn)改裝”這屬于發(fā)燒友圈子里比較經(jīng)典的玩法。老款CD機(jī)/DVD機(jī)里通常有一顆DSP或伺服芯片內(nèi)部有I2S信號(hào)但PCB上不一定預(yù)留出測(cè)試點(diǎn)。愛(ài)好者會(huì)找到芯片手冊(cè)確認(rèn)I2S引腳位置然后用漆包線(xiàn)直接把I2S信號(hào)引到外置DAC的I2S輸入跳過(guò)機(jī)內(nèi)劣質(zhì)的模擬輸出電路達(dá)到提升音質(zhì)的目的。這個(gè)玩法技術(shù)上可行但風(fēng)險(xiǎn)也不小一根飛線(xiàn)動(dòng)輒幾厘米I2S的BCLK動(dòng)輒幾MHz長(zhǎng)線(xiàn)會(huì)引入串?dāng)_和反射飛線(xiàn)焊點(diǎn)松了會(huì)導(dǎo)致雜音甚至短路。我的建議是如果你真想玩飛線(xiàn)優(yōu)先找3.3V邏輯的芯片、最短路徑引出每根I2S線(xiàn)外面套上屏蔽地線(xiàn)而且最好直接從主控芯片引腳引不要從過(guò)孔或焊盤(pán)上擠。改裝前先抓一下原始I2S信號(hào)確認(rèn)有信號(hào)再動(dòng)手。很多DIY失敗不是DAC不行而是I2S信號(hào)在飛線(xiàn)上已經(jīng)爛得沒(méi)法看了。4.4 I2S與AHB、AXI總線(xiàn)的關(guān)系澄清熱詞里還有AHB總線(xiàn)協(xié)議和AXI4總線(xiàn)協(xié)議這里順便澄清一下避免初學(xué)者混淆。AHB、AXI是芯片內(nèi)部的片上總線(xiàn)協(xié)議是SoC內(nèi)部的“高速公路”負(fù)責(zé)連接CPU、內(nèi)存、外設(shè)控制器。I2S是芯片對(duì)外的串行音頻接口協(xié)議屬于“外設(shè)功能”。兩者之間關(guān)系是I2S外設(shè)控制器掛在AHB/AXI總線(xiàn)上CPU通過(guò)AHB/AXI訪(fǎng)問(wèn)I2S的寄存器、讀寫(xiě)FIFO但I(xiàn)2S接口信號(hào)本身毫不知曉AXI的存在。你只需要知道配置I2S外設(shè)時(shí)總線(xiàn)時(shí)鐘的開(kāi)關(guān)和復(fù)位控制通常是由總線(xiàn)管理器來(lái)做的調(diào)試時(shí)如果I2S外設(shè)時(shí)鐘沒(méi)開(kāi)量到的引腳全是低電平十有八九就是總線(xiàn)側(cè)時(shí)鐘沒(méi)使能。5. 實(shí)操經(jīng)驗(yàn)補(bǔ)充與深入思考5.1 從波形讀懂I2S時(shí)序初學(xué)I2S時(shí)最需要訓(xùn)練的能力就是看波形。你可以把一根探針夾在BCLK上另一根夾在WS上用示波器的余暉模式觀察。一個(gè)正常的44.1kHz/16bit音頻流BCLK是1.4112MHz的方波WS是44.1kHz的方波兩者頻率比值剛好是3216bit × 2聲道。如果比值不是整數(shù)幀結(jié)構(gòu)一定有問(wèn)題。再看SD線(xiàn)和WS的相位關(guān)系標(biāo)準(zhǔn)I2S模式下WS翻轉(zhuǎn)后SD要等下一個(gè)BCLK上升沿才出現(xiàn)MSB。你用示波器同時(shí)看這三根線(xiàn)時(shí)會(huì)發(fā)現(xiàn)SD的第一個(gè)數(shù)據(jù)位落后WS一個(gè)時(shí)鐘。如果能清楚地看到這個(gè)“延遲一位”的現(xiàn)象說(shuō)明I2S時(shí)序大概率是對(duì)的。如果SD和WS同時(shí)翻轉(zhuǎn)那是Left-Justified模式不是標(biāo)準(zhǔn)I2S。5.2 I2S線(xiàn)上的信號(hào)完整性與PCB布局建議I2S不是高速差分信號(hào)但它在音頻場(chǎng)景里對(duì)時(shí)鐘質(zhì)量的要求接近“玄學(xué)”級(jí)別。PCB布局時(shí)建議遵循幾個(gè)原則所有I2S線(xiàn)盡量短而直最好不要跨島走線(xiàn)跨過(guò)不同的地平面。BCKL和WS之間留出間距至少2-3倍線(xiàn)寬如果空間允許用GND包地。MCLK單獨(dú)走別和I2S數(shù)據(jù)線(xiàn)平行長(zhǎng)距離走。MCLK是最高頻的信號(hào)11.2896MHz以上對(duì)串?dāng)_最敏感。電阻匹配很多方案會(huì)在MCLK和BCLK串33Ω或47Ω的電阻既能限流又能抑制振鈴實(shí)測(cè)能降低一些EMI。如果你在Codec端看到BCLK有過(guò)沖超過(guò)VCC0.3V的波形大概率是阻抗失配串個(gè)小電阻往往立竿見(jiàn)影。音頻系統(tǒng)里“聲道分離度差”這種問(wèn)題很多就是I2S線(xiàn)之間的串?dāng)_造成的適當(dāng)拉開(kāi)距離或包地就能改善。5.3 從I2S到系統(tǒng)——音頻時(shí)鐘樹(shù)設(shè)計(jì)I2S配置說(shuō)到底是在一個(gè)時(shí)鐘樹(shù)里做“頻率搬運(yùn)工”。完整的音頻時(shí)鐘樹(shù)一般包含系統(tǒng)時(shí)鐘、PLL、I2S外設(shè)分頻器、Codec內(nèi)部的PLL/分頻器。任何一個(gè)環(huán)節(jié)的“臟時(shí)鐘”最終都會(huì)反映在音頻質(zhì)量上。我的一個(gè)經(jīng)驗(yàn)是如果系統(tǒng)里有獨(dú)立的音頻晶振常見(jiàn)的有24.576MHz和22.5792MHz兩種分別對(duì)應(yīng)48k和44.1k系列采樣率一定要優(yōu)先用它作為MCLK的源頭而不是復(fù)用系統(tǒng)MCU的PLL輸出。這顆晶振是整個(gè)音頻鏈路的“心跳”它干凈后面的數(shù)據(jù)才干凈。很多高保真DAC開(kāi)發(fā)板會(huì)設(shè)計(jì)兩顆晶振一顆管44.1kHz家族22.5792MHz一顆管48kHz家族24.576MHz然后根據(jù)播放的采樣率自動(dòng)切換。這種設(shè)計(jì)不是為了炫技而是確保任何采樣率下MCLK都是fs的精確整數(shù)倍。用PLL硬分頻雖然方便但相位噪聲很難和專(zhuān)用晶振比。5.4 I2S之外的選擇PDM、TDM、USB Audio最后聊兩句I2S之外的“隔壁鄰居”。PDM接口在數(shù)字麥克風(fēng)上很常見(jiàn)它的數(shù)據(jù)線(xiàn)只有一根時(shí)鐘頻率通常在1MHz到4.8MHz之間通過(guò)過(guò)采樣噪聲整形輸出1bit數(shù)據(jù)流和I2S的多bit并行完全不同。TDM則是I2S的多通道擴(kuò)展版本適合做多聲道音頻傳輸。USB Audio則是把音頻數(shù)據(jù)打包成USB packet走USB線(xiàn)纜完全不需要I2S但在主控內(nèi)部從USB controller解出來(lái)的PCM數(shù)據(jù)大概率還是要經(jīng)過(guò)I2S或I2S-like的接口送到Codec。做系統(tǒng)選型時(shí)不要盲目追求I2S有些場(chǎng)景用PDM比如很多麥克風(fēng)陣列更合適有些場(chǎng)景用TDM多聲道音響更省引腳。但在絕大多數(shù)立體聲Codec連接場(chǎng)景中I2S依然是那個(gè)最通用、最不容易出錯(cuò)的選擇。實(shí)操心得如果你正在學(xué)習(xí)I2S我強(qiáng)烈建議你準(zhǔn)備一個(gè)30塊錢(qián)的邏輯分析儀先把主控發(fā)出的I2S波形抓下來(lái)對(duì)著數(shù)據(jù)手冊(cè)數(shù)一遍BCLK、WS、SD的對(duì)應(yīng)關(guān)系??催^(guò)一次波形、理解了幀結(jié)構(gòu)之后I2S對(duì)你來(lái)說(shuō)就不再是抽象協(xié)議了。后面換任何芯片、改任何參數(shù)基于這套對(duì)幀結(jié)構(gòu)的直覺(jué)都能快速定位問(wèn)題。這段功夫花得值別省。