从源码看 CANopenNode LSS:搞懂主从机运行流程

在这里插入图片描述

@[toc]
在这里插入图片描述

先给结论

LSS(Layer Setting Services)不是用来传过程数据的,也不是普通 SDO 配置。它解决的是设备还没有有效 Node-ID,或者需要统一切换 CAN 位率时,主站如何在 CAN 总线上找到并配置从站的问题。

在 CANopenNode 的 305 目录中,LSS 的运行核心可以压缩成三句话:

  1. 主站只通过 0x7E5 发命令,从站只通过 0x7E4 回响应。 这是 LSS 固定使用的两条 CAN 帧通道。
  2. 从站通过 0x1018 身份对象形成 128 bit LSS Address。 主站可以已知地址精准选择,也可以对未配置节点做 Fastscan。
  3. Node-ID 和 bit rate 先进入 pending 值。 Node-ID 通常要经过保存和通信复位后才真正成为 CANopen 栈运行用的 ID;bit rate 的激活更危险,必须保证全网节点同步切换。

1. LSS 解决的工程问题

在普通 CANopen 网络中,很多通信对象都依赖 Node-ID。例如心跳常见为 0x700 + Node-ID,SDO 服务器默认接收/发送 COB-ID 也与 Node-ID 相关。问题是:

  • 新设备刚出厂可能没有 Node-ID。
  • 多个同型号设备可能不能靠 Node-ID 区分。
  • 有时需要在现场统一修改 bit rate。
  • 如果 Node-ID 无效,就不能指望先用 SDO 写对象字典,因为 SDO 自身也需要 Node-ID。

所以 LSS 被设计成一个低层配置入口:即使设备还不能作为完整 CANopen 节点运行,仍能通过 LSS 从站逻辑接收主站配置。

CiA 的 LSS 说明中明确区分 LSS manager 和 LSS server,并说明 LSS manager 可修改 server 的 CANopen Node-ID、切换整个网络的数据率;其固定使用 0x7E5 作为 manager 到 server 的命令帧、0x7E4 作为 server 到 manager 的响应帧。CANopenNode 官方 305 组文档也把 LSS 描述为用于查询或修改 Node-ID、物理层 bit timing,以及与 0x1018 身份对象一致的 LSS address。

2. CANopen 设备模型中,LSS 站在哪里

理解 LSS 之前,要先分清 CANopen 的三层对象关系:

1
2
3
4
CANopen 设备
├── 通信对象:NMT、Heartbeat、SDO、PDO、SYNC、TIME、EMCY、LSS ...
├── 对象字典:通信参数、设备参数、应用参数的统一索引接口
└── 应用程序:真实控制逻辑、传感器/执行器业务逻辑

《CiA301 V4.2.0》把 CANopen 设备描述为由通信、对象字典和应用程序组成:通信单元提供通信对象和底层网络传输能力;对象字典集合影响应用程序对象、通信对象和状态机行为的数据项;对象字典是通信对象和应用程序对象之间的接口。

LSS 的特殊点是:它与普通对象字典访问不同。普通 SDO 读写对象字典依赖 Node-ID,而 LSS 要处理的正是“Node-ID 不存在或需要改变”的阶段。因此,CANopenNode 让 LSS slave 可以在完整 CANopen 初始化之前先工作。

3. 305 目录源码分工

在这里插入图片描述

CANopenNode GitHub 仓库 305/ 目录中,LSS 相关核心文件主要有 5 个:

文件 角色 阅读重点
305/CO_LSS.h 公共协议定义 命令码、错误码、LSS address、LSS 状态、bit timing 表、Node-ID 合法性宏
305/CO_LSSmaster.h 主站对象和 API 声明 返回值、非阻塞调用模型、Fastscan 参数结构
305/CO_LSSmaster.c 主站状态机实现 发送 0x7E5、等待 0x7E4、超时、选择节点、配置 Node-ID、配置 bit rate、Fastscan
305/CO_LSSslave.h 从站对象和 API 声明 pendingBitRatependingNodeID、回调接口、未配置节点处理
305/CO_LSSslave.c 从站接收和响应实现 CAN RX 回调预处理、主循环处理、配置响应、保存回调、触发通信复位

