虹科分享 | BMW BSD总线协议逆向工程与译码分析(内含在线解码工具分享)

描述

本篇技术分享来自Tech Gear免拆诊断中心的Hophy Ge。

针对宝马 BSD 总线译码难的痛点,Hophy Ge与我们分享了他完整的研究过程,同时还带来了专属 BSD 总线译码的小工具。这个译码工具目前已经上线虹科Pico官网,免费开放在线使用,欢迎大家在阅读完本文以后,前往官网体验。
一、前言

有关BMW 的BSD 总线,只要接触过BMW 的技师都会有所了解。但原厂资料并没有详细说明这个总线的协议规则。

对于BSD 总线来说,故障码的指向性一般都比较强,往往也不太难修,大概率通过更换报码所指向的部件就能解决——这大概也是没有太多人深入研究 BSD 总线的原因吧。

但对我们PicoScope 深度用户来说,看到各种总线都希望能对它进行译码,进而做出更多分析。可惜 Pico 官方并没有针对 BSD 提供译码程序,网上也几乎找不到任何关于 BSD 译码的说明,这反而让人更加好奇。难道 BSD 真的就无法译码解析了吗?这正是本文想接着往下深入探究的地方。

今天我也来分享一下,我对BSD 总线的研究与逆向工程过程。


 

二、收集到的 BSD 资料知识

在动手逆向之前,先把从 BMW 原厂资料、培训手册和网上收集到的 BSD 基础知识梳理一遍,作为后续分析的参照。

1. 定义

BSD = Bit Serial Data interface(位串行数据接口)。命名来源于其传输方式:数据位不是并行收发,而是按位串行地一位一位传输。它是一条单线数据总线,由 BMW 发动机控制单元(汽油 DME / 柴油 DDE)作为总线主机,用于控制和监测若干电源管理与发动机外围部件。

总线协议

关于 BSD 的传输速率,原厂的资料和培训手册上其实出现了两种不同的表达:一种写的是1.2 kBd,另一种写的是9.6 Kbit/s。那它到底是多少?这个问题我们留到后文,结合实测波形再来分析。

总线协议

2. 总线主机与挂接节点

DME/DDE 是 BSD 网络的主控模块(master),正常工作时应当向总线上的其他部件提供 12V 电平。挂接在 BSD 上的部件随车型/配置而变,主要包括:

节点作用
智能蓄电池传感器 IBS测量电池电压/电流/温度,供 DME 计算 SoC/SoH
发电机 Alternator(电压调节)接收 DME 充电指令,调节充电输出
电子水泵 Electric   coolant pump按 DME 指令调速
机油状态/液位传感器 Oil condition sensor上报机油状态/液位
燃烧预热控制单元(柴油机)柴油机预热通信(DDE7 除外)

这些部件虽然连接了DME不同的pin脚,但其实是共用同一条 BSD 总线与 DME 通信。因此一旦总线通信失效,相关部件会同时报通信故障——这也解释了为什么扫描时常常一次跳出一堆相关故障码。

总线协议

3. 常见 BSD 故障码

BSD线上的通讯故障,指向性还是很明确的,不管是物理层还是数据层,都会有相应的故障码。

总线协议

4. 为什么大家总把 BSD 和 LIN 相提并论

很多人会把 BSD 与 LIN 相提并论,因为两者确实有不少神似之处,逐条来看:

同样是单线总线:BSD 只用一根信号线,就把 DME 与发电机、IBS、水泵、机油传感器这 4 个节点串在一起;LIN 也是典型的单线总线,一根线挂多个节点。两者在接线形态上几乎一模一样。

物理层电压相近:BSD 的信号电压在1V~12V(电瓶电压)之间摆动;LIN 同样以电瓶电压为基准做高低电平。用示波器测出来,两条线的电压波形乍看很难分辨。用万用表测量的话,也都在 8V 左右。

总线协议

主从结构一致:BSD 由 DME/DDE 作主模块,轮询各从节点;LIN 也是主模块发起、从模块应答的主从架构。通信的“组织方式“是同一个套路。

