新闻  |   论坛  |   博客  |   在线研讨会
基于NXP iMX6ULL 扩展音频**** MAX98357A
toradex | 2022-01-07 10:54:24    阅读:323   发布文章

By Toradex胡珊逢

Colibri iMX6ULL Toradex 面向低成本设备推出的 Arm 计算机模块。该产品没有音频编****,无法直接输出模拟音频信号。本文将介绍如何使用模块的数字音频 I2S 接口扩展 MAX98357A包括如何配置 device tree 和时钟。

 Colibri iMX6ULL 模块上的 i.MX 6ULL SoC 通过 synchronous audio interfaces SAI接口提供数字音频接口可以支持 AC97 或者 I2S 以连接外部音频编****。MAX98357A 是一款易于使用的音频****,片上带有 D 类功放。无需 I2C 配置和外部 MCLK 时钟,进一步简化电路设计。接下来我们使用 Colibri iMX6ULL 搭配 Colibri Evaluation Board安装 Linux BSP 5.4 为例进行说明。

Colibri iMX6ULL 总共有三个 SAI 接口这里使用 SAI2 连接 MAX98357A

基于NXP iMX6ULL 扩展音频**** MAX98357A_web860.png 

 

根据上面的连接关系对应修改 device tree。在 imx6ull-colibri-eval-v3.dtsi中首先增加一个 codec_ext 节点。

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

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

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

然后再添加一个 simple audio card 的节点 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 节点中使用了 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";
};

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

 

这里有几个关键的参数。pinctrl_sai2 配置了引脚复用关系。对于 MAX98357A 实际上只需要前面三个引脚如前面表格中列出的连接关系。MX6UL_PAD_JTAG_TMS__SAI2_MCLK  MX6UL_PAD_JTAG_TMS__CCM_CLKO1 为了方便测试相关时钟信号。而这两个其实是同一个引脚,只是复用功能选择不同。sound 节点中 fsl,sai-mclk-direction-output; 参数同样也是为了测试 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 节点中还有三个重要属性assigned-clocksassigned-clock-parents  assigned-clock-rates。在介绍这些属性前我们简单了解下 iMX6ULL  Clock Controller ModuleCCM

CCM 负责产生和控制 iMX6ULL 上每个模块运行所需的时钟信号,包括从 Arm CPU 核心到各种外设如 USBAudio、网络等。由于每个模块需要的时钟各不相同,从高频到低频,因此 CCM 内部有多个 PLL 以及分频器提供多种频率的时钟信号。对于本次使用的 SAI 模块根据 iMX6ULL 芯片手册 Figure 18-2. Clock Tree - Part 1其时钟关系如下。

基于NXP iMX6ULL 扩展音频**** MAX98357A_web1952.png 

 

SAI2_CLK_ROOT 通过 MUX 可以选择三个来源分别是 PLL3PLL4PLL5。中间会有多个不同位数的分频器,将 PLL 输出较高的时钟逐级降为较低的频率。这些分频器并不需要手动设置,CCM 驱动会根据期望输出的频率自动计算合适的分频比例。SAI2_CLK_ROOT 最终为 SAI2 模块提供运行时钟信号。在 SAI 内部时钟信号经过内部的分频器后产生 I2S  bit block 以及帧同步信号 sync

基于NXP iMX6ULL 扩展音频**** MAX98357A_web2173.png 

对于音频文件,可以计算出所需的 bit clock。例如对于一个双通道,16bit48K采样率的音频文件,bit clock = 16x2x48000 = 1536000。这个数值是我们所需的最终目标时钟。根据上面的图示 bit clock 源自于 PLL4。根据 iMX6ULL 芯片手册 18.5.1.3.4 Audio/video PLL 章节 PLL 的频率范围从 650MHz  1.3GHz。以 1536000 为基数,取其整数 512 倍,得到 786432000。即 786432000 经过总共 512 倍分频后可以产生 1536000 bit clock 信号。这时我们再回顾 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>;

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

 

IMX6UL_CLK_SAI2_SEL 设置的 CCM_CSCMR1 寄存器中的 SAI2_CLK_SEL 位。这里设置为 2, 选择 PLL4 作为时钟源。IMX6UL_CLK_PLL4_AUDIO_DIV PLL4 分频后的时钟,设置为 19660800,这个数值是 1536000 24 倍。而 PLL4 在分频前为 786432000这是 IMX6UL_CLK_PLL4_AUDIO_DIV  4 在其 650MHz  1.3GHz 的频率范围内。

基于NXP iMX6ULL 扩展音频**** MAX98357A_web2763.png 

 

完成上面 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 输出 7864320004 分频输出 196608000Hz  pll4_audio_divMUX 之后通过 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 节点引脚配置中我们也使能该引脚 MX6UL_PAD_JTAG_TMS__CCM_CLKO1 0x17088

基于NXP iMX6ULL 扩展音频**** MAX98357A_web3255.png 

 

根据 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 上用下面命令播放一个双通道,16bit48K采样率的音频文件,此时测量 SODIMM 71 引脚上输出的波形。

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

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

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

 

基于NXP iMX6ULL 扩展音频**** MAX98357A_web3615.png 

上面图中可以看到波形频率为 24.5MHz。即 PLL4 经过多次分频后产生的时钟。再次播放上面的音频文件测量 SODIMM 31  bit clock  SODIMM 23 帧同步 sync 信号 

基于NXP iMX6ULL 扩展音频**** MAX98357A_web3721.png 

基于NXP iMX6ULL 扩展音频**** MAX98357A_web3723.png 

bit clock 频率为 1.53MHz帧同步 sync  48KHz。这也是上面计算双通道,16bit48K采样率的音频 bit clock 数值。这些信号的实际输出都符合预期。如果开启 SAI 驱动的调试日志输出功能,在播放音频文件后还可以发现其他的一些信息。在 SAI 驱动源码的第一行添加 #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 内部还有一个分频器可以对 sai2_clk_root 再次分频从而输出合适的 bit clockI2S2_TCR2 寄存器地址 0x0202c008的最后 7  DIV 可以配置该分频器。分频数值为 (DIV + 1)x2。读取该寄存器,DIV 值为 7,进行 16 分频。对应上面 SAI 驱动调试日志的 “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

基于NXP iMX6ULL 扩展音频**** MAX98357A_web4721.png 

 

总结

通过扩展 MAX98357A 我们介绍了 iMX6 ULL SoC 音频驱动 SAI 的工作原理,以及如何配置 device tree 和测试方法。借鉴该方法,用户也可以扩展其他基于 I2S 的音频编****。


*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客