简介:《ADI 音频设计也能如此简单?A2B 技术不可不知》是一份面向汽车音频系统工程师、硬件设计者与音频算法人员的 A2B 技术白皮书,聚焦传统车载音频线束笨重、成本高、布线复杂及多麦克风降噪扩展困难等痛点。压缩包仅含 1 个 PDF 文件,约 4.93MB,适合方案预研、技术选型和团队内部分享。文档从 A2B 起源、系统结构、工作原理与优势展开,讲清单根双线 UTP 电缆如何替代原有模拟与数字线束,并覆盖主从节点发现、I2C 配置、I2S/TDM/PDM 数据传输、点对点/菊花链/树形拓扑、超帧同步与低延迟机制。文中还讨论 32 路上下行音频通道、约 50Mbps 带宽、故障诊断、总线供电及 SigmaStudio 图形化设计,可帮助读者理解 A2B 在车载信息娱乐、主动与路噪降噪中的应用价值。已有 1604 人学习,适合快速建立 A2B 系统框架并评估落地可行性。
1. 一根双绞线干掉一捆线束:A2B 到底解决了什么
汽车音频设计里最贵的东西,往往不是功放,也不是麦克风,而是连接它们的那些线。A2B(Automotive Audio Bus,汽车音频总线)真正反直觉的地方在于,它没有把模拟链路简单换成数字链路,而是把整套拓扑从「星形点对点」重构成「菊花链总线」,顺手再把时钟、控制信息甚至电源一起塞进同一对非屏蔽双绞线。传统方案里,主机到功放是一根屏蔽模拟电缆,功放到低音炮又是一根,座舱里每只麦克风还得单独拉一根到降噪放大器;麦克风数量一涨,线束就成倍膨胀。A2B 把这些全部收进一根 UTP,于是 15m 节点间距、40m 总线总长、恒定两个超帧的延迟、2.7W 的总线供电预算,这些看起来零散的数字,其实是同一条设计哲学在不同侧面的投影。搞懂它们为什么必须是这些值,比记住它们是多少更有用。
2. 总线发现:主机手里没有地址表,它是怎么"点名"的
A2B 系统上电之后的第一件事不是传音频,而是搞清楚链上到底挂了几个节点、每个节点在第几级。这件事没有想象中那么容易:主机只跟主收发器之间有 I2C 和 I2S 连接,它看不见后面那串从节点,从节点之间也没有预先烧录好的固定地址。整条链的拓扑,是在上电之后被"走"出来的。
2.1 上电那一刻,总线上谁也不知道谁在哪
主收发器是整条总线的时钟源头。主机的 I2S 接口给它送来位时钟和帧同步,主收发器内部 PLL 锁住这个时序,才具备向下游传播时钟的能力。这一步是整个系统的地基——时钟没稳住,后面所有的发现、配置、数据传输都是空中楼阁。
从节点的情况更被动。它们没有本地晶振(至少在最简配置下没有),上电时处于"听"的状态,等待上游送来的信号。第一个从节点从主节点收到带时钟信息的数据流,把自己的 PLL 锁到这条恢复出来的时钟上,然后再往下游转发。第二个从节点又从第一个节点转发出来的流里恢复时钟,如此逐级传递。这是一个链式的、有先后顺序的过程,不是并行的广播。
这条链式传播带来一个直接后果:任何一个中间节点没准备好,它下游的所有节点都不可能被发现。这也是为什么现场调试时最典型的症状是"前两级认出来了,后面全丢"——问题往往不在最后那个节点,而在中间某一级的时钟恢复没成功。
2.2 发现流程:一次 I2C 写指令引发的连锁传播
真正的发现动作,是主机对主收发器写一个控制寄存器触发的。写下去之后,主收发器向下游发出一段特殊的发现信号,每个从节点收到后做三件事:锁定上游时钟、记录自己在链上的深度、把信号整形后转发给下一个。等这段信号走到链尾,各个从节点的位置信息已经写进了各自的寄存器。
主机接下来要做的,就是把这些信息读回来。这一步同样是 I2C 操作,但走的是 A2B 总线内部的远程访问通道——主机发出的是针对"第 N 级节点"的读请求,主收发器把请求打包进下行帧,沿途各级节点根据深度字段判断是不是给自己的,是就执行,然后把结果塞进上行帧带回来。整个机制本质上是一个由深度索引寻址的、带转发的寄存器总线。
下面这段示意代码把顺序关系摆出来,寄存器名和位域名按这类收发器的通用惯例抽象,具体地址要对照对应型号的寄存器手册:
/* 阶段一:配置主收发器的音频接口格式,让 PLL 有可锁的参考 */ a2b_i2c_write(MASTER, REG_I2S_CFG, I2S_TDM32 | FS_48K); /* 阶段二:使能 PLL,并轮询等待锁定 */ a2b_i2c_write(MASTER, REG_PLL_CTRL, PLL_EN); while (!(a2b_i2c_read(MASTER, REG_STATUS) & PLL_LOCKED)) { delay_us(10); /* 未锁定就发发现指令,是最常见的翻车点 */ } /* 阶段三:触发总线发现,等待完成中断 */ a2b_i2c_write(MASTER, REG_DISCOVERY_CTRL, DISCOVERY_START); while (!(a2b_i2c_read(MASTER, REG_INT_STATUS) & DISCOVERY_DONE)) { delay_us(10); } /* 阶段四:回读链上节点总数,作为后续远程配置的上界 */ uint8_t nodes = a2b_i2c_read(MASTER, REG_NODE_COUNT);四个阶段的顺序是有硬约束的,不能重排。REG_I2S_CFG决定了帧长度和槽宽,它必须在 PLL 使能之前定下来,因为 PLL 锁的是这个帧结构对应的时序;PLL_LOCKED是硬等待条件,跳过它直接发发现指令,现象是发现流程"跑完了"但节点数为 0 或者只认出第一级;DISCOVERY_DONE之后才能读REG_NODE_COUNT,早读会拿到上一次的残留值。这三处顺序错误在现场出现的频率远高于硬件故障。
2.3 发现之后:远程寄存器访问靠什么跨过物理距离
节点被发现之后,主机就获得了一种能力:像访问本地寄存器一样访问任意一个从节点内部的寄存器。这件事在电气上其实很不容易——主机和远端节点之间隔着十几米电缆和若干个转发节点,I2C 本身的电气规范根本撑不了这个距离。
A2B 的做法是把 I2C 事务"打包"进总线帧里传。主机对主收发器发出一个远程访问请求,主收发器把它编码进下行帧的控制字段,沿途每个节点检查目标深度是否匹配自己,匹配就解出内部的 I2C 事务并在本地总线上执行,执行结果再编码进上行帧回传。对主机侧软件来说,这一整套跟读写本地寄存器几乎没有区别,距离被完全抽象掉了。
这里还有个常被忽略的细节:如果某个从节点本地挂了 I2C 主机(比如一颗 EEPROM,或者一颗本地 MCU),它也能在本地配置自己那颗收发器,不需要主机越权访问。为了避免两边同时写同一颗芯片打架,A2B 定义了两个邮箱来做握手,一来一回各一个方向,语义上接近 CAN 的收发缓冲。为什么是两个而不是一个?单向单邮箱的话,一方写完必须等对方读走才能写第二次,双向通信会互相阻塞;拆成两个方向各一个,请求和响应就能并行在途。这是很典型的低速控制通道设计取舍,代价是软件上要维护两套状态机。
3. 超帧:为什么延迟能固定成两个超帧
音视频系统里"低延迟"和"确定性延迟"是两个完全不同的指标。低延迟是平均值好看,确定性延迟是最坏值等于平均值。A2B 宣传的"小于 50μs"属于后者,而这个确定性来自它的帧结构设计,不是靠提高速率堆出来的。
3.1 超帧的四个字段:SCF、下行载荷、SRF、上行载荷
A2B 总线上的数据不是以包为单位发的,而是以固定周期的"超帧"为单位。一个超帧按顺序由四段组成,这个顺序是硬性的:
| 段 | 方向 | 承载内容 |
|---|---|---|
| SCF(同步控制帧头) | 主 → 从 | I2C 控制信息、GPIO 虚拟端口、中断标志、同步字 |
| 下行数据载荷 | 主 → 从 | 各时隙的音频采样,每槽带奇偶校验位 |
| SRF(同步响应帧头) | 从 → 主 | 上行方向的 I2C 响应、GPIO、中断 |
| 上行数据载荷 | 从 → 主 | 各时隙的音频采样,可选的 ECC 保护 |
把控制信息放在数据前面的意义在于,控制指令和它要影响的数据处在同一个超帧里,不需要跨帧对齐。SCF 打完,下游节点立刻知道这一帧的时隙该怎么解释,数据段紧跟着就到,中间没有等待窗口。SRF 放在上行数据之前,是为了让从节点有机会在同一帧内就把状态回传,而不是等下一帧。
超帧周期由帧率决定。48kHz 时一帧是 1/48000,约 20.83μs;44.1kHz 时约 22.68μs。两个超帧就是 41.7μs 或 45.4μs,都在 50μs 以内——那个"小于 50μs"的指标,本质上就是"两个超帧周期加上一点固定开销"的另一种说法,不是一个独立的性能数字。
3.2 采样在本地,数据在两帧后到达
A2B 的延迟机制可以用一句话概括:第 N 帧采样,第 N+1 帧挂上总线,第 N+2 帧从目标节点输出。三个动作分属三个超帧,中间不重叠。
具体展开:在第 N 个超帧期间,主节点的音频接口把输入数据采进主收发器,从节点也在同一时刻采进自己的本地数据,双方都还只是在本地缓冲里。到第 N+1 个超帧,这些数据才被真正放上总线——主节点的数据成为下行流量,挂在 SCF 之后;从节点的数据成为上行流量,挂在 SRF 之后。再到第 N+2 个超帧,数据从目标节点的引脚上输出,下行数据出在从节点的输出引脚上,上行数据出在主节点的输入引脚上。
这个三段式结构带来的关键性质是:延迟与节点数量无关。一个 10 级菊花链和一对一的点对点连接,延迟完全一样。原因很直白——数据不是逐级存储转发的,它在第 N+1 帧就已经被调制到总线的波形上,沿途每个节点只是把波形整形放大后继续往下传,不做解包、不做缓存、不做重新排队。波形在电缆上的传播时间相对于 20μs 的帧周期可以忽略,所以整条链上所有节点看到的是同一个超帧。
这也是 A2B 和以太网 AVB、CAN 这类总线的根本区别。后两者的延迟随跳数增长,因为它们每跳都要收完整个包、校验、再重新发。A2B 的"转发"更接近物理层的信号再生,代价是它不支持任意拓扑重组,只能沿固定的链走。
3.3 确定性从哪来:没有仲裁,就没有排队
传统共享总线最不可预测的部分是仲裁。多个节点同时想发数据时,总得有个机制决定谁先谁后,无论这个机制是固定优先级还是令牌,都会引入排队延迟,而排队延迟的上界很难严格界定。
A2B 把这个变量直接消掉了。总线的每一帧里,哪些时隙归哪个节点、传哪个通道,在系统初始化时就被静态配置死了。主节点在每一帧里按照配置表依次驱动各个时隙,从节点在属于自己的时隙窗口里驱动总线,其他时间保持高阻。没有任何一帧存在"谁先发"的争议,因为每一帧的发送时刻都是预先分配好的。
代价是灵活性。系统跑起来之后想动态改变某个通道的带宽分配,就得重新配置时隙表,可能还要重新走一遍发现流程。对于座舱音频这种通道数量在设计阶段就基本确定的场景,这个代价完全可以接受;对于突发流量为主的场景,静态分配就浪费带宽了。A2B 的设计目标显然是前者。
4. 时隙映射:32 个槽位怎么装下 I2S、TDM 和 PDM
带宽这件事,A2B 给出的数字是"接近 50Mbps"。这个数字不是测出来的,是算出来的,而且算法很直接:32 个时隙 × 每槽 32 位 × 48kHz 帧率,得到约 49.2 Mbps。三个参数里任意一个变动,带宽就跟着变——这也解释了为什么槽宽和帧率都是可编程的。
4.1 时隙是一张静态表格,不是一个动态队列
把 A2B 的时隙理解成一张表格比理解成队列更准确。每个超帧固定有 32 个时隙位置,编号 0 到 31,每个位置在配置阶段被绑定到某个节点的某个本地接口通道上。绑定关系确定之后,只要系统不断电不重配,这个映射就一直有效。
映射的方向是双向独立的。同一个时隙编号,在下行载荷里可以由主节点写入、由某个从节点读出;在上行载荷里可以由某个从节点写入、由主节点读出。系统还支持从节点到从节点的直接数据交换,以及主节点向所有从节点广播——广播的实现方式就是一个下行时隙被多个从节点同时配置为读取源,写入方仍然只有一个。
下面这段示意代码展示一个从节点的下行时隙映射配置:把总线上编号 0 到 3 的四个下行时隙,分别接到本地 I2S 接口的四个通道上。
/* 为链上第 n 级从节点配置下行时隙映射 */ uint8_t addr = node_addr(n); for (uint8_t ch = 0; ch < 4; ch++) { uint8_t cfg = SLOT_EN /* 使能该时隙 */ | SLOT_WIDTH_32 /* 槽宽 32 bit,对应 TDM32 */ | SLOT_DIR_DOWN /* 使用下行载荷 */ | SLOT_SRC(ch); /* 数据源为总线时隙 ch */ a2b_i2c_write(addr, REG_DN_SLOT_MAP(ch), cfg); } /* 本地 I2S 侧同步打开这四个通道,槽宽必须与上面一致 */ a2b_i2c_write(addr, REG_I2S_TX_EN, 0x0F);SLOT_WIDTH_32和本地 I2S 的位宽配置必须对齐,这是最容易出错的地方:总线上按 32 位槽传,本地接口按 16 位帧解释,采样点会整体错位,听感上表现为音量骤降加高频失真,而不是完全没声音,所以很容易被误判成模拟电路问题。SLOT_SRC(ch)里的ch是总线时隙号,不是本地通道号,两者可以不一致——正是靠这种解耦,同一个物理通道才能在不同节点间被灵活地"搬"到不同时隙位置。
4.2 槽宽 8 到 32 位:可编程宽度省下的是什么
槽宽可编程这件事,看起来只是多了一个配置项,实际省下的是带宽和功耗。32 个时隙全按 32 位跑,带宽是 49.2 Mbps;如果某些通道只是传语音提示或者控制音,8 位或 16 位就够了,把这些槽压窄,剩下的带宽可以留给其他用途,或者干脆降低总线速率来省功耗。
更实际的价值在于兼容性。不同来源的音频数据格式不一样:数字麦克风阵列出来的 PDM 是 1 位流,经过抽取变成 PCM 之后可能是 16 位或 24 位;车载信息娱乐的 TDM 流可能是 32 位槽装 24 位有效数据;某些老平台还在用 16 位 I2S。如果槽宽固定,每接一种新格式就得在外围加转换芯片;槽宽可编程之后,同一颗收发器就能直接对接这些格式,BOM 上少一颗芯片,PCB 上少一片面积。
4.3 PDM 的抽取放在收发器里,省掉的是什么
数字麦克风输出的是 PDM,一位一位地来,速率很高但没法直接当音频用,必须先做低通滤波和降采样变成 PCM。传统做法是在主机侧或者专门的音频 DSP 里做这件事,意味着 PDM 数据要先以原始速率传一段距离,再进处理器。
A2B 把这一步挪进了收发器:麦克风输出的 PDM 直接进本地收发器,收发器内部完成抽取,把结果按配置好的槽宽放进总线时隙。这个改动看起来只是搬了个位置,实际影响不小。PDM 的原始码率是采样率的几十倍,走长电缆的话对信号完整性和 EMI 都是负担;在收发器里就地转成 PCM,线上跑的就是速率低得多的数据,电缆要求和功耗都跟着降。
代价是灵活性下降了。抽取滤波器是硬件实现的,参数固定,想换一种抽取比或者换一种滤波特性,只能换芯片或者改外部电路。对于麦克风这种规格相对固定的外设,这个取舍是划算的;对于需要频繁调滤波特性的实验场景,就未必了。
5. 避坑与排查:A2B 系统上线前最容易翻车的几处
这套总线的机制不算复杂,但把机制串起来的顺序约束很多,任何一处顺序错了,现象都会指向错误的方向。下面几条是按现场出现频率排的。
5.1 发现阶段的三个坑
坑一:发现流程跑完,链上只认出前两级
现象是REG_NODE_COUNT返回 2,后面的节点全部消失,但用示波器看电缆上确实有信号。原因几乎总是中间某一级从节点的时钟恢复没成功,导致它下游的整段链路失去参考。触发条件通常是上电时序——主节点的 I2S 时钟还没稳定,从节点的 PLL 就去锁,锁在一个漂移的频率上,发现信号传到这里就断了。解决办法是把主节点的时钟输出和从节点的上电复位做成有先后关系的,或者在发现流程里加一次重试:失败后延时几十毫秒重新触发,通常第二次就能过。这类偶发失败在实验室里很难复现,因为实验室的电源上升沿比车上干净得多。
坑二:远程读回来的寄存器值恒为 0 或 0xFF
现象是主机能读到节点数,但对某个具体节点的远程寄存器读写全部返回固定值。原因是深度索引算错了。A2B 的远程访问是按"第几级"寻址的,不是按设备 ID,如果代码里把节点在数组里的下标直接当深度用,中间跳过一级或者多算一级,请求就打到不存在的节点上。排查方法是逐个节点做一次"读回自己深度寄存器"的自检,把软件侧的下标和硬件侧的深度对一遍,对不上就是这里的问题。
坑三:邮箱握手卡死,主从两边都在等对方
现象是系统能发现节点、能传音频,但某个需要双向协商的功能一直不生效。原因是两个邮箱的状态机没有考虑"对方还没准备好"的情况,一方写完之后立刻去读响应邮箱,读到的还是上一次的残留数据,于是误判为响应已到。解决方式是在邮箱里加序列号或者长度字段,读到的响应必须和刚发出的请求序号匹配,不匹配就丢弃重读。这类问题在单节点调试时不出现,一上多节点就冒出来,因为多节点情况下响应回来的时序变得不确定了。
5.2 数据与供电阶段的两个坑
坑四:远端节点周期性重启,重启周期和音频内容相关
现象是链尾的节点每隔几秒复位一次,而且重启频率和音量大小有相关性。原因是总线供电预算超了。主设备给下行总线提供的总功率预算是固定的,音频内容越响,远端节点的功放取电越多,累积到某个点就触发欠压复位。这个问题容易被误判成电源芯片选型不当,实际是预算分配问题。解决办法有两种:一是在链中间插入本地供电的节点,本地供电会把下游的预算重置为完整额度,相当于给下游"续了一格";二是把大功率负载放到靠近主节点的位置,让功率在链上分配得更均匀。
坑五:一处短路,整条链全哑
现象是电缆某处对地短路之后,主机侧读不到任何节点。这通常不是 A2B 本身的问题,而是上层软件没有处理诊断事件。收发器能检测到对地短路、对电源短路、线间开路和线间短路这几类故障,检测到之后会把事件上报主机,并且只让故障点下游的节点受影响,故障点上游的部分继续正常工作。但如果主机侧软件没有订阅这个诊断中断,就没法知道故障发生在哪一段,只能从现象反推。正确做法是在初始化阶段就把诊断中断使能,并在中断处理里把故障节点编号记下来,这样现场排查可以直接定位到具体的那一段电缆。
提示:这几条坑的共同点是"现象指向的位置"和"实际出问题的位置"经常不在一处。链尾掉节点,问题在中段;远端重启,问题在供电预算;整链失效,问题在诊断没开。排查时先怀疑顺序和配置,再怀疑硬件。
6. 边界在哪:15m、40m、2.7W 这几个数字背后的取舍
把 A2B 的几组边界参数摆在一起看,会发现它们不是独立的规格,而是互相约束的一组平衡点。
| 参数 | 数值 | 约束的是什么 |
|---|---|---|
| 节点间距 | 15m | 单段电缆的时钟恢复裕量 |
| 总线总长 | 40m | 全链时钟抖动的累积上界 |
| 菊花链从节点数 | 10 | 转发级数带来的固定延迟与信号再生次数 |
| 树形总节点数 | 11 | 从主节点到最远分支从节点的深度上限 |
| 总线供电总预算 | 2.7W | 单段电缆能承载的直流功率 |
这几组数字的内在关系可以这么理解:15m 是单段电缆在给定线径和信号速率下,接收端还能干净恢复出时钟的距离;40m 是全链累加之后,时钟抖动还没超出容限的总长度。两者是局部约束和全局约束的关系,10 个 15m 的节点串起来理论上能到 150m,但 40m 的总长限制会先撞上。所以实际系统里,节点间距往往远小于 15m,把预算匀给更多的节点。
菊花链的 10 个节点上限和树形的 11 个深度上限是两套计数方式。树形允许从某个从节点上再分接出一个独立的 A2B 子系统,那个子系统有自己的主节点,从主系统看过去它只是一个分支。但深度是累加的:主节点算第一级,分接点算几级,分支下的节点就继续往上加,总数不能超过 11。举个具体例子,如果分接点本身在第 4 级,那么这个分支主节点下面最多还能挂 7 个从节点。这个约束不是电气上的,而是协议里深度字段的编码宽度决定的——深度字段只有有限几位,超过就装不下了。
供电预算的 2.7W 更有意思,它是一个可"续接"的额度。主设备给下行总线 2.7W,链上任何一个本地供电的从节点,会把下游的可用额度重新置回 2.7W。这意味着一条长链上如果每隔几级放一个本地供电节点,下游就能反复获得完整预算,而不是全链共享 2.7W。设计时把大功率负载和本地供电节点交错排布,比单纯加大主设备供电能力有效得多。
我自己的习惯是,在画原理图之前先把这三个约束画成一张表:每一级的功率需求、累计深度、累计电缆长度,三列并排放。任何一列超了就调整节点顺序或者插入本地供电,调完再动手。早期有过一次教训,硬件已经打样回来才发现链尾的功放把预算吃穿了,只能改板加本地电源,代价是两周工期。从那以后我每次排 A2B 拓扑,都强制先把这张三列表填完再往下走。
这套机制的文档里有完整的超帧时序图、拓扑示例和诊断寄存器说明,配合评估板一起看,比单看文字快得多。希望帮到你。
本文还有配套的精品资源,点击获取