应用场景重叠:在很多其他品牌的车型上,IBS、发电机、电子水泵、机油传感器这几个部件大多就是直接用 LIN 线来通信和控制的。


 

三、从 LIN 思路切入,但很快发现它不是 LIN

既然 BSD 看起来像LIN,那么我们最直接的办法,就是先拿 LIN 的分析框架去套它。

最初测量时,我们用标尺拉出最小驱动间隔,正好约为104 µs,对应波特率 9.6 kbit/s,这与 LIN 线能对上。

总线协议

但当你真的用 PicoScope 7 的 LIN 译码器去译码时,结果完全失败——没有任何译码数据。它显然不是 LIN 协议:没有 break 段,没有 0x55 同步,也没有不同 ID 与 DATA 的响应段。

总线协议

网上也有人说可以用 UART 译码。我们试了一下,确实能“译出一些字节”,但并没有任何具体意义。

总线协议

如果按 LIN 的方式去分析,我们手工译码,它只有3 种字节状态。如果以每次下拉驱动作为起始位,分别是01111111、00011111、00000011,对应 HEX 为7F、1F、03。这种形态,根本不像是在传输信息。
 

总线协议

总线协议

总线协议

由此可见,BSD 既不是 CAN 或 LIN 那种 NRZ 编码,也不是曼彻斯特那种一直跳变的编码。

四、真正的突破:固定的周期与规律变化

当我们不再强行用 LIN 的字节模型去套BSD,而是回到最原始的波形本身去观察时,规律就逐渐清晰了。

首先,我们发现 BSD 有非常明显的周期性——每次通信变化都在固定周期内完成。

总线协议

确认这个周期约为827 µs,且只有3 种占空比,分别约为12%、37%、75%。

由此我感觉这是一种PWM 信号,按占空比的状态来编码。可正常数据通信只有两种状态,也就是 0 和1,那这三种占空比该怎么理解呢?

五、SD 同步符与数据包边界

进一步研究发现:低占空比 12% 的状态经常连续 5 个周期重复出现,并有规律地间隔出现。这应该是一种同步符号,我们称之为Sync Delimiter(同步间隔符),简称SD。

总线协议

剩下两种占空比分别代表 0 和1。我们就先假设:37% 为0,75% 为 1。

于是我们找到了一个循环规律:从 5 个 SD 结束、到下一组 5 个 SD 开始,这中间是 0 和 1 的数据变化,应该就是一个数据包。

总线协议


 

六、从电流波形反推主从结构

确定了数据包边界之后,新的问题就出现了:究竟是谁在发?哪些部分来自主模块,哪些部分来自从模块?

单看电压波形时,我们已经能感觉到某些低电位区段带有不同的“电气印记”,但这种差异并不体现在下降沿位置上,而更像是下拉驱动源发生了变化。因此我们怀疑:有不同低电位电压的区间,很可能并不是由同一个模块持续拉低,而是由主、从节点前后接力完成。

总线协议

要验证这一点,最直接的方法就是测电流。

我们先在发电机处测试:打开电门,BSD 线电压有信号,但发电机侧并没有电流发出。难道我们的假设不对吗?当我们启动发动机后,发电机这才开始有信号电流发出——这才验证了我们的猜测。

总线协议

之后我们又分别在水泵、机油液位、IBS 处做 BSD 电流测量,发现一个有意思的规律:发动机不运行时,是 IBS 和水泵在通信;发动机启动之后,发电机、机油液位才会参与通信。

接下来把电流信号与电压信号叠在一起看,就能很清楚地看到:同一段总线低电位,其实是由主模块先拉低、从模块后接力拉低。前半段电流来自主模块,后半段电流来自从模块。前面那些原本说不清楚的“电气印记”,至此终于找到了物理来源。可以确认有电流发出的这一段是从模块发出的区间。

总线协议

把这几次电流测量的结果摆到一起,BSD 的“主从结构“也就浮出水面了。我们可以这样反推:

谁是主模块?无论拆掉哪个传感器,总线上“前半段只由 DME 拉低、没有任何从模块电流“的那部分始终都在,而且每个节点的通信都要等它先动——可见 DME/DDE 才是发起者,也就是主模块。

谁是从模块?各传感器只有在被“点到名“的那一帧、在后半段才有电流流出,平时只是挂在线上沉默等待——这正是从模块“被问才答“的特征。

怎么协同?主模块按顺序逐个点名(轮询),被点到的从模块才在紧随其后的那一段接力拉低、给出应答。这套“主问—从答—再问下一个“的节奏,正是典型的主从轮询机制。

总线协议不过这里有一个和 LIN 不一样的关键细节:在 LIN 总线上,从模块回应阶段完全由从模块独自参与;而在 BSD 上,即便进入了从模块响应阶段,主模块仍会持续发出同步间隔,扮演一个类似时钟信号的角色,配合从模块一起完成通信。

七、主模块段分析:解出 SOF 与节点ID(DID)

有了从模块的信号电流做辅助,主、从两段就能被清楚地区分出来:有从模块电流流出的那一段,是从模块在发;没有从模块电流,就是主模块在发。

主模块区域发出的部分:共有9 个周期。

每次第一个周期都是低占空比37%(对应我们定义的二进制0)。按照对总线的理解,我们认为这第一个周期就是SOF起始帧。

这样后面正好 8 个周期 = 8 个bit,构成一个字节。

按照对主从结构的理解,主模块主要负责发出对应的 ID 信息,从模块接收到对应的 ID 后再做出响应。

顺着这个思路,我们从传感器端测得 BSD 电流,就能反向得到主模块发送的信号。比如在发电机侧测得电流时,主模块发出的信息就代表对应发电机的 ID 号——这和 LIN 总线获取对应 ID 的方法相同。

由此我们推导出了各从模块传感器的ID,并发现这个 ID 分为两部分:前 4 位是该传感器的节点号(node address),后 4 位是参数编码(PID)。也就是说,从模块收到对应的节点号,就知道该哪个节点应答了;再收到对应的PID,就知道该应答哪一个参数。两者拼起来就是DATA ID,简称 DID。

总线协议

用这个方法,我们得到了 4 个从模块的 ID:

Node address对应模块配套 PID 数量
0000IBS9
0110Water Pump(水泵)12
1000Oil condition sensor(机油液位)5
1100Alternator(发电机)7

反过来证明了第五章“37% 为 0、75% 为1“的假设是成立的——否则解出来的节点号根本对不上任何部件。

我们还发现 BSD 存在命令帧的概念:主模块会发出特定的DID,而这个 DID 后面跟着的 DATA 段不是由从模块发出,而是由主模块发出,一般用于下达指令。有意思的是,在这种 DID 的 DATA 的最后一个周期,对应从模块节点会发出一个信号,应该是一个响应信号,我们称之为ACK。

总线协议

Node address对应命令配套 PID 数量
0001CMD to IBS(发给 IBS 的指令)3
0111CMD to Pump(发给水泵的指令)1
1101CMD to Alt(发给发电机的指令)3


 

八、从模块段分析:DATA + 校验 + ACK

接下来我们来看看从模块发出的部分。

从模块区域发出的部分:共有10 个周期。

我们专门研究了这 10 个周期,最终把它拆解为:8 个数据位 + 1 个校验位 + 1 个 ACK 位。

 数据位(8 周期):正好组成一个字节,是从模块真正回传的数值。

校验位(第 9 周期):是一个偶校验位,用于核对前面 8 位数据是否出错。

ACK 位(第 10 周期):由对应从模块发出的确认信号。

        

总线协议BSD 的两种帧型

帧型用途后半段(DATA)由谁发末位
读取帧主模块点名,从模块上报数值从模块发出数据校验位 + 从模块 ACK
命令帧主模块向某节点下达指令主模块发出数据(指令内容)末周期由从模块回一个 ACK 确认

九、完整数据包结构

把之前的结论拼到一起,一个完整的数据包结构就清晰了,一个正常的数据包有24个周期。按主模块发出的是“读取“还是“指令“,可分为两种帧型,两者只在中间的 DATA 段有别:

读取帧:SOF → 主模块 DID → 从模块响应 DATA → 校验 → ACK → 5 个 SD 间隔同步

命令帧:SOF → 主模块 DID → 主模块 CMD 指令 → 校验 → ACK → 5 个 SD 间隔同步


 

可以看到,两种帧的“骨架“完全一致(SOF 起头、校验 + ACK 收尾、再以一组 SD 收口分隔),区别只在于中段那一字节是从模块上报的数据,还是主模块下达的指令。

总线协议

需要补充的是,那“5 个SD“并非一成不变:实际测量中我们发现,在某些过渡状态下,SD 间隔符的个数也会有所浮动,可能出现 4 个或 6 个。

十、反向验证:断开节点观察波形

推断出的协议规则到底对不对?最好的检验办法,就是反过来动手——主动断开某个节点,看波形是否如我们预期的那样变化。

先断一个节点。以水泵为例:我们打开电门,测量BSD电压与水泵侧的电流,在期间断开水泵,断开后,BSD 线的电压波形乍看并无异常,依然在有规律地产生波形,但是水泵的BSD电流就不再发送了。

总线协议

查看断开前的BSD数据,与水泵的响应。

总线协议

断开后,水泵回传的 DATA 应答段,只剩下多个同步间隔符SD,应答数据彻底消失了。主模块照常发问、从模块却无人应答,正是“该节点失联“的典型特征。

总线协议

在第二个测试中,我们把全部 4 个从模块都断开,观察在没有任何从模块可以应答的情况下,总线会如何表现。即便如此,BSD 线上依然有信号电压。
 

总线协议放大查看后可以发现,只有主模块发出的 DID 加上同步间隔符 SD。换句话说,主模块仍在照常轮询点名,但所有本该由从模块回传的 DATA 应答段,全部消失了,取而代之的是一串同步间隔符 SD。

总线协议

至此,从“主模块点名、从模块应答“,到“应答缺失时波形如何坍缩“,都与我们逐步推断出的协议结构一一吻合。BSD 线的协议规则,到这里就基本验证清楚了。

十一、自研 BSD 译码工具

虽然协议已经被基本摸清,但如果每次都靠人工盯着波形、逐段找“哪个 node 没有应答”,实际维修效率仍然很低。因为在物理层上,很多异常并不会表现为特别醒目的畸变,而是要靠对时序和帧结构有很强的理解,才能看出哪里不对。

因此,我们进一步开发了一个 BSD 译码工具。它不只是把波形“翻译成数字”,而是把诊断人员真正关心的信息直接提取出来,例如:

当前轮询到的是哪个节点;

该节点状态是否正常;

是否出现节点无响应;

是否出现校验错误。


 

这样一来,BSD 的分析就从“能看懂波形”,进一步升级到了“能快速定位失联节点和异常帧”。这一步,才算真正把逆向研究变成了可落地的诊断工具。

译码工具:(在线版)

https://www.qichebo.com/bmwbsd/

总线协议

具体使用方法如下: 

第一步:用 PicoScope 7 采集 BSD 电压波形

• 使用 PicoScope 7,以单通道采集 BSD 总线电压信号。测试点可以选择任意 BSD 节点位置,也可以在控制模块(DME/DDE)一侧进行采集。时基设为 1 s/div,量程设为 ±20 V,采满一整页数据(约 10 s)。这样可以确保在单次采集中录入几百个完整的 BSD 数据包。若为偶发性故障,请保留故障出现时所在的缓存页,不要覆盖。

总线协议

第二步:对 BSD 通道启用 DeepMeasure,并确认边沿基准

• 在 BSD 所在通道上启用 DeepMeasure,PicoScope 会开始逐周期测量并显示数据。启用后,先放大波形,确认软件当前按哪个边沿建立周期基准。BSD 译码依赖的是下降沿作为起始点。若 DeepMeasure 当前按上升沿计算周期,则周期编号会错位,译码后的帧结构也会出现偏差。

总线协议

