4. SDO协议原理与数据流:请求/应答、上传/下载与块传输

SDO,全称 Service Data Object,是 CANopen 协议栈里最基础、也最常用的数据通道。说白了,它就是用来访问对象字典的——你想读一个参数、写一个配置,都得走 SDO。

我刚开始接触 CANopen 时,总觉得 SDO 和 PDO 差不多。后来踩了坑才明白:SDO 是确认型服务,PDO 是非确认型。一个要握手,一个只管发。今天我们就把它彻底讲透。

4.1 SDO 请求/应答机制

SDO 通信基于 客户端/服务器模型。通常,主站是客户端,从站是服务器。客户端发起请求,服务器返回应答。一来一回,确保数据可靠。

核心特征:

  • 每个 SDO 请求必须对应一个应答
  • 支持分段传输(数据超过 4 字节时)
  • 支持块传输(大量数据时效率更高)
  • 使用两个 CAN 标识符:一个用于发送,一个用于接收

我记得第一次调试 SDO 时,发现从站没反应。查了半天,原来是 CAN-ID 配反了。嗯,这种低级错误,犯过一次就记住了。

4.2 SDO 通信流程:上传与下载

SDO 的通信流程分为两种基本模式:上传(从站→主站)和下载(主站→从站)。

4.2.1 下载(写对象字典)

主站想写一个值到从站的对象字典。流程如下:

  1. 主站发送 下载请求(包含索引、子索引、数据)
  2. 从站接收并写入对象字典
  3. 从站返回 下载应答(成功或错误码)

举个例子,我想把从站的节点 ID 改成 5:

// 主站发送:写 0x2000 子索引 0x01,数据 0x05
// CAN 报文:601 [8] 23 00 20 01 05 00 00 00
// 从站应答:581 [8] 60 00 20 01 00 00 00 00

这里 23 是命令码,表示写 4 字节数据。60 是应答码,表示成功。

我的经验:下载时一定要确认对象字典的访问权限。有些对象是只读的,你写进去它也不认,返回错误码 0x08000000。我曾经在项目里被这个坑过,查了半天文档才发现。

4.2.2 上传(读对象字典)

主站想读从站的某个参数。流程更简单:

  1. 主站发送 上传请求(包含索引、子索引)
  2. 从站读取对象字典
  3. 从站返回 上传应答(包含数据)
// 主站请求:读 0x2000 子索引 0x01
// CAN 报文:601 [8] 40 00 20 01 00 00 00 00
// 从站应答:581 [8] 43 00 20 01 05 00 00 00

40 是读请求命令码。43 表示成功返回 4 字节数据,数据是 05。

4.3 SDO 分段传输

当数据超过 4 字节时,SDO 会自动进入分段模式。比如你要下载一个 100 字节的配置文件。

分段传输的规则:

  • 第一段:包含索引、子索引,数据最多 4 字节
  • 后续段:纯数据,每段最多 7 字节
  • 最后一段:用特定标志位表示结束

注意:分段传输时,主站和从站之间需要交替发送。主站发一段,从站应答一段,才能发下一段。不能连续发。我曾经在压力测试时忽略了这一点,导致从站缓冲区溢出,整个网络都卡死了。

4.4 SDO 块传输模式

块传输是 SDO 的增强模式,专门用于大数据量传输。它把数据分成多个块,每个块包含多个段,然后一次性确认。

我建议你在以下场景使用块传输:

  • 固件升级(几百 KB 到几 MB)
  • 批量参数配置
  • 日志数据上传

块传输的流程:

  1. 初始化:主站发送块下载/上传请求
  2. 数据传输:连续发送多个数据段,不需要逐段应答
  3. 块结束:发送块结束请求,从站返回确认
  4. 循环:重复步骤 2-3,直到所有数据传完

对比一下效率:

传输模式 每段数据量 应答方式 适用场景
普通 SDO ≤4 字节 逐段应答 小数据量(参数读写)
分段 SDO ≤7 字节 逐段应答 中等数据量(配置表)
块传输 SDO ≤7 字节/段,多段一确认 块确认 大数据量(固件升级)

你想想看,固件升级如果用普通 SDO,每 4 字节就要等一次应答,几百 KB 的数据得等到什么时候?块传输把确认次数减少了 90% 以上,效率提升非常明显。

4.5 SDO 数据流全景图

下面这张图展示了 SDO 通信的完整数据流。我把它画成了流程图,方便你理解。

SDO 通信数据流全景图 主站(客户端) 从站(服务器) 对象字典 下载请求 索引+子索引+数据 下载应答 成功/错误码 上传请求 索引+子索引 读取 上传应答 数据+成功/错误码 块传输模式 块传输模式 多段数据 + 块确认 说明: • 普通 SDO:每段 ≤4 字节,逐段应答,适合小数据 • 块传输 SDO:多段合并确认,效率提升 90%+,适合固件升级

4.6 实际调试中的避坑指南

我在多个项目里调试 SDO,总结了几条经验:

我曾经犯过的错:

  • CAN-ID 配置错误:主站和从站的 SDO 通道 ID 必须匹配。我有一回把 0x600+NodeID 写成了 0x700+NodeID,结果从站死活不应答。
  • 对象字典索引越界:读一个不存在的索引,从站返回错误码 0x06020000。调试时一定要先确认对象字典范围。
  • 分段传输超时:分段模式下,段与段之间的间隔不能太长。我建议设置 100ms 超时,超过就重发。
  • 块传输的块大小:块传输的块大小(每块包含的段数)要匹配从站的缓冲区。我一般设为 16 段/块,兼容性最好。

我的调试习惯:

  • 先用普通 SDO 读写单个参数,验证基本通信
  • 再用分段 SDO 测试中等数据量
  • 最后用块传输做固件升级测试
  • 全程用 CAN 分析仪抓报文,对照协议分析

嗯,SDO 这块内容就讲到这里。你只要把请求/应答机制、上传/下载流程、块传输模式这三个核心点吃透,后面调试 CANopenNode 从站工程时就会顺手很多。