7.5.10 CAN 使用指南
基本概述
- 最大可使用 CAN controller 数量:10。
- CAN 最高传输速率:8M。(受限于 transceiver 的波特率限制,目前实验室只测试验证到5M 波特率。)
- 一个 controller 的 Ram 内划分的 Block 个数:
- CAN0-CAN3:4 Block (可变 payload);
- CAN4-CAN9:4 Block (可变 payload)+ 4 Block(固定 payload)。
- 一个 controller 支持的最大 Mailbox 个数为128。
- 一个 controller 支持一路 RxFIFO,FIFO 深度为:
- CAN0-CAN3:8 * 64 bytes;
- CAN4-CAN9:32 * 64 bytes。
- 不支持 TTController,即不支持 TTCAN(一种基于 CAN 总线的高层协议)。
- CAN 支持多包合并传输,并且可以配置合包的数量和超时时间,默认合包数量为1,超时时间为1000us。
- 最大可使用 CAN controller 数量:16。
- CAN 最高传输速率:8M。(受限于 transceiver 的波特率限制,目前实验室只测试验证到5M 波特率。)
- 一个 controller 的 Ram 内划分的 Block 个数:
- CAN0-CAN3:4 Block (可变 payload);
- CAN4-CAN11:4 Block (可变 payload)+ 4 Block(固定 payload)。
- CAN12-CAN15:4 Block (可变 payload);
- 一个 controller 支持的最大 Mailbox 个数为128。
- 一个 controller 支持一路 RxFIFO,FIFO 深度为:
- CAN0-CAN3:8 * 64 bytes;
- CAN4-CAN11:32 * 64 bytes;
- CAN12-CAN15:8 * 64 bytes;
- 考虑到系统层面的唤醒功能,软件驱动不支持 controller 的 PretendedNetwork 功能。
- 不支持 TTController,即不支持 TTCAN(一种基于 CAN 总线的高层协议)。
- CAN 支持多核使用,可将不同的 CAN 控制器绑定在不同的核心上,但不支持多个核心同时使用同一个 CAN 控制器。
软件架构
S100芯片的 CAN 控制器位于 MCU 域,负责 CAN 数据收发。由于感知等应用位于 Acore,因此部分 CAN 数据需要通过 IPC 核间通信机制转发到 Acore。架构保证传输可靠性,转发机制实现数据正确性检测、丢包检测和传输超时检测等机制。此外,还需要规避 MCU 侧高频转发小数据块导致 CPU 占用率过高,造成 MCU 实时性降低等性能问题。
S100 CAN 转发方案的核心流程如下:
- 首先通过 MCU 侧 CAN2IPC 模块将 CAN 通道映射到对应 IPC 通道,然后通过 Acore 侧 CANHAL 模块将 IPC 通道反映射为虚拟 CAN 设备通道。最后用户通过 CANHAL 提供的 API 接口获取虚拟 CAN 设备中的数据。其中,CAN2IPC 模块为 MCU 侧服务,CANHAL 模块为 Acore 侧提供给应用程序的动态库。
- CAN 采用中断的方式接收数据,当接收到数据之后调用 CAN2IPC 模块,CAN2IPC 模块将 MCU 侧 CAN 数据,按照指定传输协议进行打包,然后通过 IPC 核间通信转发到 Acore。Ipc instance 0和 Ipc instance 4分配给 can 使用,默认使能 can5-can9, can5-can9与 IPC 对应关系如下表:
| Ipc_ShmCfgInstances | channel | |
|---|---|---|
| can0 | 0 | - |
| can1 | 0 | - |
| can2 | 0 | - |
| can3 | 0 | - |
| can4 | 0 | - |
| can5 | 0 | 4 |
| can6 | 0 | 6 |
| can7 | 4 | 7 |
| can8 | 4 | 2 |
| can9 | 0 | 3 |
- CANHAL 模块获取来自 MCU 侧的 IPC 数据,按照指定的传输协议解析数据,并支持业务软件通过 API 获取原始 CAN 帧。
S600芯片的 CAN 控制器位于 MCU 域,负责 CAN 数据收发。由于感知等应用位于 Acore,因此部分 CAN 数据需要通过 IPC 核间通信机制转发到 Acore。架构保证传输可靠性,转发机制实现数据正确性检测、丢包检测和传输超时检测等机制。此外,还需要规避 MCU 侧高频转发小数据块导致 CPU 占用率过高,造成 MCU 实时性降低等性能问题。
S600 CAN 转发方案的核心流程如下:
- 首先通过 MCU 侧 CAN2IPC 模块将 CAN 通道映射到对应 IPC 通道,然后通过 Acore 侧 CANHAL 模块将 IPC 通道反映射为虚拟 CAN 设备通道。最后用户通过 CANHAL 提供的 API 接口获取虚拟 CAN 设备中的数据。其中,CAN2IPC 模块为 MCU 侧服务,CANHAL 模块为 Acore 侧提供给应用程序的动态库。
- CAN 采用中断的方式接收数据,当接收到数据之后调用 CAN2IPC 模块,CAN2IPC 模块将 MCU 侧 CAN 数据,按照指定传输协议进行打包,然后通过 IPC 核间通信转发到 Acore。Ipc instance 0和 Ipc instance 4分配给 can 使用,默认使能 can1-can10, can1-can10与 IPC 对应关系如下表:
| Ipc_ShmCfgInstances | channel | |
|---|---|---|
| can0 | 0 | - |
| can1 | 0 | 1 |
| can2 | 0 | 2 |
| can3 | 0 | 3 |
| can4 | 4 | 4 |
| can5 | 0 | 4 |
| can6 | 4 | 0 |
| can7 | 4 | 1 |
| can8 | 4 | 2 |
| can9 | 4 | 3 |
| can10 | 4 | 5 |
- CANHAL 模块获取来自 MCU 侧的 IPC 数据,按照指定的传输协议解析数据,并支持业务软件通过 API 获取原始 CAN 帧。
数据流如上图所示:
- 外设数据通过 CAN 的 PHY 和控制器器件被 MCU 域 CAN 驱动接收后,CAN 驱动将数据上报并缓存在 hobot CANIF 模块。
- 满足合包个数或超时时间,调用 CAN2IPC 模块,按照可靠传输协议进行打包,然后通过 IPC 核间通信机制转发给 Acore。
- CANHAL 模块获取来自 MCU 侧的 IPC 数据,按照指定的传输协议解析数据,Acore 应用程序通过 CANHAL Lib 库提供的 API 获取 CAN 帧。
方案特性说明:
- 支持数据透传正确性校验。
- 支持数据透传丢包检测。
- 支持传输超时检测。MCU 侧 CAN2IPC 转发数据时将数据包打上 MCU 侧的时间戳,Acore CANHAL 接收到数据后会读取 Acore 的时间戳,如果传输超时会报警。注意,需要提前启动时间同步完成 MCU RTC 时间和 Acore 网卡 phc0的时间同步。
- 支持多个 CAN 通道并行传输。MCU 侧多个 CAN 控制器的数据可同时被转发给 Acore,Acore 应用程序通过 CANHAL 从不同通道号读出 CAN 数据。
- 由于 CANHAL 底层通过 ipc 核间通信进行传输,而 ipc 目前不支持多个进程或者线程读写同一个通道,因此 CANHAL 也不支持该特性。
硬件连接说明
-
CAN 物理层的形式主要分为闭环总线及开环总线网络两种,一个适合于高速通讯,一个适合于远距离通讯;S100的 sample 默认采用闭环总线网络架构。
-
CAN 总线的引脚位于 S100的 MCU 扩展板上,引出了5路 CAN 接口,连接器分别对应了5个绿色的螺丝式的3 PIN 连接器。1 PIN(三角标志)为 GND,中间 PIN 为 CAN_L,剩下的为 CAN_H。