• 如需纠正,请开启「标尺间(Between time rulers)」功能。用一个标尺将下降沿设为第一个基准点,再将另一个标尺向右移动,定义测量窗口范围。两个标尺放置正确后,DeepMeasure 会从下降沿重新计算所有周期。

总线协议

总线协议

第三步:导出 DeepMeasure 数据为 CSV 文件

• 确认周期测量已按下降沿正确对齐后,将 DeepMeasure 的测量结果导出为 CSV 文件,此文件即为 BSD 译码程序的输入文件。

第四步:上传至 BSD 译码工具并下载结果

• 打开 BSD 译码工具,上传刚才导出的 CSV 文件,下载译码结果文件即可。译码程序会自动解析 BSD 数据包,生成结构化的输出文件。

译码表怎么看?

译码结果里,每一行就是一个 BSD 数据包。下面逐列说明每一列的含义:

第 1 列:Packet No.(数据包号码)。每一行对应一个完整的 BSD 通信包,序号从 1 开始递增,用于在译码列表中快速定位某个包。

第 2 列:Start Cycle No.(DeepMeasure 起始周期编号)。这是最关键的导航列——该包对应 PicoScope DeepMeasure 里的第几个周期。当你在译码结果里发现可疑包时,拿这个编号回到 PicoScope,就能精确跳到对应波形位置查看原始信号。

第 3 列:Start Time (s)(包起始时间,单位秒)。该包在整段采集中的时间戳,用于定位某一事件(如无响应首次出现)发生的具体时刻。

第 4 列:SOF(帧起始位)。主模块每帧第一个周期,正常情况下固定为 0(低占空比 37%)。若非 0,说明帧结构存在异常。

• 第 5、6 列:Node Addr (bin) / Node Addr (hex)(节点地址,二进制 / 十六进制)。主模块发出的 4 位节点编号,用于点名某个从模块。对照:0000 = IBS、0110 = 水泵、1000 = 机油传感器、1100 = 发电机。

• 第 7、8 列:PID (bin) / PID (dec)(参数标识符,二进制 / 十进制)。主模块发出的 4 位参数编号,告知从模块本次请求的是哪个参数。不同节点各有多个 PID(IBS 有 9 个,水泵有 12 个等)。

第 9 列:DID(数据标识符)。DID = 节点地址 + PID 的组合,是识别哪个节点回答哪个参数的核心字段。例如 0x65 = 节点 0110(水泵)+ PID 5。

• 第 10、11、12 列:DATA (bin) / DATA (hex) / DATA (dec)(从模块返回数据,三种格式)。从模块本帧返回的 8 位数值,分别以二进制、十六进制、十进制呈现,方便对照分析。命令帧中此字段为主模块发出的指令;无响应帧中此字段为空。

• 第 13、14 列:Parity bit9 / Parity OK(校验位 / 校验结果)。帧中第 9 个周期为偶校验位,译码程序自动验证。OK 表示数据完整;FAIL 表示可能存在信号干扰或帧结构错误。

第 15 列:ACK bit10(第 10 位应答原始值)。帧中第 10 个周期,命令帧中从模块会在此位回传确认信号(ACK)。

第 16 列:Device(设备名称)。译码程序根据节点地址自动映射的可读名称,如 IBS Battery Sensor、Water Pump、Alternator Regulator,无需手动换算节点地址。

第 17 列:Frame Type(帧类型)。标注每帧的通信类型:Normal Response(正常响应帧)、CMD_PUMP / CMD_IBS / CMD_ALT(命令帧)、NO_RESPONSE(无响应)。NO_RESPONSE 是诊断失联节点最直接的标志——主模块发出了 DID,但从模块没有回答。

第 18 列:Alignment(帧对齐状态)。判断该包是否符合标准 BSD 帧格式(24 个周期)。OK 表示结构正常;异常时说明该包可能处于过渡态或受到干扰。

第 19 列:SD Count(同步分隔符数量)。本包前面的 SD 间隔符个数。正常稳态为 5 个;过渡状态下可能出现 4 或 6 个,数量异常可辅助判断信号质量。

