• 正文
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

在 KL27 上實(shí)現(xiàn) USB 音頻同步模式

03/03 15:01
701
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

1 前言
在進(jìn)行 USB 音頻設(shè)備開(kāi)發(fā)的時(shí)候,我們不得不考慮音頻同步的問(wèn)題。USB協(xié)議中定義了音頻傳輸?shù)娜N同步機(jī)制,如 表 1 所示。
表 1. USB 音頻設(shè)備的同步機(jī)制

表 1 中的 Source 和 Sink 都是指 USB 設(shè)備,Source 是指產(chǎn)生音頻數(shù)據(jù)并發(fā)送給主機(jī)的設(shè)備,如 USB 麥克風(fēng)。Sink 是指接收來(lái)自 USB 主機(jī)的音頻數(shù)據(jù)的設(shè)備,比如 USB 揚(yáng)聲器(播放器)。本應(yīng)用筆記主要講 USB 播放器設(shè)備中的音頻同步,因此下文中的 USB 設(shè)備如無(wú)特殊說(shuō)明都是指 Sink 設(shè)備。
三種同步機(jī)制的原理如下:
? 異步模式
當(dāng) USB 端點(diǎn)工作在異步模式時(shí),USB 設(shè)備端不會(huì)和 USB 主機(jī)的 SOF(Start of frame)信號(hào)保持同步,而是通過(guò)一個(gè)額外的反饋端點(diǎn)(feedback)告知 USB 主機(jī)設(shè)備端的真實(shí)的發(fā)送速率,USB 主機(jī)根據(jù)反饋值實(shí)時(shí)的調(diào)整自身的發(fā)送速率。
? 同步模式
當(dāng) USB 端點(diǎn)工作在同步模式時(shí),USB 設(shè)備端的傳輸速率需要和 USB 主機(jī)的 SOF 信號(hào)保持同步,通過(guò)調(diào)整設(shè)備端的時(shí)鐘系統(tǒng)來(lái)使設(shè)備端的傳輸速率和SOF 信號(hào)保持同步。
? 自適應(yīng)模式
當(dāng) USB 端點(diǎn)工作在自適應(yīng)模式時(shí),它可以工作在操作范圍內(nèi)的任意速率,而不只是 32 KHz,44.1 KHz,48 KHz 這些頻率,對(duì)于 Sink 設(shè)備來(lái)說(shuō),USB設(shè)備需要調(diào)整自身的傳輸速率來(lái)匹配 USB 主機(jī)的數(shù)據(jù)流。
關(guān)于同步機(jī)制的更多細(xì)節(jié),請(qǐng)參考 USB 2.0 協(xié)議的 5.12 章節(jié)。
NXP SDK 中的 USB 音頻播放器的例程中,一般使用異步模式來(lái)實(shí)現(xiàn) USB 主機(jī)和設(shè)備之間的音頻同步,即設(shè)備端通過(guò)反饋端點(diǎn)告訴主機(jī)設(shè)備端的真實(shí)傳輸速率,讓主機(jī)調(diào)整實(shí)際的下發(fā)速率。有些 USB 主機(jī)是不支持異步模式的,即主機(jī)不會(huì)調(diào)整自身的


