板所使用的arm芯片是imx6q,原bsp开发包所使用的音频芯片是CS42448,并且使用接口是EASI,与我们开发板是完全不同。我的开发板的CODEC硬件原理图:
sgtl5000 通过I2S接口与IMX6的SSI总线完成音频数据的交换;cpu通过I2C或者SPI完成对CODEC的控制,由于
硬件设计是I2C的接口,所以我们通过I2C来完成对CODEC的控制。
在调试过程中,我们从mx6q-sabrelite版本中将sgtl5000的驱动拷贝了过来进行调试。需要注意的是I2S的协议,
I2S协议类似于I2C协议,需要指定主备模式,主设备将会为备设备提供I2S的Bit时钟和声道选择时钟。在startup初
始化过程中,需要调试ssi模块的初始化。
SSI、AUDIO与CODEC之间的关系以及数据的流向?
对于IMX6Q来讲:AUDIO模块分为internal port和external port
两种端口类型。internal port是硬连接于ssi的,
不可以更改,其对应关系是:inter_port1<-->SSI1,
inter_port2<--->SSI2,inter_port7<--->SSI3;而external port
对应的
是3-6,对应的外部管脚AUDIO3-AUDIO6。
内外部端口结构图如下:
我们可以通过配置audio1-7的寄存器完成内外部端口之间的映射,比如可以配置port3的数据源以及TXFS和TXC
的方向和源。需要特别注意的是,这个配置需要和I2S两端配置的主备模式要协调一致。在调试过程中最早出现的问题
就是由于该内外部端口的主备模式相反,导致一直没有声音。例如若CODEC配置为MASTER模式,则I2S协议中用到
的TXC和TXFS时钟信号都是由COEC提供
的,则
AUDIO模块内的external port应该配置为output模式,也就是
master模式,否则相反。
与internal port硬连接的SSI模块需要配置为I2S模式,该模式的配置是在CODEC中的ssi的初始化接口中完成,
移植过来的代码可以直接使用,无需更改。需要特备注意的是,我们需要在startup中完成ssi模块正常工作的时钟配置。
代码如下:
- //#define CODEC_SLAVE 1
- #if defined (CODEC_SLAVE) //imx6q:master, codec:slave
- {
- /*
- * Note that bits [20:19] are defined differently by the i.MX6 Quad/Dual compared to the i.MX6 DualLite/Solo
- * The i.MX6 Solo/DualLite use bits 20:19 to control a PLL post-divider, whereas the Quad/Dual use bits 20:19
- * for testing purposes.
- */
- #define PLL_AUDIO_CTRL_POST_DIV_1 (0x3 << 19)
- #define PLL_AUDIO_CTRL_BYPASS (1 << 16)
- #define PLL_AUDIO_CTRL_ENABLE (1 << 13)
- #define PLL_AUDIO_CTRL_POWERDOWN (1 << 12)
- #define PLL_AUDIO_CTRL_MFI_MASK (0x7F << 0) /* In the docs these bits are labeled DIV_SELECT */
- #define CCM_ANALOG_PLL_AUDIO_CTRL 0x70
- #define CCM_ANALOG_PLL_AUDIO_CTRL_SET 0x74
- #define CCM_ANALOG_PLL_AUDIO_CTRL_CLR 0x78
- #define CCM_ANALOG_PLL_AUDIO_NUM 0x80
- #define CCM_ANALOG_PLL_AUDIO_DENOM 0x90
- //This register contains the numerator (A) of Audio PLL fractional loop divider.
- out32(MX6X_ANATOP_BASE + CCM_ANALOG_PLL_AUDIO_NUM, 0x2a0);
- //This register contains the Denominator (B) of Audio PLL fractional loop divider
- out32(MX6X_ANATOP_BASE + CCM_ANALOG_PLL_AUDIO_DENOM, 0x3e8);
- //The control register provides control for the audio PLL.
- //This field controls the pll loop divider. Valid range for DIV_SELECT divider value: 27~54.
- out32(MX6X_ANATOP_BASE + CCM_ANALOG_PLL_AUDIO_CTRL_CLR, PLL_AUDIO_CTRL_MFI_MASK);
- //DIV_SELECT = 28 POST_DIV_SELECT = 0x3
- out32(MX6X_ANATOP_BASE + CCM_ANALOG_PLL_AUDIO_CTRL_SET, (0x1c & PLL_AUDIO_CTRL_MFI_MASK) | PLL_AUDIO_CTRL_POST_DIV_1);
- /* Power up and enable Audio PLL (PLL4) */
- out32(MX6X_ANATOP_BASE + CCM_ANALOG_PLL_AUDIO_CTRL_CLR, PLL_AUDIO_CTRL_BYPASS | PLL_AUDIO_CTRL_POWERDOWN);
- out32(MX6X_ANATOP_BASE + CCM_ANALOG_PLL_AUDIO_CTRL_SET, PLL_AUDIO_CTRL_ENABLE);
- /* the clock frequence of ssi2 is 12.288MHz*/
- init_ssi2_clk();
- init_audiomux(2, 3);
- }
- #else //imx6q:slave, codec:master
- {
- init_audiomux(3, 2);
- }
- #endif
,该门时钟主要是控制芯片内部各个模块的时钟使能标记。主要是为了降低功耗。如下:
我们在上文配置的ssi时钟其实配置的是SSI_CLK_ROOT,该时钟的主要作用是为了产生SSI作为I2S模式下作为
MASTER
时所需要用的TXC和TXFS时钟,而SSI模块正常工作的时钟是由ipg_clk_root所提供的,
而该时时钟是由AHB时钟2分频得到的。
具体应用如下:
所以上图中的World Clock和Serial Bit Clock都是由SSI's sys clock产生的。而SSI's sys clock对应的就是
SSI_CLK_ROOT时钟源。因此我们除配置完ssi模块工作在I2S模式下的协议时钟外,还需要配置SSI模块
正常工作的时钟,即配置CCM模块
的CGR5寄存器时钟SSI_CLK_ENABLE。