第 20 列:DATA Field(数据区描述)。DATA(10bit) 表示正常的 8 位数据 + 校验 + ACK;9xSD (No Response) 表示从模块无响应,数据区被 9 个 SD 填充。这是最直观的故障判断字段。

举例说明

以下结合实际测量数据,说明如何读取译码结果。本例来自本文水泵断开插头测试中的真实采集,对比正常帧与无响应帧:

正常帧示例
正常帧示例(水泵,Packet No. 3):Start Cycle No. 26,时间戳 0.021 s,DID 0x65(节点 0110 + PID 5),DATA 0x76(十进制 118),校验通过,Frame Type 为 Normal Response,SD Count 5 SD。

总线协议

无响应帧示例
无响应帧示例(水泵,Packet No. 410):Start Cycle No. 9952,时间戳 8.297 s,DID 0x6C(节点 0110 + PID 12),DATA 字段为空,Frame Type 为 NO_RESPONSE,DATA Field 显示 9xSD (No Response)。

总线协议

在正常帧中,水泵返回了有效的 DATA 字节 0x76,校验位通过,SD 计数正常为 5 个。在无响应帧中,主模块仍在正常发出同一个 DID,但 DATA 字段为空,译码程序将其标记为 NO_RESPONSE。这就是节点失去响应时在译码结果中直接呈现出来的特征。

两个最关键的定位字段是 Packet No. 和 Start Cycle No.。Packet No. 用于在译码列表中识别是第几个数据包,而 Start Cycle No. 则将该数据包映射回 PicoScope DeepMeasure 里对应的周期编号,可以随时从可疑的译码结果直接跳回原始波形对应位置做进一步核查。以上述无响应帧为例,Packet 410 从 DeepMeasure第 9952 个周期、时间戳 8.297 s 开始,回到 PicoScope 定位到该周期,就能看到水泵插头被拔出的那一刻以及 DATA 响应消失的实际波形。

十二、总结

仔细研究下来你会发现,BSD 这条看似简单的单线总线,其实藏着一套相当完整而精巧的主从问答机制。

同时,第二章留下的那个疑问,到这里也终于有了答案。BSD采用 PWM 占空比编码,每一个 bit 都要占用一整个周期,带宽利用率并不高——一个周期约827 µs,所以从“每 bit 一周期“来算,它的速率就是约1.2 kBd;而 PWM 在一个周期内的最小驱动间隔约为104 µs,换算过来正好是9.6 kbit/s。原厂资料里那两个看似矛盾的数字,其实一个说的是帧速率、一个说的是PWM 的驱动分辨率,到这里就都说得通了。

通过 PicoScope 一步步逆向,我们不仅搞懂了它的编码方式,还把它做成了一个可落地的诊断工具。希望这篇手记,能为同样对BSD 感到好奇的同行提供一点参考。

当然,以上都是我个人在逆向过程中的推论,难免与实际协议有出入或不足之处,也欢迎大家批评指点。

致谢

本次研究能够顺利完成,离不开几位朋友的鼎力相助:感谢虹科(HongKe)的 Eric Chen 提供了大量的技术支持,从逆向分析到最终把译码做成一个网页版小工具,都给了很大的帮助,让整个过程少走了很多弯路;也感谢Jessica Lu 提供实测车辆与场地,让这些波形得以在真实环境下采集和验证。在此一并致以诚挚的谢意。

附录:术语速查

本文逆向过程中反复用到下面几个缩写,统一约定如下,便于随时回查:

缩写全称含义
SDSync   Delimiter同步间隔符,低占空比(约12%),成组出现,用于分隔数据包
SOFStart of   Frame帧起始,主模块发送字节的第一个周期
node   address节点号(4 位),标识总线上某个从模块
PIDParameter   ID参数编码(4 位),标识要读/写的具体参数
DIDData ID= node   address + PID,主模块用它点名“哪个节点、答哪个参数“
ACKAcknowledge应答位,从模块对命令帧的确认

 

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

全部0条评论

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

×
20
完善资料,
赚取积分