基于NXP iMX6ULL 擴展音頻解碼器 MAX98357A

By Toradex胡珊逢

Colibri iMX6ULL?是?Toradex?面向低成本設備推出的?Arm?計算機模塊。該產(chǎn)品沒有音頻編解碼器,無法直接輸出模擬音頻信號。本文將介紹如何使用模塊的數(shù)字音頻I2S?接口擴展MAX98357A,包括如何配置device tree?和時鐘。

在?Colibri iMX6ULL?模塊上的i.MX 6ULL SoC?通過synchronous audio interfaces?(SAI)接口提供數(shù)字音頻接口,可以支持AC97?或者I2S?以連接外部音頻編解碼器。MAX98357A?是一款易于使用的音頻解碼器,片上帶有?D?類功放。無需?I2C?配置和外部?MCLK?時鐘,進一步簡化電路設計。接下來我們使用Colibri iMX6ULL?搭配?Colibri Evaluation Board,安裝?Linux BSP 5.4?為例進行說明。

Colibri iMX6ULL?總共有三個SAI?接口,這里使用SAI2?連接?MAX98357A。



根據(jù)上面的連接關系,對應修改?device tree。在?imx6ull-colibri-eval-v3.dtsi中首先增加一個codec_ext?節(jié)點。

---------------------------------------------

codec_ext: max98357a@0 {????compatible = "maxim,max98357a";????#sound-dai-cells = <0>;};

---------------------------------------------

然后再添加一個simple audio card?的節(jié)點?sound。其中的sound-dai?引用了上面的定義的?codec_ext。

---------------------------------------------

sound {????compatible = "simple-audio-card";????status = "okay";????simple-audio-card,name = "max98357a";????simple-audio-card,format = "i2s";????simple-audio-card,bitclock-master = <&dailink_master_cpu>;????simple-audio-card,frame-master = <&dailink_master_cpu>;????simple-audio-card,codec {????????sound-dai = <&codec_ext>;????};????dailink_master_cpu: simple-audio-card,cpu {????????sound-dai = <&sai2>;????};};

---------------------------------------------


上面的sound?節(jié)點中使用了sai2,因此接下來需要對?sai2進行初始化。

---------------------------------------------

&sai2 {????pinctrl-names = "default";????pinctrl-0 = <&pinctrl_sai2>;????assigned-clocks = <&clks IMX6UL_CLK_SAI2_SEL>,??????????????<&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;????assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;????assigned-clock-rates = <2>, <196608000>;????fsl,sai-asynchronous;????/*fsl,sai-mclk-direction-output;*/????status = "okay";};

---------------------------------------------


這里有幾個關鍵的參數(shù)。pinctrl_sai2?配置了引腳復用關系。對于MAX98357A?實際上只需要前面三個引腳,如前面表格中列出的連接關系。MX6UL_PAD_JTAG_TMS__SAI2_MCLK?和MX6UL_PAD_JTAG_TMS__CCM_CLKO1?為了方便測試相關時鐘信號。而這兩個其實是同一個引腳,只是復用功能選擇不同。sound?節(jié)點中fsl,sai-mclk-direction-output;?參數(shù)同樣也是為了測試SAI?的MCLK?輸出,配合MX6UL_PAD_JTAG_TMS__SAI2_MCLK?輸出SAI MCLK,但該信號并不用于?MAX98357A。

---------------------------------------------

pinctrl_sai2: sai2grp {????????fsl,pins = <????????????MX6UL_PAD_JTAG_TDI__SAI2_TX_BCLK ???0x1F089????????????MX6UL_PAD_JTAG_TDO__SAI2_TX_SYNC ???0x17088????????????MX6UL_PAD_JTAG_TRST_B__SAI2_TX_DATA ???0x11088????????????/*MX6UL_PAD_JTAG_TMS__SAI2_MCLK ???????0x17088*/????????????MX6UL_PAD_JTAG_TMS__CCM_CLKO1 ??0x17088????????>;????};};

---------------------------------------------


sound?節(jié)點中還有三個重要屬性,assigned-clocks,assigned-clock-parents?和?assigned-clock-rates。在介紹這些屬性前,我們簡單了解下iMX6ULL?的Clock Controller Module(CCM)。

