音频芯片WM8976基于Windows CE6.0的驱动调试笔记 --------基于X210开发板 2011年10月7日 有一年多没有写过代码了,最近因朋友要求,移植X210-S5PV210开发板中音频驱动.这款开发板选用的CODEC芯片是wolfson 的WM8976.因以前在三星的S3C2450.S3C6410上都移过这款芯片的驱动.本以为可以很快移完.想不到是的花了我整个5天国庆假期.由于以前没有记笔记的习惯,现在记性也不好了.所以今天特记录下来.写音频驱动架构的资料网上比较多,有些介绍比较完善,所以在此本人只从调试过程做些记录. 音频驱动是典型的流驱动.三星原厂开发板的BSP包有示例代码.由于X210-S5PV210开发板采用的CODEC芯片不同,所以移植从以下几方面入手, 1. 先保证调试I2S通道的频率正常. 2. 保证有音频数据输出 3. 保证I2C正常通信. 4. 修改CODEC WM8976相关控制代码. 一. I2S通道的频率 I2S音频正常工作需要以下几路信号 IISSCLK ------------------- 采样时钟 IISLRCLK ------------------ 左右声道的时钟 IISCDCLK ------------------ 主时钟 IISSDO ------------------- IIS格式音频数据输出 IISSDI ------------------- IIS格式音频数据输入 S5PV210的IIS通道做master,WM8976作为slave.所以IISSCLK IISLRCLK,IISCDCLK三个时钟都由S5PV210产生,提供给音频WM8976芯片. IISSCLK 采用44.1Khz的采样率. IISLRCLK 根据210芯片手册采用32fs,即1.4112Mhz.(注:fs就是采样频率44.1Khz.) IISCDCLK 根据210芯片手册采用256fs ,即11.289Mhz 经以上分析,正式开始移植, X210开发板音频所采用的IIS1通道与三星原厂的IIS0不同,所以把所有通道改为I2S1.示波器抓IISSCLK IISLRCLK,IISCDCLK引脚的波形,发现时钟频率不对.有时钟输出,说明IIS通道已从IIS0改到IIS1通道. 接下来就是查找为何时钟频率不对的原因.仔细查看S5PV210芯片手册,主要时钟配置在IISMOD寄存器,按手册配置后,时钟频率一直不对.多次配置后,要么 IISCDCLK 11.289Mhz. IISSCLK 470.4khz IISLRCLK 14.7hz 要么 当把IISCDLK 66.7MHZ时 IISSCLK 1.4112Mhz IISLRCLK 44.1Khz 以为手册上有寄存器没有配置到位,所以反复看了几遍,一下无果.这问题一直持续了好几天.就卡在正确的频率出不来.郁闷之极啊. 后来发现IISLRCLK引脚上的波形很规则,是有规律的被拉成高高低低的台阶,怀疑CODEC芯片也输出波形,从而造成正常的波形被影响.查看WM8976寄存器初始化值,发现是被配成SLAVE模式,原理上应该不会有数据输出.为了进一步验证这个结果,屏蔽掉IIS寄存器的初始化代码.也就是不让主控芯片输出IIS的相关时钟,来检测WM8976上是否有时钟输出.结果测量IISLRCLK,发现时钟信号并不存在.证明WM8976并没有输出时钟信号.到此时,似乎没有任何思路了. 绝望中寻找希望.在后来的调试中,屏蔽掉I2C对WM8976的代码后,时钟频率奇迹般正确分频了.看来问题出在I2C和WM8976的配置通信中,原因后面会分析. IISCDCLK 11.289Mhz. IISSCLK 1.4112Mhz IISLRCLK 44.1Khz 呵呵,接下来的工作比较好办了. 二. 保证有数据输出 有音频数据输出时, IISLRCLK会输出44.1Khz的采样频率时钟,同时IISSDO会在频率输出.如果没有,则查DMA通道是否有数据送出.通过加打印信息跟踪即可.在有了时钟和数据输出后,接下来就是控制音频芯片工作了. 三. 保证I2C的正常通信 音频芯片WM8976的控制通信接口是采用I2C接口,由于CODEC 芯片WM8976无法读取内置寄存器值.所以不能通过I2C读取CODEC ID来验证是否读操作是否正常.自然也不能通过读写进去的值来验证I2C写操作是否正常. 因为在上面的步骤当中,设置频率时出现的问题,可判定I2C操作是对CODEC有影响的,认为是正常通信.只是写进去的值不对而导致影响到主控芯片S5PV210提供的时钟频率.仔细查看读写寄存器的函数,发现的问题所在. 在此不得不说下WM8976芯片寄存器的特点.WM8976的寄存器值有9位.通常我们对I2C器件写数据时,都是8bit数据.为此,在往WM8976芯片中写数据时,需按以下规格处理 高7位寄存器地址
| 9b
| 8位数据位
| 7b
| 6b
| 5b
| 4b
| 3b
| 2b
| 1b
| 0b
| 7b
| 6b
| 5b
| 4b
| 3b
| 2b
| 1b
| 0b
| | | | | | | | | | | | | | | | |
CODEC寄存器地址左移一位,D0位用于存放数据寄存器的最高位D8.函数实现如下,见蓝色字体部分: Void HardwareContext::WriteCodecRegister(WORD wReg, WORD wVal) { BYTE btWriteBuffer[2]; btWriteBuffer[0] = (BYTE)(wReg<<1)|(BYTE)((wVal>>8)&1); btWriteBuffer[1] = (BYTE)(wVal&0xFF); WriteI2C_CODEC(m_hI2CCodec, btWriteBuffer, 2); DBGMSG(WAVE_CODEC, (L"[WAV] WRITE ADDR : 0x%04X, DATA : 0x%04X\r\n", wReg, wVal)); } 在WM8976寄存器数值的数组如下 // WM8976 Codec-chip Initialization Value unsigned int WM8580_Codec_Init_Table[][2] =\ { {0x00,0x00},//R0 software reset {0x03,0xed},//R1 power management 1--PLL 0ff {0x05,0x80},//R2 power management 2 …… }; 数组WM8580_Codec_Init_Tabl[][2]中的寄存器地址和数据已经做了移位处理, WriteCodecRegister()再进行移位处理,造成了数据全部错位.所以解决办法是只保留一次移位操作.即可.改之.声音出来了 四. 修改WM8976的控制代码 参考以前的WM8976的初始化代码和WM8976的数据手册,完成相关的控制. 总结: 此时调试时间主要花在配置时钟频率.原因就是CODEC音频芯片的影响,由于对三星S5PV210芯片不熟悉,一直怀疑S5PV210寄存器配置有问题. 虽然分析过CODEC对时间频率的影响,正确的排除法是去除I2C对CODEC的初始化代码或根本就不给CODEC上电.但这款X210开发板是直接上电,没有GPIO控制. |