源码阅读建议先看 CO_LSS.h,再看 CO_LSSslave.c,最后看 CO_LSSmaster.c。原因是从站更接近协议响应本质,主站源码里有更多异步状态机和 Fastscan 细节。

4. CO_LSS.h:公共协议层是整套流程的字典

CO_LSS.h 里最重要的是五类定义。

4.1 命令码决定 data[0] 的含义

LSS 所有请求/响应都是 8 字节 CAN 数据帧,data[0] 是 command specifier。源码中常见命令如下:

命令 方向 用途
CO_LSS_SWITCH_STATE_GLOBAL 0x04 Master -> Slave(s) 全局切换 waiting/configuration
CO_LSS_SWITCH_STATE_SEL_VENDOR 0x40 Master -> Slave(s) 选择指定 LSS 地址:Vendor-ID
CO_LSS_SWITCH_STATE_SEL_PRODUCT 0x41 Master -> Slave(s) 选择指定 LSS 地址:Product Code
CO_LSS_SWITCH_STATE_SEL_REV 0x42 Master -> Slave(s) 选择指定 LSS 地址:Revision Number
CO_LSS_SWITCH_STATE_SEL_SERIAL 0x43 Master -> Slave(s) 选择指定 LSS 地址:Serial Number
CO_LSS_SWITCH_STATE_SEL 0x44 Slave -> Master 指定选择成功响应
CO_LSS_CFG_NODE_ID 0x11 双向 配置 Node-ID,请求和响应复用同一命令码
CO_LSS_CFG_BIT_TIMING 0x13 双向 配置 pending bit rate
CO_LSS_CFG_ACTIVATE_BIT_TIMING 0x15 Master -> Slave(s) 激活 pending bit rate,无确认
CO_LSS_CFG_STORE 0x17 双向 保存 pending Node-ID/bit rate
CO_LSS_IDENT_FASTSCAN 0x51 Master -> Slave(s) Fastscan 请求
CO_LSS_IDENT_SLAVE 0x4F Slave -> Master Fastscan 应答
CO_LSS_INQUIRE_* 0x5A..0x5E 双向 查询 0x1018 各字段或 Node-ID

4.2 LSS Address 直接对应对象 0x1018

源码定义:

1
2
3
4
5
6
7
8
9
10
typedef union {
uint32_t addr[4];

struct {
uint32_t vendorID;
uint32_t productCode;
uint32_t revisionNumber;
uint32_t serialNumber;
} identity;
} CO_LSS_address_t;

这 4 个 uint32_t 就是 LSS 的 128 bit 地址。主站如果已知这四段值,可以直接发选择序列;如果不知道,就要靠 Fastscan 搜索。

这里有一个工程风险:0x1018 必须真正唯一。如果两个未配置设备的 Vendor-ID、Product Code、Revision Number、Serial Number 完全相同,LSS 主站无法可靠地区分它们。CANopenNode 的 LSS 教程也强调 LSS 地址依赖 0x1018 的唯一性。

4.3 LSS 状态只有 waiting 和 configuration

源码定义:

1
2
#define CO_LSS_STATE_WAITING       0x00U
#define CO_LSS_STATE_CONFIGURATION 0x01U

不要把 LSS 状态机和 NMT 状态机混在一起。LSS waiting/configuration 只决定 LSS 从站是否接受配置命令;NMT pre-operational/operational/stopped 决定的是普通 CANopen 通信服务可用性。

4.4 Node-ID 合法性宏体现了 LSS 的“未配置”语义

1
2
#define CO_LSS_NODE_ID_ASSIGNMENT 0xFFU
#define CO_LSS_NODE_ID_VALID(nid) (((nid >= 1U) && (nid <= 0x7FU)) || (nid == CO_LSS_NODE_ID_ASSIGNMENT))