發(fā)送速率的,例如索尼的 Play Station(PS4)和 Nintendo Switch,這時(shí)候就需要設(shè)備端工作在同步模式,設(shè)備端通過(guò)調(diào)整自身
時(shí)鐘來(lái)匹配 USB 主機(jī)的傳輸速率。
根據(jù)一些客戶的需求,NXP SDK 中有一些設(shè)備已經(jīng)支持了同步模式,比如 LPC54608 和 RT600,他們的同步模式的實(shí)現(xiàn)方法如
下:
? LPC54608
在 LPC54608 的 SDK USB 音頻播放器的例程中,程序會(huì)根據(jù)用于存儲(chǔ)音頻數(shù)據(jù)的環(huán)形緩沖區(qū)的余量來(lái)實(shí)時(shí)的調(diào)整 Free
Running Oscillator (FRO)時(shí)鐘的 trim 值。由于 FRO 時(shí)鐘還作為 Phase Locked Loop (PLL)模塊的輸入時(shí)鐘,因此由
PLL 分頻得到的 I2S_BCLK(Bit Clock)和 I2S_WS(Word Select)也會(huì)被同步的更新。
? RT600
在 RT600 的 SDK USB 音頻播放器的例程中,通過(guò) SCTimer 實(shí)時(shí)的測(cè)量 USB 主機(jī)的 SOF 幀間隔,根據(jù)幀間隔來(lái)調(diào)整 PLL
的小數(shù)分頻系數(shù),從而調(diào)整 I2S_BCLK 和 I2S_WS。
Kinetis L(KL)系列 MCU 是一款基于 Cortex-M0+的帶有 USB 設(shè)備控制器低功耗低成本微控制器,一些客戶會(huì)選用 KL 系列
微控制器作為 USB 音頻播放器的控制器,如 KL27,但是如果客戶想使 USB 音頻播放器支持 PS4 這種不支持異步模式的主機(jī),
則需要使 KL27 的 USB 端點(diǎn)工作在同步模式。與 LPC54608, RT600 不同的是,KL27 是一款低成本的微控制器,并沒(méi)有 PLL 模
塊和小數(shù)分頻器,這就使得 KL27 不能像 LPC54608 和 RT600 一樣通過(guò)調(diào)整 PLL 來(lái)調(diào)整 I2S_BCLK 和 I2S_WS。 本篇應(yīng)用筆記
將介紹一種基于 KL 系列 MCU 的音頻同步模式的實(shí)現(xiàn)方法,通過(guò)調(diào)整 I2S_BCLK 的整數(shù)分頻器和 I2S 字長(zhǎng)(Word Length)來(lái)調(diào)
整設(shè)備端的傳輸速率以匹配 USB 主機(jī)的發(fā)送速率。
2 實(shí)現(xiàn)方法
本節(jié)將以 KL27 為例,介紹如何在 USB 音頻播放器中實(shí)現(xiàn)音頻同步模式。
2.1 軟件硬件支持
? 硬件
由于 FRDM-KL27 板子上的 KL27 為 MKL27Z64VLH4,此芯片沒(méi)有 I2S 外設(shè),且 FRDM 板子上沒(méi)有 Codec 芯片,因此無(wú)法
在此板子上運(yùn)行 USB 音頻播放器的程序。 NxH3670 SDK 板是基于 KL27 的無(wú)線耳機(jī)方案的評(píng)估板,板上有 MKL27Z256VMP4
和 Codec WM8904,所以選用此板作為測(cè)試的硬件平臺(tái),板子的配置如 圖 1 所示。關(guān)于更多板子的細(xì)節(jié),請(qǐng)參考NxH3670

SDK board(文檔 UM11150)。

? 軟件
FRDM-KL27 的 SDK 包是針對(duì) MKL27Z64VLH4 這顆芯片的,沒(méi)有 I2S 的驅(qū)動(dòng),因此選用 FRDM-KL43 的 SDK 包中的 USB音頻例程作為基礎(chǔ)工程。
2.2 系統(tǒng)框圖

KL27 音頻播放器的系統(tǒng)框圖如 圖 2 所示。

2.3 USB 音頻同步模式的使能
本例程將 KL43 SDK 中的 dev_composite_hid_audio_bm 工程作為基礎(chǔ)工程,在此基礎(chǔ)上,增加了 Codec 的驅(qū)動(dòng)和音頻環(huán)形緩沖
區(qū)的相關(guān)代碼。

