</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);
tlvaic3101音频芯片开发笔记调试技巧
最新推荐文章于 2022-03-18 22:53:51 发布