含义:

  • 1..0x7F 是有效 CANopen Node-ID。
  • 0xFF 在 CANopenNode LSS 中表示“需要分配 Node-ID”。
  • 0 不是有效普通节点 ID;广播 Node-ID 0 属于 NMT 等协议语义,不能分配给一个普通从站。

4.5 Bit timing 表把协议值映射成人能读的 kbit/s

CO_LSS_BIT_TIMING_* 里的表索引对应常见 CANopen 位率:1000、800、500、250、125、50、20、10 kbit/s,还有 CO_LSS_BIT_TIMING_AUTO。主站 API CO_LSSmaster_configureBitTiming() 接收的是数值 bit rate,再在函数里转换成 LSS 表索引。

5. 从站上电:为什么 LSS 要插在 CANopen 初始化中间

在这里插入图片描述

CO_LSSslave.h 的注释说明了一个关键启动顺序:

1
2
3
CO_CANinit()
CO_LSSinit() / CO_LSSslave_init()
CO_CANopenInit()

原因是:LSS slave 和 NMT slave 需要共存,但如果节点没有有效 Node-ID,完整 CANopen 对象不能正常初始化。CANopenNode 的处理方式是:

  1. 应用先从 NVM、拨码开关或默认配置读出 pendingBitRatependingNodeID
  2. 调用 CO_LSSslave_init(),把这两个变量的指针交给 LSS 从站对象。
  3. 如果 pendingNodeID1..0x7F,它立刻成为 activeNodeID,后续 NMT、SDO、PDO 等对象正常初始化。
  4. 如果 pendingNodeID == 0xFF,CANopenNode 只初始化并处理 LSS slave;其他 CANopen 模块会跳过或暂停。
  5. 当主站通过 LSS 配置出有效 Node-ID 后,从站在合适时机请求 CO_NMT_RESET_COMMUNICATION,重新走通信对象初始化流程。

这就是 LSS 比普通 SDO 更底层的原因:没有 Node-ID 时,SDO 不能作为配置入口;LSS 可以。

6. 从站对象 CO_LSSslave_t 的字段如何映射运行流程

CO_LSSslave_t 可以按四组理解。

6.1 身份和状态

1
2
3
4
5
CO_LSS_address_t lssAddress;
uint8_t lssState;
CO_LSS_address_t lssSelect;
CO_LSS_address_t lssFastscan;
uint8_t fastscanPos;
  • lssAddress 是本设备真实 128 bit LSS 地址。
  • lssState 是 waiting/configuration。
  • lssSelect 暂存主站通过 0x40/0x41/0x42/0x43 发来的四段地址。
  • lssFastscanfastscanPos 服务 Fastscan 搜索过程。

6.2 pending 值和 active 值

1
2
3
uint16_t* pendingBitRate;
uint8_t* pendingNodeID;
uint8_t activeNodeID;

这里是理解 LSS 的重点:

  • pendingNodeID 是主站配置的新值,可能还没真正成为栈使用的 Node-ID。
  • activeNodeID 是当前 CAN 接口/通信对象正在使用的 Node-ID。
  • 对未配置节点,activeNodeID == 0xFF,配置成功后通过 reset communication 让 pending 值生效。

6.3 接收缓存和发送标志

1
2
3
volatile void* sendResponse;
uint8_t service;
uint8_t CANdata[8];

CAN RX 回调中不做复杂处理,只保存服务类型和数据,并设置 sendResponse。主循环或协议处理任务随后调用 CO_LSSslave_process() 处理。

6.4 应用回调

1
2
3
bool_t (*pFunctLSScheckBitRate)(void* object, uint16_t bitRate);
void (*pFunctLSSactivateBitRate)(void* object, uint16_t delay);
bool_t (*pFunctLSScfgStore)(void* object, uint8_t id, uint16_t bitRate);

这三类回调是 LSS 从站把硬件能力检查、位率激活和参数持久化交给应用层处理的接口:

