专栏首页程序手艺人[ 物联网篇 ] 28 - Linux ES7210 Driver 调试

[ 物联网篇 ] 28 - Linux ES7210 Driver 调试

前言

项目开发过程中,由于Broadcom平台音频数字接口比较少,所以采用模拟麦克风作为输入端,经顺芯ES7210 ADC 转换送至Broadcom PCM 数字音频接口。

提示:本文记录了调试ES7210 Driver 过程中的问题与收获。

一、ES7210 简介

ES7210 是一款高性能四通道音频ADC,支持I2S / PCM / TDM 模式,可支持多个ES7210级连模式。常用于智能音箱领域。

二、ES7210 Driver Porting

1. Broadcom 平台 集成 ES7210

ES7210 Driver 需要顺芯原厂提供,虽然Linux 先的音频框架是一样的,但是芯片内部会有一系列寄存器需要设置。

  • 将ES7210.c和ES7210.h复制到src/kernel/linux/v4.4/sound/soc/codecs/路径下
  • 修改src/kernel/linux/v4.4/sound/soc/codecs/Makefile,
#obj-$(CONFIG_SND_SOC_ES7243)   += es7243.o
obj-$(CONFIG_SND_SOC_ES7210)    += es7210.o

默认驱动ees7210.c中采用过的是I2C_detect方式注册,

如有需要用dts方式注册,请将ES7210_MATCH_DTS_EN赋值为1.

#define ES7210_MATCH_DTS_EN		1	
//ES7210 match method select: 0: i2c_detect, 1:of_device_id

2. Broadcom 平台定制化参数

/*  to set internal mclk and adclrclk ratio   */

#define RATIO_768  0xC3
#define RATIO_256  0xC1
#define RATIO_128  0x01
#define RATIO_64   0x41 /* mclk from bclk pin */

#define ES7210_MCLK_LRCK_RATIO   RATIO_128

Broadcom 平台 LRCK 默认是16KHz , 通过逻辑仪看到LRCK的频率为2.04MHz。故ES7210_MCLK_LRCK_RATIO 需要设置为RATIO_128

3. 排查 ES7210 无法正常工作

通过逻辑分析仪观察到波形,PCM In 一直没有数据,相当于ES7210 没有正常工作。

根据 调试笔记 — 使用ADC芯片ES7243遇到的问题 的分析,快速验证了I2C , 可以正常工作。

参考数字音频接口

找到ES7210 Datasheet ,TDM参考设计。MCLK 需要连接

而Broadcom 中的ES7210 中的MCLK 是悬空的, 这个时候找顺芯FAE 咨询了下,MCLK 不能悬空,一般是LRCLK的256倍。如果没有MCLK,需要将BCLK短接到MCLK。

通过飞线将MCLK与BCLK连接在一起, 通过逻辑分析仪抓取波形,发现PCM Data 一直都是某个bit持续为高电平,其它为低电平。感觉ES7210 还是没有工作起来。跟顺芯FAE沟通了解. 驱动中不需要更改。

想起来之前,驱动代码中一旦使能 clk_prepare_enable(es7210->mclk),kernel 会立即发生崩溃。顺芯FAE 解释说 本身提供的是的RK 平台的驱动代码,针对博通平台,需要去掉该操作,只要主控能送出BCLK 就可以,其他不会有影响,代码只是使能MCLK

