IMX6 中的wm8962 DC servo timed out报错

程序里要用到音频播放,由于方案公司提供的测试就是aplay xx.wav,没有基于alsa声卡框架的测试源码,没有办法,在网上下载了alsa-lib及alsa-utils,编译通过后,再把播放器源码里面的播放音频及设置音量部分抠出来集成到自己的应用程序里面;完成了这部分工作后,就开始测试应用程序;
在测试过程中,遇到一个很奇怪的现象,那就是系统第一次启动后,执行自己的app程序,概率性会报wm8962 DC servo timed out错误,然后播放音频的线程就死掉了;更奇怪的是方案公司那边技术说从未遇到这个问题,我也是无语,我用原版sdk,原版测试方法来测试,我的就有,他们就没有;
在声卡驱动文件wm8962.c找到报错的地方
IMX6 中的wm8962 DC servo timed out报错其中WM8962_DC_SERVO_6的值是0x42,看字面意思即读出寄存器的值与预期的值不匹配,一共读200次,200次都读到不对的值就报错
去wm8962芯片手册,找到0x42寄存器
IMX6 中的wm8962 DC servo timed out报错这是个状态寄存器,读出来的值是0,实际上期望的7,8位的值是1

继续跟进程序发现,系统启动后的第一次播放并未卡死在内核,在内核部分,读出寄存器匹配不成功超时后就返回了,但是应用程序是卡死了,多次使用printf后,发现应用程序卡死在这里
IMX6 中的wm8962 DC servo timed out报错play.c的playback_go函数里面,这个函数的作用是读声音文件,然后往声卡里面写数据来播放,怪的是发生错误的时候,它并不是全部写不成功,而是写了一部分数据到声卡里面了,然后后面的写就不成功了,我猜想的原因是声卡的缓冲区有限,由于open函数进行初始化配置的时候并没有完全成功,导致pcm_write写入的数据并未被声卡拿去播放,一般这种都喜欢用环形缓冲区,缓冲区写满后,后面的就写不进去了,然后程序一直阻塞在这里;

系统内核加载声卡阶段,并未报任何声卡异常,这个错误意思是在app程序调用snd_pcm_open的时候,到调用到内核里面上面截图部分出现的错误,意思就是说,app打开声卡设备,配置一些声卡的状态并未完全成功,经过测试发现,系统启动后第一次播放概率性失败,ctrl+c中止当前进程后,每次播放都成功,直到下一次重新启动系统才有可能会播放失败;

顺着这个思路,看看ctrl+c后系统干了些什么事情,ctrl+c会发送一个信号,强行杀死当前前台进程,找到该信号的信号处理函数,信号处理函数里面会关闭设备,以及做一些释放配置的事情;

做一个现象模拟测试程序,启动后播放两次,第一次播放只打开设备,初始化,关闭设备,释放资源的工作,而屏蔽掉真正的播放部分(几屏蔽把声音数据搬往声卡的过程),以防止卡死;第二次播放才是打开设备,初始化配置,播放,直至完成,这样的确可以在第一次播放超时后,进入第二次播放,顺利播放音频;
测试过程发现,第一次假象播放里面snd_config_update_free_global(),这个函数重点不能少,它里面有snd_config_delete(snd_config); snd_config_update_free(snd_config_global_update);这两个函数,看字面意思就是删除配置,释放及更新资源了,下一次播放就能顺利进行了;

还是觉得奇怪,假象播放和正常播放都是一样的初始化及配置流程,为什么先一定要进行一次假象播放呢,是哪里动了声卡的配置,而且没有还原?看了启动脚本,里面果然有调用声卡进行声卡测试的部分,好吧,那我把里面对应的部分删除掉了,另外app程序里面开机后还是会做一次假象播放,以防止播放出错,暂时先这样顶着用,毕竟赶时间;

这个问题并未完全解决,真正要找到wm8962那个状态寄存器没有成功置位的原因,alsa框架比较复杂,而且nxp论坛看到有的说这个和电源部分相关,好在找到一个方法能先顶一下,等忙完这阵子,我再来彻底解决你这个bug;