回调 触发命令 应用要做什么
pFunctLSScheckBitRate 0x13 Configure Bit Timing 判断目标 bit rate 是否被当前 CAN 外设时钟和位时序支持
pFunctLSSactivateBitRate 0x15 Activate Bit Timing 按延时要求停止发送、重配 CAN bit timing、恢复总线
pFunctLSScfgStore 0x17 Store Configuration 把 Node-ID 和 bit rate 写入 Flash/EEPROM/外部 NVM

如果没有注册相关回调,CANopenNode 会用“不响应”或错误响应表达不支持。这一点对调试很重要:主站超时不一定是总线坏了,也可能是从站故意 no-ack 表示不支持该服务。

7. 从站接收路径:ISR 做短处理,主循环做协议动作

在这里插入图片描述

CO_LSSslave_receive() 是 CAN RX 回调,通常在中断或驱动接收上下文中调用。它的策略是:

  1. 只接受 DLC 为 8 的 LSS 帧。
  2. 如果已有待响应帧还没处理,就不覆盖当前请求。
  3. 对简单状态切换、选择地址、Fastscan 匹配做必要判断。
  4. 需要主循环进一步处理时,设置 service、复制 CANdata、置位 sendResponse
  5. 如果启用了 CO_CONFIG_FLAG_CALLBACK_PRE,调用 pFunctSignalPre() 唤醒处理任务。

这种分工适合周期主循环或事件驱动任务。不要在 CAN RX 回调里写 Flash、重配 CAN、等待定时器,这些都应放到 CO_LSSslave_process() 或应用回调中。

8. 已知 LSS Address 时:选择指定从站

在这里插入图片描述

主站已知从站的 128 bit LSS Address 时,调用:

1
CO_LSSmaster_swStateSelect(LSSmaster, timeDifference_us, &lssAddress);

主站源码里的动作是连续发送四帧:

1
2
3
4
0x40 + Vendor-ID
0x41 + Product Code
0x42 + Revision Number
0x43 + Serial Number

从站在 waiting 状态下逐段收集到 lssSelect。当收到最后一段 Serial Number 后,执行:

1
CO_LSS_ADDRESS_EQUAL(LSSslave->lssAddress, LSSslave->lssSelect)

如果完全匹配:

  • 从站进入 CO_LSS_STATE_CONFIGURATION
  • 从站设置 service = CO_LSS_SWITCH_STATE_SEL_SERIAL
  • 后续 CO_LSSslave_process() 发送 0x44 响应。
  • 主站收到 0x44 后认为选择成功。

如果不匹配,从站继续保持 waiting,不响应。对主站来说,这会表现为超时。

9. 配置 Node-ID:为什么配置后还要 reset communication

在这里插入图片描述

前置条件:从站已经处于 LSS configuration。通常是通过指定地址选择,或者 Fastscan 选中了一个未配置节点。

主站调用:

1
CO_LSSmaster_configureNodeId(LSSmaster, timeDifference_us, nodeId);

主站发送:

1
2
data[0] = 0x11  // CO_LSS_CFG_NODE_ID
data[1] = nodeId

从站处理逻辑:

  1. 检查 nodeId 是否满足 CO_LSS_NODE_ID_VALID()
  2. 若有效,则写入 *pendingNodeID
  3. 响应 0x11, errorCode=0
  4. 若无效,则响应 0x11, errorCode=1 或厂商错误。

关键点是:配置命令改变的是 pendingNodeID,不一定立刻改变 activeNodeID。如果设备之前是未配置状态,后续从 configuration 切回 waiting 时,CO_LSSslave_receive() 会检测到:

1
2
activeNodeID == 0xFF
pendingNodeID != 0xFF

于是让 CO_LSSslave_process() 返回 true,表示请求 CO_NMT_RESET_COMMUNICATION。这次通信复位后,新的 pending Node-ID 才会被完整 CANopen 栈采用。

CANopenNode 的 LSS 示例也提醒:修改 Node-ID 后,Node-ID 变化不是立即完成,通常要 reset communication/node 才会生效。

