1.概要
由于项目需要实现 4 路MIC 以及 2 路Speaker回采输入android系统,硬件是一个ES7210用来采集4路MIC,一个ES7243E用来采集2路Speaker回采,组成类似6路麦克风输入系统。系统SoC无法支持TDM,所以只能将两个设备挂I2S上进行来调试。本文说说驱动调试过程,对遇见的问题做一个记录。
2.整体架构流程
系统播放音频时,ES7243E回采数据,通过I2S传送给ES7210, 同时ES7210通过录音获取到4路MIC的数据,总共6路数据通过I2S传输给系统,系统通过算法将数据以16000hz来将数据分成6个通道的数据,其中4路为MIC,2路为Speaker。从而可以使用这数据进行录音降噪处理。
3. ES7210、ES7243E Driver
1.编译配置:
原厂提供了E7210、ES7243E 二合一 Driver 代码,将对应的driver代码放置如下路径,并配置好编译宏控。
kernel-4.14/sound/soc/codecs/
修改kernel-4.14/sound/soc/codecs/Makefile
obj-$(CONFIG_STARMINI_ES7210) += es7210/
2.配置设备树DTS:
提供过来的代码默认采用过的是I2C_detect方式注册。
可以通过宏控改dts方式注册
#define ES7210_MATCH_DTS_EN 1 //ES7210 match method select: 0: i2c_detect, 1:of_device_id
代码默认配置是用DTS方式注册I2C。
因此需要在对应项目的DTS内,写上对应的设备节点:
MicArray_1@40 {
compatible = "MicArray_1"; /* ES7210 这里是根据驱动内的of_device_id来配置*/
reg = <0x40>;
status = "okay";
};
es7243e@10 {
compatible = "es7243e";
reg = <0x10>;
status = "okay";
};
3. 驱动挂载:
因默认没有驱动内没有针对ES7243E DTS注册I2C的驱动代码,需要自己简单写下ES7243E注册设备的驱动代码。
static int es7243e_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *i2c_id)
{
struct es7210_priv *es7243e;
SMLOG("begin->>>>>>>>>>!\n");
es7243e = devm_kzalloc(&i2c->dev, sizeof(struct es7210_priv), GFP_KERNEL);
if (es7243e == NULL)
return -ENOMEM;
es7243e->i2c = i2c;
es7243e->tdm_mode = ES7210_WORK_MODE; //to set tdm mode or normal mode
dev_set_drvdata(&i2c->dev, es7243e);
i2c_clt1[1] = i2c; /* 原厂驱动默认是通过这个i2c_client数组来控制分别控制 ES7210、ES7243E */
SMLOG("end->>>>>>>>>>!\n");
return 0;
}
static int __exit es7243e_i2c_remove(struct i2c_client *i2c)
{
SMLOG("\n");
kfree(i2c_get_clientdata(i2c));
return 0;
}
static const struct i2c_device_id es7243e_i2c_id[] = {
{ "es7243e", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, es7243e_i2c_id);
static const struct of_device_id es7243e_dt_ids[] = {
{ .compatible = "es7243e", },//es7210_0
};
MODULE_DEVICE_TABLE(of, es7243e_dt_ids);
static struct i2c_driver es7243e_i2c_driver = {
.driver = {
.name = "es7243e",
.owner = THIS_MODULE,
.of_match_table = es7243e_dt_ids,
},
.probe = es7243e_i2c_probe,
.remove = __exit_p(es7243e_i2c_remove),
.class = I2C_CLASS_HWMON,
.id_table = es7243e_i2c_id,
};
/* 在如下代码内加上对ES7243E的注册函数 */
static int __init es7210_modinit(void)
{
int ret;
//,i;
//struct i2c_adapter *adapter;
// struct i2c_client *client;
SMLOG("%s enter es7210\n",__func__);
#ifdef !ES7210_MATCH_DTS_EN
adapter = i2c_get_adapter(ES7210_I2C_BUS_NUM);
if (!adapter) {
printk("i2c_get_adapter() fail!\n");
return -ENODEV;
}
printk("%s() begin0000",__func__);
for(i = 0; i < ADC_DEV_MAXNUM; i++) {
client = i2c_new_device(adapter, &es7210_i2c_board_info[i]);
printk("%s() i2c_new_device\n",__func__);
if (!client)
return -ENODEV;
}
i2c_put_adapter(adapter);
#endif
ret = i2c_add_driver(&es7243e_i2c_driver); /* add ES7243E driver */
if (ret != 0)
pr_err("Failed to register es7243E i2c driver : %d \n", ret);
ret = i2c_add_driver(&es7210_i2c_driver);
if (ret != 0)
pr_err("Failed to register es7210 i2c driver : %d \n", ret);
return ret;
}
4. 驱动配置:
/* 4路MIC 2路Speaker 则相当于有6路MIC进入 */
#define ES7210_TDM_ENABLE ENABLE
#define ES7210_CHANNELS_MAX MIC_CHN_6
/* 由于项目只用了一路I2S来抓取录音,需要配置将TDM的模式配置*/
#define ES7210_WORK_MODE ES7210_TDM_NLRCK_I2S
/* 这里根据LRCK、MCLK 频率来设置,具体要根据data sheet 跟示波器测量后来设置 */
#define ES7210_MCLK_LRCK_RATIO RATIO_768
/* 配置codec */
kernel-4.14/sound/soc/mediatek/common_int/mtk-soc-machine.c
static struct snd_soc_dai_link mt_soc_extspk_dai[] = {
{
.....
{
.name = "I2S1_AWB_CAPTURE",
.stream_name = MT_SOC_I2S2ADC2_STREAM_NAME,
.cpu_dai_name = MT_SOC_I2S2ADC2DAI_NAME,
.platform_name = MT_SOC_I2S2_ADC2_PCM,
#ifdef CONFIG_STARMINI_ES7210
.codec_dai_name = "ES7210 4CH ADC 1", /* 需要与ES7210 driver 内的名字一样 */
.codec_name = "es7210.1-0040", /* 这里注意需要配置成ES7210内的一样,否则无法挂载*/
#else
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
#endif
.ops = &mt_machine_audio_ops,
},
....
};
这里配置好,开机就会自动去挂载ES7210 4CH ADC 1 这个codec。
4. 调试过程中的问题点
- 查看ES7210/ES7243E I2C是否正常挂载上,如果没有挂载上,需要查看串口log找出挂载失败的原因并解决。
- 查看声卡是否正常注册上 cat /proc/asound/pcm,如果没有注册上声卡,还是需要通过log查看原因。
tb8788p1_64_wifi:/ # cat /proc/asound/pcm
00-00: MultiMedia1_PLayback mt-soc-codec-tx-dai-0 : : playback 1
.....
00-31: I2S2ADC2_Capture ES7210 4CH ADC 1-31 : : capture 1 /* 此处为挂载成功的声卡 */
tb8788p1_64_wifi:/ #
- 在确保声卡挂载上后,就可以通过tinycap去录音:
tinycap /sdcard/file.wav -D 0 -d 31 -c 2 -r 48000 /* 参数具体含义,自行查询 */
如果录制出来的的文件内容都是全0的文件,就得排查,I2S的信号是否正常。
- MCLK没有波形:通过示波器抓波形,MCLK波形不起来,只有BCLK、LRCK有波形,TDM out(data pin)处于常高状态,顺芯FAE:如果MCLK没有起来的状况下可以通过将BCLK与MCLK短接,使得BCLK复用成MCLK。
尝试了短接BCLK MCLK 但是PCMIN(data pin)还是处于常高状态,当时没有去排查是不是ES7210的寄存器是否正常。最终还是使用MCLK来调试的,具体的MCLK打开,需要跟平台走的I2S通道来配置。
MCLK如果有打不开的情况,可以提CR咨询MTK协助处理,调试的时候,MCLK这块调试了好几天才出来。
kernel-4.14/sound/soc/mediatek/mt6771/mtk-auddrv-clk.c
void EnableI2SCLKDiv(unsigned int I2snum, bool bEnable) /* 通过该函数来打开MCLK */
void EnableALLbySampleRate(unsigned int SampleRate) /* 通过该函数来修改MCLK频率 */
注意事项: MTK平台的I2S一般都是4组,I2S0/I2S2只支持输入,I2S1/I2S3只支持输出。
MCLK需要达到12.288Mhz
在I2S/PCM接口的ADC/DAC系统中,除了BCLK和FS(LRCLK)外,CODEC经常还需要控制器提供MCLK (Master Clock),这是由CODEC内部基于Delta-Sigma (ΔΣ)的架构设计要求使然。MCLK时钟频率一般为256*FS,具体参考特定器件手册。(硬件需要连接MCLK)
- 在确保MCLK LRCK BCLK 都有正常的波形后,TDM out(data pin)就有波形。但是录制出来的文件,导出来的文件还是全0状态。 这种情况就的排查ES7210的寄存器,这一步得更具规格书来调整ES7210寄存器的值。最终还是根据FAE提供的ES7210的寄存器初始化解决录制文件为全0的情况。
通过i2cdump指令来查看 寄存器是否正确
130|tb8788p1_64_wifi:/ # i2cdump -y -f 1 0x40
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 41 20 c3 04 01 00 04 20 30 30 30 02 00 09 ff ff A ???.? 000?.???
10: 00 60 07 00 00 00 00 00 f7 f7 00 bf bf bf bf ff .`?.....??.?????
20: 0a 2a 0a 2a 11 ff ff 0a ff ff ff 2a ff ff ff 2a ?*?*???????*???*
30: ff ff ff 2a ff ff ff 2a ff ff ff ff ff 72 10 02 ???*???*?????r??
40: 42 70 70 1e 1e 1e 1e 08 08 08 08 00 00 ff ff ff Bpp????????..???
50: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ????????????????
60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ????????????????
70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ????????????????
80: 41 20 c3 04 01 00 04 20 30 30 30 02 00 09 ff ff A ???.? 000?.???
90: 00 60 07 00 00 00 00 00 f7 f7 00 bf bf bf bf ff .`?.....??.?????
a0: 0a 2a 0a 2a 11 ff ff 0a ff ff ff 2a ff ff ff 2a ?*?*???????*???*
b0: ff ff ff 2a ff ff ff 2a ff ff ff ff ff 72 10 02 ???*???*?????r??
c0: 42 70 70 1e 1e 1e 1e 08 08 08 08 00 00 ff ff ff Bpp????????..???
d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ????????????????
e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ????????????????
f0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ????????????????
-
因为ES7243E跟ES7210是用的同一组I2S调试就很顺畅,只需要来简单配置寄存器正常初始化就可以正常回采数据了。
-
第一次录制回采都正常,第二次录制回采无效,初步判断,ES7243没有正常复位。通过代码重新复位初始化就正常了。
-
解决使用APK录音依旧无法录音问题
vendor/mediatek/proprietary/hardware/audio/common/V3/aud_drv/AudioALSACaptureDataProviderNormal.cpp
- int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmUl1Capture);
- int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmUl1Capture);
+ int pcmindex = AudioALSADeviceParser::getInstance()->GetPcmIndexByString(keypcmI2S2ADCCapture);
+ int cardindex = AudioALSADeviceParser::getInstance()->GetCardIndexByString(keypcmI2S2ADCCapture);
+ ALOGD("Healer %s: Capture card switch I2S2(+)", __FUNCTION__);
+
小结
调试ES7210、ES7243E Driver花了很长一段时间,主要时间还是花费在I2S这块,第一次调试,调试了一两天才知道接出来的I2S 不支持输入,后面飞线又改板才使用正确的I2S, 在MCLK这里有卡住了,最终还是寻求MTK才解决MCLK不出来的问题,主要还是因为很少调试I2S设备,基本都是LCD/TP/Camer/Sensor的调试,还有很多细节就没有写了,具体还是根据自身的调试情况来处理。