ssoc-audio soc-audio: ASoC: machine MapleTree should use snd_soc_register_card()
########### debug 1es7210_probe!
Unable to handle kernel paging request at virtual address fffffffe
pgd = c0014000
[fffffffe] *pgd=1fffd821, *pte=00000000, *ppte=00000000
Internal error: Oops: 17 [#1] PREEMPT SMP ARM
Modules linked in:
CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.1.52 #8
Hardware name: Generic DT based system
task: df422c00 ti: df43a000 task.ti: df43a000
PC is at clk_prepare+0x14/0x2c
LR is at clk_prepare_lock+0x10/0xf8
pc : [<c02721b8>]    lr : [<c02710f8>]    psr: 60000113
sp : df43bdb0  ip : 00000000  fp : 00000000
r10: df4c4e20  r9 : df4c4c58  r8 : fffffffe
r7 : df4c4c00  r6 : df4c3d90  r5 : c07b6ca0  r4 : fffffffe
r3 : df422c00  r2 : 00000001  r1 : 00000000  r0 : 00000001
Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
Control: 10c5387d  Table: 0001404a  DAC: 00000015
Process swapper/0 (pid: 1, stack limit = 0xdf43a210)
Stack: (0xdf43bdb0 to 0xdf43c000)
bda0:                                     df4c4c10 c02bb894 df4c4c10 df4c4c28
.....
[<c02721b8>] (clk_prepare) from [<c02bb894>] (es7210_probe+0x58/0x110)
[<c02bb894>] (es7210_probe) from [<c028d3bc>] (soc_probe_component+0x1f0/0x320)
[<c028d3bc>] (soc_probe_component) from [<c028ff7c>] (snd_soc_register_card+0x8b0/0xfc0)
[<c028ff7c>] (snd_soc_register_card) from [<c02186fc>] (platform_drv_probe+0x2c/0x60)
[<c02186fc>] (platform_drv_probe) from [<c02172a0>] (really_probe+0x190/0x290)
[<c02172a0>] (really_probe) from [<c0215a0c>] (bus_for_each_drv+0x60/0x94)
[<c0215a0c>] (bus_for_each_drv) from [<c0217108>] (device_attach+0x84/0x8c)
[<c0217108>] (device_attach) from [<c02167f8>] (bus_probe_device+0x84/0xa8)
[<c02167f8>] (bus_probe_device) from [<c0214b30>] (device_add+0x358/0x544)
[<c0214b30>] (device_add) from [<c02184c8>] (platform_device_add+0x110/0x220)
[<c02184c8>] (platform_device_add) from [<c05c3a6c>] (bcm63xx_audio_init+0x38/0x60)
[<c05c3a6c>] (bcm63xx_audio_init) from [<c001973c>] (do_one_initcall+0x8c/0x1d4)
[<c001973c>] (do_one_initcall) from [<c05a9dcc>] (kernel_init_freeable+0x148/0x1e8)
[<c05a9dcc>] (kernel_init_freeable) from [<c0446484>] (kernel_init+0x8/0xe8)
[<c0446484>] (kernel_init) from [<c001f4e8>] (ret_from_fork+0x14/0x2c)
Code: 012fff1e e92d4010 e1a04000 ebfffbcb (e5940000) 
---[ end trace 0daed059f560601b ]---
Kernel panic - not syncing: Fatal exception
CPU3: stopping
CPU: 3 PID: 0 Comm: swapper/3 Tainted: G      D         4.1.52 #8
Hardware name: Generic DT based system
[<c0026be0>] (unwind_backtrace) from [<c00229c8>] (show_stack+0x10/0x14)
[<c00229c8>] (show_stack) from [<c044a57c>] (dump_stack+0x8c/0xa0)
[<c044a57c>] (dump_stack) from [<c00253a4>] (handle_IPI+0x148/0x158)
[<c00253a4>] (handle_IPI) from [<c001941c>] (gic_handle_irq+0x5c/0x60)
[<c001941c>] (gic_handle_irq) from [<c00234c0>] (__irq_svc+0x40/0x74)
Exception stack(0xdf45ff88 to 0xdf45ffd0)
ff80:                   00000001 00000000 00000000 c002bd00 df45e000 c05dc4b0
ffa0: c0450704 00000000 df45ffd8 c05d7200 00000000 00000001 01000000 df45ffd0
ffc0: c00205f0 c00205f4 60000113 ffffffff
[<c00234c0>] (__irq_svc) from [<c00205f4>] (arch_cpu_idle+0x38/0x3c)
[<c00205f4>] (arch_cpu_idle) from [<c005ce60>] (cpu_startup_entry+0x15c/0x264)
[<c005ce60>] (cpu_startup_entry) from [<000194ac>] (0x194ac)                                         
CPU0: stopping                                                                                       
CPU: 0 PID: 0 Comm: swapper/0 Tainted: G      D         4.1.52 #8                                    
Hardware name: Generic DT based system                                                               
[<c0026be0>] (unwind_backtrace) from [<c00229c8>] (show_stack+0x10/0x14)
[<c00229c8>] (show_stack) from [<c044a57c>] (dump_stack+0x8c/0xa0)
[<c044a57c>] (dump_stack) from [<c00253a4>] (handle_IPI+0x148/0x158)
[<c00253a4>] (handle_IPI) from [<c001941c>] (gic_handle_irq+0x5c/0x60)
[<c001941c>] (gic_handle_irq) from [<c00234c0>] (__irq_svc+0x40/0x74)
Exception stack(0xc05dbf28 to 0xc05dbf70)
bf20:                   c05dbf70 00000018 312acb4c 00000000 dfbc9910 00000001
bf40: 3124e81c 00000000 312acb4c 00000000 c0602f54 c05d9200 14000000 c05dbf70
bf60: fffffff8 c0267dac 00000113 ffffffff
[<c00234c0>] (__irq_svc) from [<c0267dac>] (cpuidle_enter_state+0xd8/0x20c)
[<c0267dac>] (cpuidle_enter_state) from [<c005cf08>] (cpu_startup_entry+0x204/0x264)
[<c005cf08>] (cpu_startup_entry) from [<c05a9c78>] (start_kernel+0x3a8/0x3b4)
[<c05a9c78>] (start_kernel) from [<0001807c>] (0x1807c)
CPU2: stopping
CPU: 2 PID: 371 Comm: ubi_bgt0d Tainted: G      D         4.1.52 #8
Hardware name: Generic DT based system
[<c0026be0>] (unwind_backtrace) from [<c00229c8>] (show_stack+0x10/0x14)
[<c00229c8>] (show_stack) from [<c044a57c>] (dump_stack+0x8c/0xa0)
[<c044a57c>] (dump_stack) from [<c00253a4>] (handle_IPI+0x148/0x158)
[<c00253a4>] (handle_IPI) from [<c001941c>] (gic_handle_irq+0x5c/0x60)
[<c001941c>] (gic_handle_irq) from [<c00234c0>] (__irq_svc+0x40/0x74)
Exception stack(0xd965fe20 to 0xd965fe68)
fe20: c07aeafc 80000193 00000001 20000113 dfbc3f08 00000005 00000035 c07906b8
fe40: 00000000 00000006 00000000 00000100 00000002 d965fe68 c0061710 c0062310
fe60: 60000113 ffffffff
[<c00234c0>] (__irq_svc) from [<c0062310>] (console_unlock+0x33c/0x4f8)
[<c0062310>] (console_unlock) from [<c0062814>] (vprintk_emit+0x348/0x5a0)
[<c0062814>] (vprintk_emit) from [<c0062b8c>] (vprintk_default+0x20/0x28)
[<c0062b8c>] (vprintk_default) from [<c0448810>] (printk+0x6c/0x7c)
[<c0448810>] (printk) from [<c02495c4>] (ubi_thread+0x40/0x174)
[<c02495c4>] (ubi_thread) from [<c0046da8>] (kthread+0xdc/0xf4)
[<c0046da8>] (kthread) from [<c001f4e8>] (ret_from_fork+0x14/0x2c)
Rebooting in 5 seconds..

然后查看原理图,发现有MIC_EN引脚,连接的是ES7210中断引脚,咨询TP_Link硬件之后,发现这个脚目前是悬空状态,因此排除中断引脚的问题。

发现该排查的问题已经排查完成,先和FAE沟通,看还有哪些忽略的点,FAE说打开调试信息,查看Reg的值,沟通之后,了解方法之后,查看代码。通过应用层操作可以看出全部寄存器的数值。

1721 static struct attribute_group es7210_debug_attr_group = {
1722         .name   = "es7210_debug",
1723         .attrs  = es7210_debug_attrs,
1724 };
static DEVICE_ATTR(es7210, 0644, es7210_show, es7210_store);

06 static ssize_t es7210_show(struct device *dev, struct device_attribute *attr, char *buf)
1707 {
1708         printk("echo flag|reg|val > es7210\n");
1709         printk("eg read star address=0x06,count 0x10:echo 0610 >es7210\n");
1710         printk("eg write star address=0x90,value=0x3c,count=4:echo 4903c >es7210\n");
1711         return 0;
1712 }

/由于echo flag打印的寄存器不全,需要用 echo 0x47可以打印出全部寄存器

echo 0x4f > /sys/devices/platform/ubus@ff800000/ff802100.i2c/i2c-0/0-0040/es7210_debug/es7210

Read: start REG:0x00,count:0x4f
REG[0x00]: 0x41;  REG[0x01]: 0x20;  REG[0x02]: 0xc3;  REG[0x03]: 0x04;  
REG[0x04]: 0x01;  REG[0x05]: 0x00;  REG[0x06]: 0x00;  REG[0x07]: 0x20;  
REG[0x08]: 0x20;  REG[0x09]: 0x30;  REG[0x0a]: 0x30;  REG[0x0b]: 0x02;  
REG[0x0c]: 0x00;  REG[0x0d]: 0x09;  REG[0x0e]: 0xff;  REG[0x0f]: 0xff;  
REG[0x10]: 0x00;  REG[0x11]: 0x63;  REG[0x12]: 0x07;  REG[0x13]: 0x00;  
REG[0x14]: 0x03;  REG[0x15]: 0x03;  REG[0x16]: 0x00;  REG[0x17]: 0x00;  
REG[0x18]: 0xf7;  REG[0x19]: 0xf7;  REG[0x1a]: 0x00;  REG[0x1b]: 0xbf;  
REG[0x1c]: 0xbf;  REG[0x1d]: 0xbf;  REG[0x1e]: 0xbf;  REG[0x1f]: 0xff;  
REG[0x20]: 0x0a;  REG[0x21]: 0x2a;  REG[0x22]: 0x0a;  REG[0x23]: 0x2a;  
REG[0x24]: 0x11;  REG[0x25]: 0xff;  REG[0x26]: 0xff;  REG[0x27]: 0x0a;  
REG[0x28]: 0xff;  REG[0x29]: 0xff;  REG[0x2a]: 0xff;  REG[0x2b]: 0x2a;  
REG[0x2c]: 0xff;  REG[0x2d]: 0xff;  REG[0x2e]: 0xff;  REG[0x2f]: 0x2a;  
REG[0x30]: 0xff;  REG[0x31]: 0xff;  REG[0x32]: 0xff;  REG[0x33]: 0x2a;  
REG[0x34]: 0xff;  REG[0x35]: 0xff;  REG[0x36]: 0xff;  REG[0x37]: 0x2a;  
REG[0x38]: 0xff;  REG[0x39]: 0xff;  REG[0x3a]: 0xff;  REG[0x3b]: 0xff;  
REG[0x3c]: 0xff;  REG[0x3d]: 0x72;  REG[0x3e]: 0x10;  REG[0x3f]: 0x01;  
REG[0x40]: 0x42;  REG[0x41]: 0x70;  REG[0x42]: 0x70;  REG[0x43]: 0x1c;  
REG[0x44]: 0x1c;  REG[0x45]: 0x1c;  REG[0x46]: 0x1c;  REG[0x47]: 0x08;  
REG[0x48]: 0x08;  REG[0x49]: 0x08;  REG[0x4a]: 0x08;  REG[0x4b]: 0x00;  
REG[0x4c]: 0x00;  REG[0x4d]: 0xff;  REG[0x4e]: 0xff; 

根据寄存器的值判断ES7210的工作状态,这个时候想到确实应该这样操作,FAE确实从其中发现了问题:

通过寄存器0x14和0x15发现处于Mute状态。

同时0x02寄存器值不对,没匹配到没有mclk的值。这才真正的问题所在,这个时候思考为什么会导致这样的情况发生?

FAE推测到 说明没执行到es7210_pcm_startup()或者录音没有跑这个7210的声卡。这个时候最终明白问题所在了。

目前ES7210只走初始化流程,并不走es7210_pcm_startup() 这个时候明白了问题所在。

当初最初设计的方案 :

● ES7210 只需要走初始化流程,不需要完全对接Alsa的应用层,因为ES7210 SOC 是被动的,最终是Broadcom SOC PCM 接口去ES7210 获取数据的。 ● Broadcom SOC 不需要通过Alsa 应用层,可以先通过bhDsphal.c应用程序调试看PCM是否又音频数据。

而ES7210中是对接的Alsa Lib接口,当通过arecord 录音的时候,Alsa Driver 是需要调用 es7210_pcm_startup(),而该函数的功能是启动延迟队列,执行 umute 操作。

通过这样的分析,解释了为什么ES7210 没数据的问题,主要是驱动初始化执行了mute操作,当arecoed的时候执行umut操作。而BCM6755 PCM 并没有走Alsa流程,导致一直处于mute状态。

 831 static struct snd_soc_dai_ops es7210_ops = {
 832         .startup = es7210_pcm_startup,
 833         .hw_params = es7210_pcm_hw_params,
 834         .set_fmt = es7210_set_dai_fmt,
 835         .set_sysclk = es7210_set_dai_sysclk,
 836         .digital_mute = es7210_mute,
 837 };
 
 
static int es7210_pcm_startup(struct snd_pcm_substream *substream,struct snd_soc_dai *dai)
{
    struct snd_soc_codec *codec = dai->codec;
    struct es7210_priv *es7210 =                        snd_soc_codec_get_drvdata(codec);
    if (es7210_init_reg == 0) {
        schedule_delayed_work(&es7210->pcm_pop_work, msecs_to_jiffies(100));
    }
        return 0;
}
// 延迟队列执行函数
 747 static void pcm_pop_work_events(struct work_struct *work)
 748 {
 749         printk("enter into %s\n", __func__);
 750         es7210_unmute();
 751         es7210_init_reg = 1;
 752 }

4. ES7210 Gain Channels Adjust

// 由于echo flag打印的寄存器不全,需要用 echo 0x47可以打印出全部寄存器
echo 0x4f > /sys/devices/platform/ubus@ff800000/ff802100.i2c/i2c-0/
0-0040/es7210_debug/es7210
//寄存器列表如下图 
//需要调整ES7210 通道的GAIN数值

#define ES7210_MIC1_GAIN_REG43		0x43
#define ES7210_MIC2_GAIN_REG44		0x44
#define ES7210_MIC3_GAIN_REG45		0x45
#define ES7210_MIC4_GAIN_REG46		0x46

#define ES7210_MIC_GAIN 0x1c  // need check hw design and channel
#define ES7210_AEC_GAIN 0x13  // need check hw design and channel

es7210_write(ES7210_MIC1_GAIN_REG43, ES7210_MIC_GAIN, i2c_clt1[i]);
es7210_write(ES7210_MIC2_GAIN_REG44, ES7210_MIC_GAIN, i2c_clt1[i]);
es7210_write(ES7210_MIC3_GAIN_REG45, ES7210_MIC_GAIN, i2c_clt1[i]);
es7210_write(ES7210_MIC4_GAIN_REG46, ES7210_MIC_GAIN, i2c_clt1[i]);

// 根据寄存器可以分析出,增益值现在为34.5dB, 根据算法的要求,麦克风的录音数据应该是不需要添加任何增益的,需要改为0
i2cset -f -y 0 0x40 0x43 0x10
i2cset -f -y 0 0x40 0x44 0x10
i2cset -f -y 0 0x40 0x45 0x10
i2cset -f -y 0 0x40 0x46 0x10

总结

调试ES7210 Driver 前后花费了一周的时间,过程中遇到的很多问题,所以每次交付的时间都Delay。主要这个Broadcom平台对接的是TDM接口以及走的ALSA 接口有区别,很多东西不是很熟悉,解决问题过程中需要去弄明白才能快速的解决问题。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [ 后端篇 ] 10 - AWS API 返回 Endpoint request time out

    设备访问服务端的时候,返回Endpoint request time out,在stackoverflow看到有类似的问题 Amazon API gateway...

    程序手艺人
  • CSDN博客转载详解

    程序手艺人
  • [ 系统篇 ] 嵌入式系统中磁盘空间占用率100%

    系统OTA升级之后,发现/etc/config 分区占用率100%,着实郁闷,/etc/config 分配20M空间,实际占用的配置文件<1M, 怎么会磁盘占用...

    程序手艺人
  • Go 语言错误及异常处理篇(二):defer 语句

    Go 语言中的类没有构造函数和析构函数的概念,处理错误和异常时也没有提供 try...catch...finally 之类的语法,那当我们想要在某个资源使用完毕...

    学院君
  • Golang之轻松化解defer的温柔陷阱

    defer是Go语言提供的一种用于注册延迟调用的机制:让函数或语句可以在当前函数执行完毕后(包括通过return正常结束或者panic导致的异常结束)执行。深受...

    梦醒人间
  • Golang之轻松化解defer的温柔陷阱

    defer是Go语言提供的一种用于注册延迟调用的机制:让函数或语句可以在当前函数执行完毕后(包括通过return正常结束或者panic导致的异常结束)执行。深受...

    老钱
  • (十八)golang--defer关键字

    在函数中,程序员经常需要创建资源(比如,数据库连接,文件句柄,锁等),为了在函数执行完毕后,及时释放资源,go设计者提供defer(延时机制)

    绝命生
  • Golang之轻松化解defer的温柔陷阱

    defer是Go语言提供的一种用于注册延迟调用的机制:让函数或语句可以在当前函数执行完毕后(包括通过return正常结束或者panic导致的异常结束)执行。

    李海彬
  • [日常] Go语言圣经-Deferred函数

    1.只需要在调用普通函数或方法前加上关键字defer,就完成了defer所需要的语法。当defer语句被执行时,跟在defer后面的函数会被延迟执行。直到包含该...

    陶士涵
  • golang defer关键字的使用

    在golang当中,defer代码块会在函数调用链表中增加一个函数调用。这个函数调用不是普通的函数调用,而是会在函数正常返回,也就是return之后添加一个函数...

    开发架构二三事

扫码关注云+社区

领取腾讯云代金券