10. 保存配置:0x17 不是普通变量赋值,而是 NVM 边界

主站调用:

1
CO_LSSmaster_configureStore(LSSmaster, timeDifference_us);

从站收到 CO_LSS_CFG_STORE 后,如果注册了 pFunctLSScfgStore(),会调用应用层保存:

1
pFunctLSScfgStore(object, pendingNodeID, pendingBitRate)

这一步不是协议栈自己能替你完成的。不同工程的 NVM 后端可能是:

  • MCU 内部 Flash 某个参数页。
  • 外部 EEPROM。
  • 外部 SPI NOR Flash。
  • 上层配置文件或 Bootloader 参数区。

保存成功才应返回 OK。保存失败要返回错误,否则下次上电后主站以为配置已持久化,实际设备又回到旧 Node-ID 或旧 bit rate,排查会很困难。

11. 配置 bit rate:比配置 Node-ID 更危险

在这里插入图片描述

bit rate 的 LSS 流程分两步:

  1. 0x13 Configure Bit Timing:把新 bit rate 设置成 pending 值。
  2. 0x15 Activate Bit Timing:让节点在指定延时后切换到 pending bit rate。

主站 API:

1
2
CO_LSSmaster_configureBitTiming(LSSmaster, timeDifference_us, bit);
CO_LSSmaster_ActivateBit(LSSmaster, switchDelay_ms);

源码中 configureBitTiming() 接收的 bit1000/800/500/250/125/50/20/10/0 这类值,然后转换为 LSS 表索引。0 对应自动 bit rate 检测。

从站收到 0x13 后:

  • 检查 table index 是否有效。
  • 查表得到实际 kbit/s。
  • pFunctLSScheckBitRate() 让应用确认当前硬件是否支持。
  • 支持则写入 *pendingBitRate 并响应 OK。

真正危险的是 0x15 Activate Bit Timing:CANopenNode 主站源码要求它只能在 CFG_GLOBAL 状态调用,因为切 bit rate 应该全网同时进行。官方文档也明确提示 bit rate 切换是关键步骤,失败会让网络不可用。

实现 pFunctLSSactivateBitRate() 时,关键约束是主站与所有目标从站必须按同一延时策略切换到同一 bit rate;否则后续 CAN 帧将无法互通。

12. Fastscan:不知道地址时如何找出一个未配置节点

在这里插入图片描述

Fastscan 的目标不是“一次列出所有设备”,而是:在一组未配置 LSS 从站中,识别出一个唯一的 LSS Address,并让这个从站进入 configuration 状态。 之后主站给它分配 Node-ID,再扫描下一个。

CANopenNode 主站入口:

1
CO_LSSmaster_IdentifyFastscan(LSSmaster, timeDifference_us, &fastscan);

fastscan 参数里每一段地址有三种策略:

1
2
3
4
5
typedef enum {
CO_LSSmaster_FS_SCAN = 0,
CO_LSSmaster_FS_SKIP = 1,
CO_LSSmaster_FS_MATCH = 2,
} CO_LSSmaster_scantype_t;

含义:

策略 含义 适用场景
FS_SCAN 这 32 bit 完全扫描 完全未知
FS_MATCH 已知该 32 bit,只验证 已知 Vendor-ID 或 Product Code
FS_SKIP 跳过该段 只允许有限跳过,不能随意跳过 Vendor-ID

源码状态机注释很清楚:

1
2
3
4
5
6
7
8
9
check for non-configured nodes
scan vendor ID
verify vendor ID, switch node state
scan product code
verify product code, switch node state
scan revision number
verify revision number, switch node state
scan serial number
verify serial number, switch node to LSS configuration mode

12.1 “有响应”和“没响应”都携带信息

Fastscan 的一个不直观之处是:主站不是等从站返回具体位值,而是用“是否有人应答”来推断当前假设是否成立。

主站从 bit31 扫到 bit0。源码里当超时后如果没有收到 CO_LSS_IDENT_SLAVE,会把当前 bit 置 1:

