您的位置:首页 > 大数据 > 人工智能

tlvaic3101音频芯片开发笔记调试技巧

2016-08-19 18:05 477 查看
</pre><pre name="code" class="html">        tlvaic3101音频芯片开发笔记调试技巧

4、解读芯片寄存器设置
TLV320AIC3101IRHBT寄存器共分两组:page0和page1,每页127个寄存器, 我们需要关心的主要是page0的127个寄存器
page0中寄存器,按照功能分类如下:
page选择:    register 0
复位:           register 1
配置采样率: register 2 3 4 5 6 7 11
配置数据格式: register 8 9 10
录音ADC音量增益: register 15 16
输入通道设置: regisert 17 ~ 35
输出通道设置: register 37 ~89
输出音量设置:register 43 44
时钟设置:       register 101 102

5、调试音频时,需要注意的地方
调试放音时,
a,放音音量默认设置为最大
b,cpu输出的i2s数据,位宽等要与音频芯片中的设置对等
c,注意通道的选择,硬件上连接的通道与软件寄存器设置的通道要对的上
调试录音时,
a,录音的增益调至最大
b,录音时,mic部分不能有悬空的引脚,否则会出现杂音的。

6、调试技巧
IIC调试
a,可以尝试向音量控制寄存器写入音量,在读出,若都ok的话,则证明iic通讯异常
录音/放音有杂音,放音无声音
a,用逻辑分析仪测试I2S总线,在放音时左声道,右声道的数据应该是一致的,否则需要检查reg10的设置与处理器输出数据设置的关系
b,录音时,测试I2S总线,录音的左右声道数据也应该是一致的,可与手册中的I2S波形进行对比,查找原因。

分析过程:
在\dvrrdk_04.00.00.03.kernel\sound\soc\codecs\tlv320aic3x.c
//重要的数据结构
/* machine i2c codec control layer */
static struct i2c_driver aic3x_i2c_driver = {
.driver = {
.name = "tlv320aic3x-codec",
.owner = THIS_MODULE,
},
.probe	= aic3x_i2c_probe,
.remove = aic3x_i2c_remove,
.id_table = aic3x_i2c_id,
};

static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
.set_bias_level = aic3x_set_bias_level,
.reg_cache_size = ARRAY_SIZE(aic3x_reg),
.reg_word_size = sizeof(u8),
.reg_cache_default = aic3x_reg,
.probe = aic3x_probe,       //声卡的探测和初始化
.remove = aic3x_remove,     //声卡卸载
.suspend = aic3x_suspend,   //声卡休眠
.resume = aic3x_resume,     //声卡从休眠到恢复
};

////////////////////
static struct snd_soc_dai_ops aic3x_dai_ops = {
.hw_params	= aic3x_hw_params,              //硬件参数设定
.digital_mute	= aic3x_mute,               //静音操作
.set_sysclk	= aic3x_set_dai_sysclk,         //系统时钟
.set_fmt	= aic3x_set_dai_fmt,            //格式设置
};

static struct snd_soc_dai_driver aic3x_dai = {
.name = "tlv320aic3x-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = AIC3X_RATES,
.formats = AIC3X_FORMATS,},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = AIC3X_RATES,
.formats = AIC3X_FORMATS,},
.ops = &aic3x_dai_ops,      //声卡操作函数集合全部与硬件操作有关
.symmetric_rates = 1,
};
/////////////////////

module_init(aic3x_modinit)
--->aic3x_modinit(void)
--->i2c_add_driver(&aic3x_i2c_driver)
--->aic3x_i2c_probe
---snd_soc_register_codec(&i2c->dev,&soc_codec_dev_aic3x, &aic3x_dai, 1);
//执行结构体中soc_codec_dev_aic3x中的硬件探测函数aic3x_probe
--->aic3x_probe(struct snd_soc_codec *codec)
//硬件寄存器初始化
--->aic3x_init(codec)
//Output stage volumes控制
--->snd_soc_add_controls(codec, aic3x_snd_controls,ARRAY_SIZE(aic3x_snd_controls));

在\dvrrdk_04.00.00.03.kernel\sound\soc\soc-core.c
//重要的数据结构,可以参考图来理解由上而下
/* ASoC platform driver */
static struct platform_driver soc_driver = {
.driver		= {
.name		= "soc-audio",
.owner		= THIS_MODULE,
.pm		= &soc_pm_ops,
},
.probe		= soc_probe,
.remove		= soc_remove,
};

/* ASoC PCM operations */
static struct snd_pcm_ops soc_pcm_ops = {
.open		= soc_pcm_open,
.close		= soc_codec_close,
.hw_params	= soc_pcm_hw_params,
.hw_free	= soc_pcm_hw_free,
.prepare	= soc_pcm_prepare,
.trigger	= soc_pcm_trigger,
.pointer	= soc_pcm_pointer,
};

static int __init snd_soc_init(void)
//platform注册
--->platform_driver_register(&soc_driver);
/* probes a new socdev */
--->soc_probe(struct platform_device *pdev)
//获取platform设备指针
--->platform_get_drvdata(pdev)
//snd_soc_register_card - Register a card with the ASoC core
--->snd_soc_register_card(card)
--->snd_soc_instantiate_cards();
--->snd_soc_instantiate_card(card);
--->INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
--->soc_probe_dai_link(card, i);
/* probe the cpu_dai */
--->if (!cpu_dai->probed)
/* probe the CODEC */
--->if (!codec->probed)
/* probe the platform */
--->if (!platform->probed)
/* probe the CODEC DAI */
--->if (!codec_dai->probed)
//创建一个pcm实例
--->soc_new_pcm(rtd, num);
--->snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);

问1:在tlvaic310x.c中aic3x_mute静音操作函数如何被上层调用的?
答1:
在
static struct snd_soc_dai_ops aic3x_dai_ops = {
.hw_params	= aic3x_hw_params,
.digital_mute	= aic3x_mute,
.set_sysclk	= aic3x_set_dai_sysclk,
.set_fmt	= aic3x_set_dai_fmt,
};

.digital_mute
被--->dai->driver->ops->digital_mute(dai, mute);
被--->int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute)
被--->static int soc_codec_close(struct snd_pcm_substream *substream)
被--->asla应用层调用

问2:Asoc驱动中,音频数据流如何处理的?
答2:
在sound\soc\davinci\davinci-pcm.c
static int __init snd_davinci_pcm_init(void)
--->platform_driver_register(&davinci_pcm_driver)
--->davinci_soc_platform_probe(struct platform_device *pdev)
--->snd_soc_register_platform(&pdev->dev, &davinci_soc_platform)
//被谁调用?
--->davinci_pcm_new(struct snd_card *card,struct snd_soc_dai *dai, struct snd_pcm *pcm)
//播放
--->if (dai->driver->playback.channels_min) {
ret = davinci_pcm_preallocate_dma_buffer(pcm,
//录音
--->if (dai->driver->capture.channels_min) {
ret = davinci_pcm_preallocate_dma_buffer(pcm,
//分配dma内存
--->dma_alloc_writecombine

问3:谁来调用davinci_pcm_new?
答3:
static struct snd_soc_platform_driver davinci_soc_platform = {
.ops =		&davinci_pcm_ops,
.pcm_new = 	davinci_pcm_new,
.pcm_free = 	davinci_pcm_free,
};

在sound\soc\Soc-core.c
/* create a new pcm */
static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
--->platform->driver->pcm_new(rtd->card->snd_card, codec_dai, pcm);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: