Rockchip Combo DAI详解:当单个音频接口不够用时,如何让它们“组队作战”

电子说

1.4w人已加入

描述

 

做音频开发的工程师,多多少少都遇到过这样的尴尬:芯片上的一个 I2S 接口只有 个通道,但项目需要 10 路麦克风同时录音;或者产品既要走模拟输出又要走光纤输出,希望两套输出完全同步......

怎么办?再塞一颗芯片?成本扛不住。砍需求?产品经理不答应。

其实 Rockchip 早就给了一个优雅的解决方案 ——Combo DAI

一、Combo DAI 是什么?一句话讲清楚

如果把每个音频接口(I2SPDMSPDIF 等)比作一根水管,那 Combo DAI 就是一个智能分水器 / 集水器:它把多根水管在头上拧成一根粗管子,对外只露一个接口;用户(也就是你的应用程序)只管对接这一根粗管子,不用关心底下到底有几根细水管在干活。

在内核层面,Combo DAI 会把应用程序的每一次操作 —— 比如 "开始播放""设置采样率""配置通道数"——自动复制并分发给底下所有的子接口,确保它们步调一致。

二、三个典型场景,看看你能不能用上

场景 1:通道不够?凑一凑就有了

你有一块 RK3308,上面两个 I2S 各支持 通道。单独用,最多录 路;但把 I2S0 + I2S1 组合起来,瞬间变成 16 通道同时录音,麦克风阵列、会议拾音、声学成像...... 这些需求都能 cover

场景 2:多路输出要完全同步

高端播放器或专业音频设备经常要求:模拟输出和光纤(SPDIF)输出必须是同一时钟、同一数据源,不能有丝毫延迟差。用 Combo DAI 把 I2S 和 SPDIF 绑在一起,内核层保证同时启停、共享时钟,用户空间只看到一个 PCM 设备,数据自然同步。

场景 3:东拼西凑凑出想要的通道数

RK3576 的 SAI 接口很灵活,SAI0 出 通道、SAI2 出 通道、SAI3 出 通道...... 单独看都不够用,组合起来就是 通道,刚好满足你的特殊硬件布局。

三、内核里是怎么做到的?

Combo DAI 的驱动代码在 rockchip_multi_dais.c 里,核心逻辑其实非常直白——遍历子 DAI 列表,逐个代理

比如应用程序调用hw_params() 设置采样率和通道数:

1.Combo DAI 驱动收到请求

2.遍历自己绑定的所有子 DAII2S_8chI2S_2chSPDIF......

3.根据 DTS 里配置的通道映射,把总通道数拆成几份

4.分别调用每个子 DAI 的 hw_params()

trigger()(启停)、set_fmt()(格式)、set_tdm_slot()(时隙)也是同样的套路。对上层来说,这就像调用了一个普通的声卡;对下层来说,驱动在默默协调所有子接口。

四、DTS 配置:关键就这几行

想让 Combo DAI 工作,设备树里主要做两件事:定义成员 分配通道

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
multi_dais: rockchip-multi-dais {    compatible = "rockchip,multi-dais";    /* 告诉驱动:我由这两个 DAI 组成 */    dais = <&i2s0_8ch &i2s2_2ch>;    /* 播放时,i2s0_8ch 出 8 通道,i2s2_2ch 出 2 通道,一共 10 通道 */    playback,channel-mapping = <8 2>;    /* 录制时同理 */    capture,channel-mapping = <8 2>;    /* MCLK 倍频(可选,看 CODEC 需求) */    mclk-fs-mapping = <256 256>;};

定义好之后,声卡配置里把这个 Combo DAI 当成一个普通的 CPU DAI 来引用即可:

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
sound {    compatible = "simple-audio-card";    simple-audio-card,name = "rockchip,combo";    simple-audio-card,cpu {        sound-dai = <&multi_dais>;  /* 引用 combo dai */    };    simple-audio-card,codec {        sound-dai = <&external_codec>;    };};

就这么简单。channel-mapping 的顺序和dais 列表一一对应,别写错位就行。

五、通道映射:数据在内存里怎么排?

这是很多人配置完后踩坑的地方。总通道数是对齐了,但每一通道的数据到底来自哪个接口?

假设你配了 3 个子 DAI

 DAI

播放通道

录制通道

DAI0 (I2S_8ch)

8

8

DAI1 (I2S_2ch)

2

2

DAI2 (SPDIF)

2

0

DTS 配置:

  •  
  •  
playback,channel-mapping = <8 2 2>;  /* 总计 12 通道播放 */capture,channel-mapping  = <8 2 0>;  /* 总计 10 通道录制 */

 ALSA 的 PCM Buffer 里,数据是严格按 DAI 顺序紧挨着排列的:

  •  
  •  
  •  
  •  
  •  
播放 Buffer 布局:[CH0-CH7 : DAI0] [CH8-CH9 : DAI1] [CH10-CH11 : DAI2]录制 Buffer 布局:[CH0-CH7 : DAI0] [CH8-CH9 : DAI1]               ↑ DAI2 没有录制通道,直接不参与

记住这个顺序,否则后期做通道映射、做音频算法的时候会对不上号。

六、时钟同步:最容易翻车的地方

Combo DAI 把多个物理接口绑在一起,意味着它们必须共享同一个时间基准。如果 I2S0 跑 48kHzI2S2 跑 44.1kHz,那组合出来的声卡必然一团糟。

主从模式要统一

设备树里的bitclock-master frame-master 决定谁产生时钟:

所有子 DAI 都配成 <1>CPU 做 Master,自己产生时钟

所有子 DAI 都配成 <0>CODEC 做 Master,所有子 DAI 跟着 CODEC 的时钟走

混着配:除非你知道自己在做什么,否则别这么干,时钟不同步的后果就是爆音、断续、甚至完全无声

MCLK 可以各自独立

虽然 BCLK/LRCK 必须对齐,但每个子 DAI 的 MCLK 倍频可以不一样(只要 CODEC 能接受):

  •  
mclk-fs-mapping = <256 512 256>;

上面这行表示:DAI0 用 256×fsDAI1 用 512×fsDAI2 用 256×fs。这在某些多 CODEC 场景下很实用。

七、特殊芯片的特殊待遇

RK330816 通道录音的秘密

RK3308 专门有一个 rockchip,rk3308-multi-dais  compatible,用于把 I2S08ch+ I2S18ch)组合成 16 通道录制。

它的特殊之处在于:驱动会自动检查 I2S0 和 I2S1 的主从模式是否互补(一个 CBS_CFS、一个 CBM_CFM),如果是,就通过 GRF 寄存器使能 16 通道控制逻辑。你不用手动写寄存器,但主从模式必须配对正确。

  •  
  •  
  •  
  •  
  •  
  •  
  •  
multi_dais: rockchip-multi-dais {    compatible = "rockchip,rk3308-multi-dais";    dais = <&i2s0_8ch &i2s1_8ch>;    playback,channel-mapping = <0 0>;  /* 纯录制场景 */    capture,channel-mapping = <8 8>;   /* 16 通道录制 */    rockchip,grf = <&grf>;};

RK3576SAI 灵活组合

RK3576 的 SAI 接口也支持 Combo,配置方式和普通 I2S 一样,只是节点名换成 &sai0&sai2 等:

  •  
  •  
dais = <&sai0 &sai2 &sai3>;playback,channel-mapping = <4 1 1>;  /* 凑出 6 通道 */

八、别和 Multi Codecs 搞混了

这两个概念名字有点像,但解决的问题完全不同:

 

Combo DAI

Multi Codecs

组合对象

多个 CPU DAI 接口

一个 CPU DAI + 多个 CODEC

目的

扩展通道数

一个 DAI 同时驱动多个外部芯片

典型例子

8ch + 2ch = 10ch 录音

I2S 同时接耳机 CODEC + 功放

驱动文件

rockchip_multi_dais.c

rockchip_multicodecs.c

简单记:Combo DAI 是 CPU 这边多合一,Multi Codecs 是 CODEC 那边一对多。

九、调试验证:三步确认是否配好

第一步:看声卡是否注册成功

  •  
cat /proc/asound/cards

如果看到rockchip,combo 或者你自定义的声卡名,说明 DTS 被解析了。

第二步:看通道数对不对

  •  
cat /proc/asound/card0/pcm0c/sub0/hw_params

重点看channels 字段,它应该等于你channel-mapping 里所有数字之和。

第三步:看时钟有没有跑起来

  •  
cat /sys/kernel/debug/clk/clk_summary | grep -E 'i2s|sai'

确认所有子 DAI 的时钟频率一致,且处于 enable 状态。

常见问题速查

现象

可能原因

排查方向

声卡没出现

某个子 DAI 没就绪

检查子 DAI 节点的 status = "okay"

通道数少了

channel-mapping 配错

核对每个值的和是否等于预期

声音断断续续

时钟不同步

检查 bitclock-master/frame-master 是否统一

某个 DAI 完全没声

mapping 里配了 0

确认对应位置的值不为 0

十、总结

Combo DAI 本质上是一个 "胶水层驱动 :它不改变任何物理接口的能力,只是把它们捆绑起来,对外伪装成一个更强大的声卡。

用好它,你需要记住三点:

1.通道映射顺序即数据顺序Buffer 里的数据严格按照 dais 列表和channel-mapping 排列

2.时钟必须统一,所有子 DAI 必须同源同频,主从模式别乱配

3. Multi Codecs 区分清楚,一个是 CPU 侧扩通道,一个是 CODEC 侧接多颗芯片

如果你正在做麦克风阵列、多通道采集、或者需要多路同步输出的项目,Combo DAI 大概率能帮你省下一颗芯片的钱。

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分