1
2
/* no response received, assumption is wrong */
LSSmaster->fsIdNumber |= 1UL << LSSmaster->fsBitChecked;

简化理解:

  • 主站先假设某些高位为 0,发请求。
  • 如果仍有从站匹配,就会应答,说明假设可以保留。
  • 如果无人应答,说明假设错了,把当前位改成 1 再继续。

这样逐位收敛出 32 bit,再换下一段地址。

12.2 从站只在未配置状态参与 Fastscan

CO_LSSslave_receive() 中对 Fastscan 有明确限制:

1
2
pendingNodeID == 0xFF
activeNodeID == 0xFF

也就是说,CANopenNode 的 Fastscan 只用于未配置节点。已经有有效 Node-ID 的设备,通常可通过 SDO 读取 0x1018,或通过指定地址选择进入 LSS configuration。

13. 主站 API 为什么都要“循环调用”

在这里插入图片描述

CANopenNode 的 LSS master API 大多是非阻塞函数。典型模式是:

1
2
3
4
5
6
7
8
9
10
11
12
CO_LSSmaster_return_t ret;
uint32_t dt_us;

ret = CO_LSSmaster_configureNodeId(&lssMaster, 0, newNodeId);
while (ret == CO_LSSmaster_WAIT_SLAVE) {
dt_us = get_elapsed_us();
ret = CO_LSSmaster_configureNodeId(&lssMaster, dt_us, newNodeId);
}

if (ret == CO_LSSmaster_OK) {
/* request completed */
}

第一次调用时:

  • 检查状态机是否空闲。
  • 填充 TXbuff->data[]
  • CO_CANsend() 发 0x7E5。
  • 返回 CO_LSSmaster_WAIT_SLAVE

后续调用时:

  • 检查 CANrxNew 是否收到响应。
  • 若收到,解析 CANrxData[]
  • 若未收到,累计 timeoutTimer
  • 超时则返回 CO_LSSmaster_TIMEOUTCO_LSSmaster_SCAN_NOACK

这种设计适合周期主循环或事件驱动任务,不会在协议栈里阻塞等待 CAN 响应。

14. 主站返回值怎么读

CO_LSSmaster_return_t 里有三类返回值。

14.1 正常过程值

返回值 含义
CO_LSSmaster_WAIT_SLAVE 请求已发出,还在等从站响应,下一周期继续调用同一个 API
CO_LSSmaster_OK 请求完成,且从站确认成功
CO_LSSmaster_SCAN_FINISHED Fastscan 某个扫描阶段完成或整个扫描成功

14.2 本地主站错误

返回值 常见原因
CO_LSSmaster_ILLEGAL_ARGUMENT 传入 NULL、非法 Node-ID、非法 bit rate、Fastscan 参数不满足限制
CO_LSSmaster_INVALID_STATE 上一个 LSS 命令还没完成,或当前主站状态不允许发该命令
CO_LSSmaster_TIMEOUT 普通请求超时,无从站响应
CO_LSSmaster_SCAN_NOACK Fastscan 阶段没有符合条件的从站应答
CO_LSSmaster_SCAN_FAILED Fastscan 过程中收到错误响应或状态机无法继续

14.3 从站拒绝,但协议完成

返回值 含义
CO_LSSmaster_OK_ILLEGAL_ARGUMENT 从站收到了请求,但拒绝该参数,比如不支持的 bit timing
CO_LSSmaster_OK_MANUFACTURER 从站返回厂商特定错误

这类返回值容易误判。它不是 CAN 总线失败,而是 LSS 从站有明确反馈:请求到了,但参数不被接受。

15. 主从机典型运行流程一:已知地址,修改 Node-ID

适用场景:设备有唯一 0x1018 身份对象,主站知道这四个字段。目标是把 Node-ID 改成 10 并保存。