CCM?負責產(chǎn)生和控制?iMX6ULL?上每個模塊運行所需的時鐘信號,包括從?Arm CPU?核心到各種外設如?USB、Audio、網(wǎng)絡等。由于每個模塊需要的時鐘各不相同,從高頻到低頻,因此?CCM?內(nèi)部有多個?PLL?以及分頻器提供多種頻率的時鐘信號。對于本次使用的SAI?模塊,根據(jù)iMX6ULL?芯片手冊Figure 18-2. Clock Tree - Part 1,其時鐘關系如下。



SAI2_CLK_ROOT?通過MUX?可以選擇三個來源,分別是PLL3,PLL4,PLL5。中間會有多個不同位數(shù)的分頻器,將?PLL?輸出較高的時鐘逐級降為較低的頻率。這些分頻器并不需要手動設置,CCM?驅(qū)動會根據(jù)期望輸出的頻率自動計算合適的分頻比例。SAI2_CLK_ROOT?最終為SAI2?模塊提供運行時鐘信號。在SAI?內(nèi)部,時鐘信號經(jīng)過內(nèi)部的分頻器后產(chǎn)生I2S?的bit block?以及幀同步信號?sync。


對于音頻文件,可以計算出所需的?bit clock。例如對于一個雙通道,16bit,48K采樣率的音頻文件,bit clock = 16x2x48000 = 1536000。這個數(shù)值是我們所需的最終目標時鐘。根據(jù)上面的圖示,?bit clock?源自于?PLL4。根據(jù)iMX6ULL?芯片手冊18.5.1.3.4 Audio/video PLL?章節(jié),該PLL?的頻率范圍從650MHz?到?1.3GHz。以?1536000?為基數(shù),取其整數(shù)?512?倍,得到?786432000。即?786432000?經(jīng)過總共?512?倍分頻后可以產(chǎn)生?1536000 bit clock?信號。這時我們再回顧?sai2?節(jié)點中的一些時鐘屬性。

---------------------------------------------

assigned-clocks = <&clks IMX6UL_CLK_SAI2_SEL>,????????????<&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;assigned-clock-parents = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;assigned-clock-rates = <2>, <196608000>;

---------------------------------------------


IMX6UL_CLK_SAI2_SEL?設置的?CCM_CSCMR1?寄存器中的?SAI2_CLK_SEL?位。這里設置為?2,?選擇?PLL4?作為時鐘源。IMX6UL_CLK_PLL4_AUDIO_DIV?為?PLL4?分頻后的時鐘,設置為?19660800,這個數(shù)值是?1536000?的?24?倍。而PLL4?在分頻前為786432000,這是IMX6UL_CLK_PLL4_AUDIO_DIV?的4?倍,在其650MHz?到1.3GHz?的頻率范圍內(nèi)。



完成上面device tree?修改后,重新編譯,并更新到?Colibri iMX6ULL。下面命令可以直接在模塊上覆蓋原來的dtb?文件。

---------------------------------------------

root@colibri-imx6ull:~# ubiupdatevol /dev/ubi0_1 imx6ull-colibri-eval-v3.dtb

---------------------------------------------


重啟后可以看到max98357a?音頻設備。

---------------------------------------------

root@colibri-imx6ull:~# aplay -l**** List of PLAYBACK Hardware Devices ****card 0: max98357a [max98357a], device 0: 202c000.sai-HiFi HiFi-0 []??Subdevices: 1/1??Subdevice #0: subdevice #0

---------------------------------------------


同時在clock tree?中也可以看到sai2?相關時鐘。PLL4?輸出786432000,4?分頻輸出196608000Hz?的?pll4_audio_div。MUX?之后通過pred 4?分頻輸出49152000Hz,再通過podf 2?分頻輸出24576000Hz?的SAI2_CLK_ROOT,為SAI2?模塊運行提供時鐘信號。

---------------------------------------------

root@colibri-imx6ull:~# cat /sys/kernel/debug/clk/clk_summary????pll4 ?????????????????????????????0 ???????0 ???????0 ??786432000 ?????????0 ????0 ?50000???????pll4_bypass ???????????????????0 ???????0 ???????0 ??786432000 ?????????0 ????0 ?50000??????????pll4_audio ?????????????????0 ???????0 ???????0 ??786432000 ?????????0 ????0 ?50000?????????????pll4_post_div ???????????0 ???????0 ???????0 ??196608000 ?????????0 ????0 ?50000????????????????pll4_audio_div ???????0 ???????0 ???????0 ??196608000 ?????????0 ????0 ?50000???????????????????sai2_sel ??????????0 ???????0 ???????0 ??196608000 ?????????0 ????0 ?50000??????????????????????sai2_pred ??????0 ???????0 ???????0 ???49152000 ?????????0 ????0 ?50000?????????????????????????sai2_podf ??????0 ???????0 ???????0 ???24576000 ?????????0 ????0 ?50000????????????????????????????sai2 ??????0 ???????0 ???????0 ???24576000 ?????????0 ????0 ?50000