- MCU 小板通过2pin 跳帽的形式来选择是否在 CAN_H 和 CAN_L 之间接入120欧姆电阻;当插入跳帽时,接入电阻,适用于闭环网络所需的终端匹配阻抗;移除跳帽则断开终端电阻,适用于开环网络或中继节点场景。

CAN 闭环网络使用两个120欧姆电阻是 CAN 总线的标准配置,以下以 S100举例,如何正确接入电阻:
整体而言,开环网络配置不需要接入120欧姆电阻, 而闭环网络配置总共需要插入两个120欧姆电阻;
- 在使用开环网络时,确保 CAN_H 与 CAN_L 线路正确连接,所用到的 CAN 不要插入跳线帽(在网络中不接入120欧姆电阻);
- 若将 S100的 CAN5和 CAN6连接组成双节点内部闭环网络,确保 CAN_H 与 CAN_L 线路正确连接,还需要在 CAN5和 CAN6接线端子后面的插针插入跳帽(在网络中插入两个120欧姆电阻);
- 若将 S100的 CAN5-CAN9连接组成多节点内部闭环网络,确保 CAN_H 与 CAN_L 线路正确连接,还需要插入两个跳线帽,任意选择两个,严禁插入超过2个跳线帽,以免出现不可预测的问题;
- 若将 S100的 CAN5-CAN9中的任意一个控制器和其它 CAN 设备组成外部闭环网络,确保 CAN_H 与 CAN_L 线路正确连接外,还需要在 RDK 的 CAN 控制器的接线端子后面的插针插入跳帽,并在网络中其它设备端接入一个120Ω电阻;
-
CAN 物理层的形式主要分为闭环总线及开环总线网络两种,一个适合于高速通讯,一个适合于远距离通讯;S600的 sample 默认采用闭环总线网络架构。
-
CAN 总线的引脚 S600共引出10路 can,其中在 MCU 扩展板,引出了5路 CAN 接口,连接器分别对应了5个绿色的螺丝式的3 PIN 连接器。每个 pin 脚的作用可以查看 mcu 子板的背面。在底板上,也引出了5路 CAN 接口,使用 BP 连接器引出。
-
MCU 小板通过拨动拨码开关,来选择是否在 CAN_H 和 CAN_L 之间接入120欧姆电阻;当拨码开关波动到 ON 端,表示接入电阻,适用于闭环网络所需的终端匹配阻抗;当拨码开关波动到数字编码端,表示断开电阻,适用于开环网络或中继节点场景。
-
MCU 扩展版上的 CAN 与拨码开关:

- CAN 与拨码开关的对应关系:
| DPI num | DPI num | ||
|---|---|---|---|
| can1 | 1 | can4 | 4 |
| can2 | 2 | can10 | 5 |
| can3 | 3 |
- S600底板上的 CAN 与拨码开关:

- 底板上 J16为 can 在的位置, 信号名 J16从上到下如下:
| Signal name |
|---|
| GND |
| CAN5_H |
| CAN5_L |
| CAN6_H |
| CAN6_L |
| GND |
| CAN7_H |
| CAN7_L |
| CAN8_H |
| CAN8_L |
| CAN9_H |
| CAN9_L |
- 底板拨码开关在底板背面

- CAN 与拨码开关的对应关系:
| DPI num | DPI num | ||
|---|---|---|---|
| can5 | 1 | can8 | 4 |
| can6 | 2 | can9 | 5 |
| can7 | 3 |
CAN 闭环网络使用两个120欧姆电阻是 CAN 总线的标准配置,以下以 S600举例,如何正确接入电阻:
- 在使用开环网络时,确保 CAN_H 与 CAN_L 线路正确连接,所用到的 CAN(在网 络中不接入120欧姆电阻);
- 若将 S600的 CAN1和 CAN2连接组成双节点内部闭环网络,确保 CAN_H 与 CAN_L 线路正确连接,还需要将 CAN1和 CAN2对应拨码开关波动到 ON 端(在网络中插入两个120欧姆电阻);
- 若将 S600的 CAN1-CAN10中的任意一个控制器和其它 CAN 设备组成外部闭环网络,确保 CAN_H 与 CAN_L 线路正确连接外,还需要将 RDK 的 CAN 控制器对应的莫玛开源波动到 ON 端,并在网络中其它设备端接入一个120Ω电阻;
CAN Filter 配置
标准帧的 filter 最多可配置128个,扩展帧的 filter 最多可配置64个,可选择的 filter 类型如下:
- ONE_ID_FILTER:指定 ID 并可配置 MASK 来忽略 ID 中的哪些 bit 进行过滤,
- RANGE_ID_FILTER:按照 ID 范围进行过滤,
- TWO_ID_FILTER:指定两个 ID 进行过滤。
过滤器的识别
过滤器类型通过检查 u32HwFilterCode 的最高2位来确定:
- 0b00: ONE_ID_FILTER
- 0b01: RANGE_ID_FILTER
- 0b10: TWO_ID_FILTER
/**
* @struct Can_HwFilterType
* @brief Can Hardware Filter
* @NO{S01E03C01}
*/
typedef struct Can_HwFilterType
{
const uint32 u32HwFilterCode; /**< @brief Specifies (together with the filter mask) the identifiers range that passes the hardware filter. */
const uint32 u32HwFilterMask; /**< @brief Describes a mask for hardware-based filtering of CAN identifiers. */
}Can_HwFilterType;
- 配置举例:
- 这是 CAN 7 的过滤器配置,拥有两个过滤器
- 过滤器0的第一个元素的高2位为01,属于范围过滤方式
- 扩展帧和标准帧的过滤相互独立,互不影响
- 标准帧的所有过滤器,如下面的例子过滤器0和过滤1为"或"关系,即如果至少有一个过滤元件满足匹配标准,则 CAN 消息内容将被传输到增强型 RX FIFO 存储器
- 同理,扩展帧的所有过滤器,如下面的例子过滤器2和过滤3为"或"关系,即如果至少有一个过滤元件满足匹配标准,则 CAN 消息内容将被传输到增强型 RX FIFO 存储器
// Config/McalCdd/gen_s100_sip_B_mcu1/Can/src/Can_PBcfg.c
static const Can_HwFilterType Can_aHwFilter_Object7[4U]=
{
{ /* Standard frame configuration */
(uint32)0x400007ffU, // 标准帧配置:接收id为0x0~0x7ff的消息
(uint32)0x00000000U
},
{ /* Standard frame configuration */
(uint32)0x400007ffU, // 标准帧配置:接收id为0x600~0x7ff的消息
(uint32)0x00000600U
},
{ /* Extended frame configuration */
(uint32)0x5fffffffU, // 扩展帧配置:接收id为0x0~0x1fffffff的消息
(uint32)0x00000000U
},
{ /* Extended frame configuration */
(uint32)0x5fffffffU, // 扩展帧配置:接收id为0x600~0x1fffffff的消息
(uint32)0x00000600U
}
};
ONE_ID_FILTER(单 ID 过滤方式)
这是最常见的过滤器类型,使用过滤器代码和掩码进行过滤,伪代码如下:
if ((Received_ID & Filter_Mask) == (Filter_Code & Filter_Mask))
// 接收该消息
else
// 丢弃该消
以标准帧过滤器0配置为例,代码如下:
// Config/McalCdd/gen_s100_sip_B_mcu1/Can/src/Can_PBcfg.c
static const Can_HwFilterType Can_aHwFilter_Object7[4U]=
{
{ /* Standard frame configuration */
(uint32)0x00000400U, // 只接收id = 0x400&0x7ff = 0x400 消息
(uint32)0x000007ffU
},
{ /* Standard frame configuration */
(uint32)0x400007ffU, // 范围过滤方式,支持混用
(uint32)0x00000600U
}
{ /* Extended frame configuration */
(uint32)0x5fffffffU, // 扩展帧配置:接收id为0x0~0x1fffffff的消息
(uint32)0x00000000U
},
{ /* Extended frame configuration */
(uint32)0x5fffffffU, // 扩展帧配置:接收id为0x600~0x1fffffff的消息
(uint32)0x00000600U
}
};
RANGE_ID_FILTER(范围过滤方式)
在这种模式下,使用范围过滤逻辑:
if (id1 <= Received_ID <= id2)
// 接收该消息
else
// 丢弃该消息
这也是 S100 MCU 默认的过滤方式,也是最常用的过滤方式;举例代码如下:
// Config/McalCdd/gen_s100_sip_B_mcu1/Can/src/Can_PBcfg.c
static const Can_HwFilterType Can_aHwFilter_Object7[4U]=
{
{ /* Standard frame configuration */
(uint32)0x00000400U, // 只接收id = 0x400&0x7ff = 0x400 消息
(uint32)0x000007ffU
},
{ /* Standard frame configuration */
(uint32)0x400007ffU, // 范围过滤方式,支持混用
(uint32)0x00000600U
}
{ /* Extended frame configuration */
(uint32)0x5fffffffU, // 扩展帧配置:接收id为0x0~0x1fffffff的消息
(uint32)0x00000000U
},
{ /* Extended frame configuration */
(uint32)0x5fffffffU, // 扩展帧配置:接收id为0x600~0x1fffffff的消息
(uint32)0x00000600U
}
};
TWO_ID_FILTER(双 ID 过滤方式)
这种类型允许指定两个独立的 ID 进行匹配:
- id1: 第一个匹配 ID
- id2: 第二个匹配 ID
if (Received_ID == id1 || Received_ID == id2)
// 接收该消息
else
// 丢弃该消息
以标准帧过滤器0配置为例,代码 如下:
// Config/McalCdd/gen_s100_sip_B_mcu1/Can/src/Can_PBcfg.c
static const Can_HwFilterType Can_aHwFilter_Object7[4U]=
{
{ /* Standard frame configuration */
(uint32)0x80000404U,// 只接收id为404的消息
(uint32)0x00000303U // 只接收id为303的消息
},
{ /* Standard frame configuration */
(uint32)0x400007ffU, // 范围过滤方式,支持混用
(uint32)0x00000600U
}
{ /* Extended frame configuration */
(uint32)0x5fffffffU, // 扩展帧配置:接收id为0x0~0x1fffffff的消息
(uint32)0x00000000U
},
{ /* Extended frame configuration */
(uint32)0x5fffffffU, // 扩展帧配置:接收id为0x600~0x1fffffff的消息
(uint32)0x00000600U
}
};
- RDK S100软硬件支持收发扩展帧和标准帧,而不需要修改配置
- RDK S100软硬件支持对扩展帧和标准帧分别过滤
- 注意 id 的长度配置,超出规定长度将发生截断,扩展帧的 id 长度最高为29位,即最大为0x1FFFFFFF,标准帧的 id 长度最高为11位,即最大为0x7FF
- RDK S600软件目前还不支持扩展帧
波特率配置
CAN 的标称位时(Nominal bit timing)可以分为四个段:
- 同步段(sync_seg):用于节点间的时钟同步,所有节点在此段内检测信号边沿。其长度固定为1个时间单位(TQ)
- 传播段(prop_seg):补偿信号在物理线路上的传播延迟。其长度可调整,用于确保信号在物理介质上的传输时间
- 相位缓冲段1(phase_seg1):用于调整相位误差,确保采样点的准确性,可以扩展重同步
- 相位缓冲段2(phase_seg2):同样用于调整相位误差,但可以缩短 这些段的总和决定了 CAN 的总位时间,通过调整这些段的长度,可以配置不同的波特率。 此外还有以下几个重要概念:
- 同步跳转宽度(SJW,synchronization jump width):CAN 总线同步机制中允许调整相位缓冲段的最大时间量,在 硬同步 和 重同步 过程中补偿节点间的时钟偏差,确保采样点对齐。
- 延迟补偿偏移量(Transceiver Delay Compensation Offset):仅 CAN FD 支持,用于解决数据段高速传输时的物理层时序偏移用于补偿 CAN FD 模式下 收发器 环路延迟 和 信号传播时间 的固定修正值
- 采样点:CAN 控制器在位时间内对总线电平进行采样的精确时刻,用于判定位的逻辑值(显性0或隐性1)
取值范围和公式计算
- 采样点计算:(sync_seg + prop_seg + phase_seg1)/(sync_seg + prop_seg + phase_seg1 + phase_seg2)×100%
- 同步段固定一个 tq
- prop_seg + phase_seg1>phase_seg2
- SJW ≤ min(Phase_Seg1, Phase_Seg2)
- 当配置5M 及以上波特率时,需配置补偿参数,补偿参数计算公式如下:
- TDC offset = (PropSeg + Seg1 + 1) * Fd Prescaler
配置仲裁段1M 数据段5M 实例说明
1. 基础参数确认
- CAN 时钟频率(CAN_CLK): 40 MHz
- 目标波特率(Bit Rate): 5 Mbps
- 预分频值(Prescaler): 1(不分频)
- 单 Bit 时间内的 TQ 总数: TQ = CAN_CLK/(Bit Rate×Prescaler)=40MHz/5Mbps×1=8TQ
- 时间量子:Tq time = 1 / (40M / prescaler) = 1/40M = 25ns