1
2
3
4
5
6
7
8
9
10
1. Master: swStateSelect(vendor, product, revision, serial)
2. Slave : 地址完全匹配,进入 LSS configuration,响应 0x44
3. Master: inquire node-id,可选
4. Master: configureNodeId(10)
5. Slave : pendingNodeID = 10,响应 OK
6. Master: configureStore()
7. Slave : 调应用 NVM 保存回调,响应 OK
8. Master: swStateDeselect() 或 global waiting
9. Slave : 若原来未配置,则请求 reset communication
10. CANopen 栈使用 Node-ID 10 重新初始化,开始正常 NMT/Heartbeat/SDO/PDO

对应 CANopenNode LSS demo 的典型命令形态是:先 lss_switch_sel,再 lss_get_nodelss_set_nodelss_store,最后切回 waiting 并 reset communication。

16. 主从机典型运行流程二:未知地址,Fastscan 后分配 Node-ID

适用场景:现场接入了一个或多个未配置节点,主站不知道它们的 0x1018 完整地址。

推荐流程:

1
2
3
4
5
6
7
8
9
1. Master: IdentifyFastscan()
2. Slave : 未配置节点参与 Fastscan,应答匹配请求
3. Master: 得到 fastscan.found 里的 128 bit LSS Address
4. Slave : 被 Fastscan 选中的一个节点进入 LSS configuration
5. Master: configureNodeId(newId)
6. Master: configureStore()
7. Master: swStateDeselect() 或 global waiting
8. Slave : reset communication,使新 Node-ID 生效
9. Master: 如还有未配置节点,重复 Fastscan

注意:Fastscan 的目标通常是一次选出一个节点。多节点批量配置时,不要尝试给多个未配置节点同时写同一个 Node-ID。

17. 主从机典型运行流程三:切换全网 bit rate

适用场景:所有节点当前能以同一 bit rate 通信,且都支持目标 bit rate。

最低风险流程:

1
2
3
4
5
6
7
8
1. 确认所有节点在线,并已知各自 LSS address 或能进入 LSS configuration
2. Master: 全局切换到 LSS configuration
3. Master: 对每个节点 configureBitTiming(targetBitRate)
4. Slave : 各自通过 checkBitRate 回调确认支持
5. Master: 可选 configureStore()
6. Master: ActivateBit(switchDelay_ms)
7. 所有从站和主站按同一延时策略切换 CAN bit timing
8. Master: 在新 bit rate 下重新建立 CANopen 通信

不建议在以下情况下做全网 bit rate 激活:

  • 有节点不确定是否支持目标位率。
  • 主站自身切换 bit rate 的时序不可控。
  • 总线上还有非 CANopen 或不可控设备。
  • 没有现场恢复手段,一旦切错只能拆机单独重配。

18. 与 NMT 状态机的关系

LSS 和 NMT 是两套状态机,但会在启动和 reset communication 处交汇。

《CiA301 V4.2.0》中,NMT 初始化态包含初始化、复位应用、复位通信三个子状态;复位通信完成后执行 boot-up 写服务并进入配置态。配置态允许 SDO 通信但不允许 PDO 通信;运行态允许所有通信服务;停止态会终止大部分通信服务,只保留节点保护/心跳等错误控制服务。

对 LSS 学习来说,重点不是背 NMT 图,而是理解:

  • LSS 可以先于完整 CANopen 通信对象工作。
  • LSS 配置有效 Node-ID 后,通过 reset communication 让普通 CANopen 通信对象按新 Node-ID 初始化。
  • 进入 NMT operational 后才是 PDO 等过程数据通信的正常阶段。

参考资料

  • CANopenNode 官方 Doxygen:CANopen 305 / LSS / LSS Master / LSS Slave。
  • CANopenNode GitHub:https://github.com/CANopenNode/CANopenNode,重点文件为 305/CO_LSS.h305/CO_LSSmaster.c/h305/CO_LSSslave.c/h
  • CiA:CiA 305 Layer Setting Services 公开介绍。
  • 《CiA301 V4.2.0(中文注释版)》:用于 CANopen 设备模型、对象字典、NMT 状态机和通信对象上下文。