---------------------------------------------

CCM?提供了兩個引腳?CCM_CLKO1?和?CCM_CLKO2?可以輸出相關時鐘進行測試。在上面的device tree SAI2?節(jié)點引腳配置中我們也使能該引腳?MX6UL_PAD_JTAG_TMS__CCM_CLKO1 0x17088。



根據(jù)CCM_CCOSR?寄存器CLKO2_SEL?位,sai2_clk_root?位于CCM_CLKO2, CLK_OUT_SEL?位允許CCM_CLKO1?上輸出CCM_CLKO1?或?CCM_CLKO2。因此,可以通過向CCM_CCOSR?寄存器寫入0x01130180,在?模塊SODIMM 71?引腳上啟用CCM_CLKO1?,輸出sai2_clk_root?信號。在?Colibri iMX6ULL?上運行下面命令。

---------------------------------------------

root@colibri-imx6ull:~# devmem2 0x020c4060 w 0x01130180

---------------------------------------------


在?Colibri iMX6ULL?上用下面命令播放一個雙通道,16bit,48K采樣率的音頻文件,此時測量?SODIMM 71?引腳上輸出的波形。

---------------------------------------------

root@colibri-imx6ull:~# aplay -D sysdefault:CARD=max98357a LRMonoPhase4.wav -vv

---------------------------------------------



上面圖中可以看到波形頻率為?24.5MHz。即?PLL4?經(jīng)過多次分頻后產(chǎn)生的時鐘。再次播放上面的音頻文件,測量SODIMM 31?的bit clock?和SODIMM 23?幀同步sync?信號?



bit clock?頻率為1.53MHz,幀同步sync?為?48KHz。這也是上面計算雙通道,16bit,48K采樣率的音頻?bit clock?數(shù)值。這些信號的實際輸出都符合預期。如果開啟?SAI?驅(qū)動的調(diào)試日志輸出功能,在播放音頻文件后還可以發(fā)現(xiàn)其他的一些信息。在?SAI?驅(qū)動源碼的第一行添加#define DEBUG,然后重新編譯?zImage。

---------------------------------------------

[ ??49.838293] fsl-sai 202c000.sai: clk_rate 0 Hz, ?mclk_clk id 0[ ??49.838316] fsl-sai 202c000.sai: clk_rate 24576000 Hz, ?mclk_clk id 1[ ??49.838328] fsl-sai 202c000.sai: ratio 16 for freq 1536000Hz based on clock 24576000Hz[ ??49.838351] fsl-sai 202c000.sai: best fit: clock id=1, ratio=16, deviation=0

---------------------------------------------


1536000Hz?的bit clock?是通過24576000Hz?進行16?分頻得到的。這是因為在SAI?內(nèi)部還有一個分頻器可以對sai2_clk_root?再次分頻從而輸出合適的?bit clock。I2S2_TCR2?寄存器(地址0x0202c008)的最后7?位DIV?可以配置該分頻器。分頻數(shù)值為?(DIV + 1)x2。讀取該寄存器,DIV?值為?7,進行?16?分頻。對應上面SAI?驅(qū)動調(diào)試日志的?“ratio 16 for freq 1536000Hz based on clock 24576000Hz”。

---------------------------------------------

root@colibri-imx6ull:~# devmem2 0x0202c008 w/dev/mem opened.Memory mapped at address 0x76f4b000.Read at address ?0x0202C008 (0x76f4b008): 0x07000007

---------------------------------------------


最后接上?MAX98357A?和揚聲器就可以聽到播放的音頻文件。

https://v.youku.com/v_show/id_XNTgzMjUxMTg2NA==.html



總結(jié)

通過擴展?MAX98357A?我們介紹了?iMX6 ULL SoC?音頻驅(qū)動?SAI?的工作原理,以及如何配置?device tree?和測試方法。借鑒該方法,用戶也可以擴展其他基于?I2S?的音頻編解碼器。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容