在原始代碼中,USB 音頻設(shè)備是工作在異步模式的,因此需要修改相關(guān)的 USB 描述符使其工作在同步模式,本例程中使用DEVICE_AUDIO_USE_SYNC_MODE 宏來(lái)配置 USB 音頻設(shè)備工作在異步模式還是同步模式,將USB_DEVICE_AUDIO_USE_
SYNC_MODE 宏設(shè)置為 1,使 KL27 工作在同步模式,具體的配置細(xì)節(jié)請(qǐng)參考附件中的代碼。
2.4 KL27 的時(shí)鐘分配
配置 I2S 的 Master clock(I2S_MCLK)為 48 M 的系統(tǒng)時(shí)鐘,然后將 I2S_MCLK 分頻之后產(chǎn)生 I2S_BCLK。本例程中使用的 USB
音頻設(shè)備的格式為雙聲道的 48 K/24 bit 數(shù)據(jù)流。若 I2S 接口也配置為 48 K/24 bit,則對(duì)應(yīng)的 I2S_BCLK = 48K * 24 * 2 = 2.034
M。我們無(wú)法從 48 M 的 I2S_MCLK 整數(shù)分頻得到 2.034 M,所以需要將 I2S 字長(zhǎng)調(diào)整為 25 位,此時(shí) I2S_BCLK = 48K * 25 * 2

= 2.4 M,可以將 I2S_MCLK 20 分頻得到所需要的 I2S_BCLK。

2.5 Codec 的配置
NxH3670 SDK 板上的 Codec 為 WM8904,由于本例程中使用的 USB 音頻設(shè)備的格式為雙聲道 48 K/24 bit 數(shù)據(jù),因此也需要將
Codec 配置為相同的數(shù)據(jù)格式,且 Codec 需要工作在 I2S 從機(jī)模式,即 I2S_BCLK 和 I2S_WS 信號(hào)由 KL27 提供。Codec 的主時(shí)鐘(master clock)由板子上外接的 12.288 M 的晶振提供。

需要注意的是 WM8904 是一個(gè) 24 位的設(shè)備,如果將 KL27 的 I2S 字長(zhǎng)配置為超過(guò) 24 位的長(zhǎng)度,那么 WM8904 將會(huì)自動(dòng)忽略超
出 24 位長(zhǎng)度的數(shù)據(jù)。即使將 I2S 主機(jī)的字長(zhǎng)配置為 25 位,也不會(huì)影響 Codec 實(shí)際的播放效果。
2.6 環(huán)形緩沖區(qū)的管理
本例程使用環(huán)形緩沖區(qū)來(lái)存儲(chǔ) USB 主機(jī)發(fā)送過(guò)來(lái)的音頻數(shù)據(jù), 同時(shí)使用 DMA 將環(huán)形緩沖區(qū)中的數(shù)據(jù)搬運(yùn)至 I2S 的 TX 數(shù)據(jù)寄存器中。環(huán)形緩沖區(qū)的管理由兩個(gè)中斷服務(wù)函數(shù)實(shí)現(xiàn),這兩個(gè)中斷服務(wù)函數(shù)分別為:
? USB0_IRQHandler
? Audio_DMATxCallback
本例程中使用的環(huán)形緩沖區(qū)機(jī)制來(lái)自于 NxH3670 SDK 開(kāi)發(fā)包,使用了三個(gè)環(huán)形緩沖區(qū),分別為 gs_Interfaces[0].buffer[4096],
gs_Interfaces[1].buffer[4096]和 s_audioService_BufferOut[4096]。NxH3670 SDK 中的環(huán)形緩沖區(qū)機(jī)制支持音頻混合的功能,可

以同時(shí)輸出游戲通道和聊天通道兩個(gè)音頻通道中的音頻數(shù)據(jù),其原理是將游戲和聊天兩個(gè)音頻接口中的數(shù)據(jù)分別存儲(chǔ)在gs_Interfaces[0].buffer 和 gs_Interfaces[1].buffer 兩個(gè)環(huán)形緩沖區(qū)中,然后再按照時(shí)間的先后順序?qū)蓚€(gè)環(huán)形緩沖區(qū)中的數(shù)據(jù)拷
貝至 s_audioService_BufferOut 數(shù)組中,然后使用 DMA 將 s_audioService_BufferOut 數(shù)組中的數(shù)據(jù)搬運(yùn)至 I2S TX 數(shù)據(jù)寄存器
中,這樣人耳就可以同時(shí)聽(tīng)到游戲和聊天兩個(gè)通道混合的聲音。音頻流示意圖如 圖 5 所示。

在本例程中,只實(shí)現(xiàn)了一個(gè)音頻接口,并沒(méi)有使用到音頻混合的功能,即音頻數(shù)據(jù)流只會(huì)按照 圖 5 中綠色箭頭的指向來(lái)移動(dòng)。
2.6.1 環(huán)形緩沖區(qū)的閾值設(shè)定
本例程中使用的 gs_Interfaces[0].buffer 環(huán)形緩沖區(qū)的長(zhǎng)度為 4096,閾值設(shè)定如 圖 6 所示。

環(huán)形緩沖區(qū)的余量的正常范圍在長(zhǎng)度的 40%(1638)和 60%(2457)之間,若超出此范圍,則需要調(diào)整 I2S 的傳輸速率。 若余
量超過(guò) 2457,則需要加快 I2S 的傳輸速率,若余量小于 1638,則需要降低 I2S 傳輸速率。
2.6.2 USB 中斷服務(wù)函數(shù)

USB 中斷服務(wù)函數(shù)中對(duì)音頻流的處理如 圖 7 所示。

對(duì)于全速 USB 音頻設(shè)備, USB 主機(jī)每毫秒發(fā)送一包音頻流數(shù)據(jù),數(shù)據(jù)包大小為 288 個(gè)字節(jié)(48K*2*3)。由 圖 7 可知,在USB
中斷服務(wù)函數(shù)中首先會(huì)調(diào)用 USB_FeedbackCalculate 函數(shù)計(jì)算環(huán)形緩沖區(qū)的余量,并判斷是否需要更新 I2S_WS,若需要更新,則更新 g_I2sBclkSwitchFlag 和 g_I2sFormatIndex 變量的值,需要注意的是 I2S_WS 并不會(huì)被馬上更新,而是會(huì)等當(dāng)前DMA 傳輸完成,在 DMA 中斷服務(wù)函數(shù)中被更新。執(zhí)行完 USB_FeedbackCalculate 函數(shù)之后調(diào)用 audio_ringbuffer_write 函數(shù)將接收到的音頻數(shù)據(jù)寫(xiě)入到 gs_Interfaces[0].buffer,在寫(xiě)入之前,需要先將 24 位數(shù)據(jù)擴(kuò)充為 32 位數(shù)據(jù),這是因?yàn)?DMA 每次搬運(yùn)的長(zhǎng)度為 32 位。然后判斷此環(huán)形緩沖區(qū)是否半滿,若半滿,則調(diào)用 audio_StartTx 函數(shù)開(kāi)啟 DMA 傳輸,所以正常情況下,環(huán)形緩沖區(qū)的余量應(yīng)該保持在長(zhǎng)度的 50%左右。如果客戶對(duì)音頻數(shù)據(jù)的延時(shí)有比較嚴(yán)格的要求,那么可以減小緩沖緩沖區(qū)的長(zhǎng)度來(lái)縮短音頻延時(shí)。

2.6.3 DMA 中斷服務(wù)函數(shù)
配置 DMA 的傳輸長(zhǎng)度為 1ms 的音頻數(shù)據(jù)流大小,即 384 個(gè)字節(jié)(48*2*4),DMA 每毫秒完成一次傳輸并觸發(fā)一次 DMA 中

斷,在 DMA 中斷服務(wù)函數(shù)中調(diào)用 audio_DMATxCallback 函數(shù),audio_DMATxCallback 中的音頻處理流程如 圖 8 所示。

