原创 基于NXP iMX6ULL 扩展音频解码器 MAX98357A

2022-1-7 10:52 1715 12 12 分类: MCU/ 嵌入式

By Toradex胡珊逢

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

 Colibri iMX6ULL 模块上的 i.MX 6ULL SoC 通过 synchronous audio interfaces SAI接口提供数字音频接口可以支持 AC97 或者 I2S 以连接外部音频编解码器。MAX98357A 是一款易于使用的音频解码器,片上带有 类功放。无需 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 输出 786432000分频输出 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 的音频编解码器。


作者: hai.qin_651820742, 来源:面包板社区

链接: https://mbb.eet-china.com/blog/uid-me-1864768.html

版权声明:本文为博主原创,未经本人允许,禁止转载!

文章评论0条评论)

登录后参与讨论
我要评论
0
12
关闭 站长推荐上一条 /2 下一条