在 audio_DMATxCallback 函數(shù)中,首先會(huì)判斷 g_I2sBclkSwitchFlag 變量是否為 1,若為 1,表明環(huán)形緩沖區(qū)的余量超出了設(shè)定
的閾值范圍,此時(shí)程序會(huì)調(diào)用 audio_SetI2sWS 函數(shù)調(diào)整 I2S_BCLK 的分頻系數(shù)和 I2S 字長(zhǎng)來(lái)使調(diào)整 I2S 的傳輸速率,使環(huán)形緩沖區(qū)的余量盡快回歸到閾值范圍內(nèi),避免造成環(huán)形緩沖區(qū)的上溢或者下溢。關(guān)于調(diào)整 I2S_WS 的細(xì)節(jié),請(qǐng)參考更新 I2S 的傳輸速率。若不需要調(diào)整 I2S_WS,則直接調(diào)用 audio_GetAndTransmitSamples 函數(shù)將 gs_Interfaces[0].buffer 中的音頻數(shù)據(jù)拷貝 384個(gè)字節(jié)到 s_audioService_BufferOut 數(shù)組中,然后調(diào)用 audio_ConfigureLinkTxDma 函數(shù)開(kāi)始一個(gè)新的 DMA 傳輸,從
s_audioService_BufferOut 數(shù)組中搬運(yùn) 384 個(gè)字節(jié)到 I2S TX 數(shù)據(jù)寄存器中。
2.7 更新 I2S 的傳輸速率
由上一節(jié)的內(nèi)容可知,如果環(huán)形緩沖區(qū)的余量超出了閾值范圍,那么需要在當(dāng)前 DMA 傳輸完成觸發(fā)的中斷服務(wù)函數(shù)中調(diào)用
audio_SetI2sWS 函數(shù)去更新 I2S_WS。根據(jù) KL27 的時(shí)鐘分配中的描述,I2S_BCLK 是由 I2S_MCLK 分頻得到,且 I2S_BCLK =
I2S_MCLK/(DIV+1)/2 = I2S_WS * 2 * WordLength,因此我們可以通過(guò)修改 I2S_BCLK 的分頻系數(shù)和字長(zhǎng)來(lái)調(diào)整 I2S_WS。

由 圖 9 可知,I2S_BCLK 的分頻系數(shù)只能為偶數(shù),初始的 DIV 的值為 9,此時(shí)分頻系數(shù)為 20,此時(shí) I2S_BCLK = 48M /20
=2.4M。若要增加 I2S_BCLK,需要將 DIV 的值設(shè)置為 8,此時(shí)分頻系數(shù)為 18,I2S_BCLK = 48M / 18 = 2.67M, I2S_WS =
I2S_BCLK/2/25bit =53.3K。若要減小 I2S_BCLK, 需要將 DIV 的值設(shè)置為 10,此時(shí)分頻系數(shù)為 22,I2S_BCLK = 48M / 22 =
2.18M,I2S_WS = I2S_BCLK/2/25bit =43.6K。

如果只修改 I2S_BCLK 的分頻系數(shù),得到的 I2S_WS 與 48K 采樣率相差較大,此時(shí)還可以調(diào)整 I2S 字長(zhǎng)以獲得更接近 48K 的采樣率,如當(dāng)分頻系數(shù)為 22 時(shí),將字長(zhǎng)修改為 24bit,此時(shí) I2S_WS = I2S_BCLK/2/24 = 45.4K。本例程中使用了如 表 3 中列出的三種 I2S_WS 頻率。
表 3. 三種 I2S_WS 頻率的配置


本例程中使用了 47619,48000,和 48387 三種 I2S_WS 頻率來(lái)匹配 USB 主機(jī)的發(fā)送速率。在 USB 中斷服務(wù)函數(shù)中周期的檢測(cè)
環(huán)形緩沖區(qū)的余量并及時(shí)調(diào)整 I2S_BCLK 和 I2S_WS 來(lái)避免環(huán)形緩沖區(qū)中的音頻數(shù)據(jù)上溢和下溢。關(guān)于更多更新 I2S_WS 的細(xì)
節(jié),請(qǐng)參考 AN13364SW。
3 測(cè)試
將修改之后的 SDK 代碼下載到 NxH3670 SDK 板中并運(yùn)行程序,圖 11 為使用邏輯分析器抓取的 I2S 信號(hào),測(cè)試時(shí)使用的USB
主機(jī)為 Windows 10。

相關(guān)推薦

電子產(chǎn)業(yè)圖譜