class CAN -- 控制器局域网通信总线

CAN 同时支持经典 CAN(bxCAN,用于 OpenMV Cam M4 和 M7)和 CAN FD(FDCAN,用于 OpenMV Cam H7、H7 Plus 和 Pure Thermal)控制器。在物理层面上,CAN 总线由两条线组成,即 RX 和 TX。要将 OpenMV Cam 连接到 CAN 总线,必须使用 CAN 收发器,将 MCU 的 CAN 逻辑信号转换为总线上正确的电压电平。

回环(无收发器)模式下的经典 CAN:

from pyb import CAN

can = CAN(1, CAN.LOOPBACK)

# Accept messages with id 123, 124, 125 or 126.
can.setfilter(0, CAN.LIST16, 0, (123, 124, 125, 126))

can.send("message!", 123)   # send a message with id 123
can.recv(0)                 # receive a message on FIFO 0

启用了全部可选特性的 CAN FD(FD 帧、比特率切换、扩展帧 ID;500 kbit/s 仲裁阶段、1 Mbit/s 数据阶段):

from pyb import CAN

can = CAN(
    1,
    CAN.NORMAL,
    baudrate=500_000,
    brs_baudrate=1_000_000,
    sample_point=80,
)

# Accept any id in the range 0xFFF0 .. 0xFFFF.
can.setfilter(0, CAN.RANGE, 0, (0xFFF0, 0xFFFF))

can.send(b"a" * 64, 0xFFFF, fdf=True, brs=True, extframe=True)
can.recv(0)

除非另有说明,以下 CAN 模块函数及其参数对经典 CAN 和 FD CAN 控制器均可用。

构造函数

class pyb.CAN(bus: int | str, *args, **kwargs)

在给定的 bus(一个整数外设索引,例如 1 对应 CAN12 对应 CAN2)上构造一个 CAN 对象。若不提供其他参数,则只创建对象但不进行初始化(它会保留之前的总线设置,如果有的话);若给出额外参数,则会对总线进行初始化。可用参数请参阅 CAN.init()

在每一款暴露 pyb.CAN 的 OpenMV Cam(M4 / M7 / H7 / H7 Plus / Pure Thermal)上,CAN(2) 都连接到相同的排针引脚:

信号

排针引脚

说明

RX

P3

TX

P2

CAN 外设仅提供逻辑电平信号;要驱动真实的 CAN 总线需要外接 CAN 收发器。

pyb.CAN 在 OpenMV Cam N6 上不可用。

方法

init(mode: int, prescaler: int = 100, *, sjw: int = 1, bs1: int = 6, bs2: int = 8, auto_restart: bool = False, baudrate: int = 0, sample_point: int = 75, num_filter_banks: int = 14, brs_sjw: int = 1, brs_bs1: int = 8, brs_bs2: int = 3, brs_baudrate: int = 0, brs_sample_point: int = 75) None

使用给定参数初始化 CAN 总线:

  • mode 取以下之一:NORMAL、LOOPBACK、SILENT、SILENT_LOOPBACK

  • prescaler 是 CAN 输入时钟用于生成标称位时间量子时的分频值。对于经典 CAN,预分频值可取 1 到 1024(含)之间;对于 CAN FD,可取 1 到 512(含)之间。

  • sjw 是标称位的重同步跳转宽度,以时间量子为单位;对于经典 CAN,可取 1 到 4(含)之间;对于 CAN FD,可取 1 到 128(含)之间。

  • bs1 定义采样点的位置,以标称位的时间量子为单位;对于经典 CAN,可取 1 到 16(含)之间;对于 CAN FD,可取 2 到 256(含)之间。

  • bs2 定义发送点的位置,以标称位的时间量子为单位;对于经典 CAN,可取 1 到 8(含)之间;对于 CAN FD,可取 2 到 128(含)之间。

  • auto_restart 设置控制器在进入总线关闭(bus-off)状态后是否会自动尝试重启通信;如果禁用此功能,则可以使用 restart() 来退出总线关闭状态

  • baudrate 如果提供的波特率不为 0,此函数将尝试自动计算同时满足 baudrate(误差在 0.1% 以内)和期望 sample_point(精确到最接近的 1%)的 CAN 标称位时间(覆盖 prescalerbs1bs2)。如需更精确地控制 CAN 时序,请直接设置 prescalerbs1bs2 参数。

  • sample_point 指定位采样相对于整个标称位时间的位置,以标称位时间的整数百分比表示。默认 sample_point 为 75%。除非设置了 baudrate,否则此参数将被忽略。

  • num_filter_banks 对于经典 CAN,这是分配给 CAN(1) 的滤波器组数量,28 个中剩余的部分则分配给 CAN(2)。

其余参数仅在支持 CAN FD 的开发板上存在,用于配置可选的 CAN FD 比特率切换(BRS)特性:

  • brs_prescaler 是 CAN FD 输入时钟用于生成数据位时间量子时的分频值。预分频值可取 1 到 32(含)之间。

  • brs_sjw 是数据位的重同步跳转宽度,以时间量子为单位;可取 1 到 16(含)之间

  • brs_bs1 定义采样点的位置,以数据位的时间量子为单位;可取 1 到 32(含)之间

  • brs_bs2 定义发送点的位置,以数据位的时间量子为单位;可取 1 到 16(含)之间

  • brs_baudrate 如果提供的波特率不为 0,此函数将尝试自动计算同时满足 brs_baudrate(误差在 0.1% 以内)和期望 brs_sample_point(精确到最接近的 1%)的 CAN 数据位时间(覆盖 brs_prescalerbrs_bs1brs_bs2)。如需更精确地控制 BRS 时序,请直接设置 brs_prescalerbrs_bs1brs_bs2 参数。

  • brs_sample_point 指定位采样相对于整个标称位时间的位置,以标称位时间的整数百分比表示。默认 brs_sample_point 为 75%。除非设置了 brs_baudrate,否则此参数将被忽略。

时间量子 tq 是 CAN 总线的基本时间单位。tq 等于 CAN 预分频值除以 PCLK1(内部外设总线 1 的频率);要确定 PCLK1,请参阅 pyb.freq()

单个位由同步段(始终为 1 tq)组成。其后是位段 1,然后是位段 2。采样点位于位段 1 结束之后。发送点位于位段 2 结束之后。波特率为 1/bittime,其中 bittime 等于 1 + BS1 + BS2 再乘以时间量子 tq。

例如,在 OpenMV Cam H7 上(PCLK1 = 100 MHz),采样点为 75% 的 250 kbps CAN 可配置为 prescaler=25, sjw=1, bs1=11, bs2=4tq = 25 / 100 MHz = 250 nsbittime = (1 + 11 + 4) × 250 ns = 4 µs、采样点 = (1 + 11) / 16 = 75%,波特率为 1 / 4 µs = 250 kHz

更多细节请参阅 OpenMV Cam 所用 MCU 的 STM32 参考手册中的 bxCAN / FDCAN 章节。

deinit() None

关闭 CAN 总线。

restart() None

强制软件重启 CAN 控制器,但不重置其配置。

如果控制器进入总线关闭状态,它将不再参与总线活动。如果控制器未配置为自动重启(参阅 init()),则可使用此方法触发重启,控制器随后将遵循 CAN 协议退出总线关闭状态并进入错误活动状态。

state() int

返回控制器的状态。返回值可以是以下之一:

  • CAN.STOPPED —— 控制器完全关闭并已复位;

  • CAN.ERROR_ACTIVE —— 控制器已开启并处于错误活动(Error Active)状态(TEC 和 REC 均小于 96);

  • CAN.ERROR_WARNING —— 控制器已开启并处于错误警告(Error Warning)状态(TEC 或 REC 至少有一个达到或超过 96);

  • CAN.ERROR_PASSIVE —— 控制器已开启并处于错误被动(Error Passive)状态(TEC 或 REC 至少有一个达到或超过 128);

  • CAN.BUS_OFF —— 控制器已开启但不参与总线活动(TEC 溢出超过 255)。

info(list: list | None = None) list

获取有关控制器错误状态以及 TX 和 RX 缓冲区的信息。如果提供了 list,则它应当是一个至少包含 8 个条目的列表对象,这些条目将被填入相应信息。否则将创建一个新列表并填入信息。两种情况下,该方法的返回值都是已填充的列表。

列表中的值为:

  • TEC 值

  • REC 值

  • 控制器进入错误警告(Error Warning)状态的次数(超过 65535 后回绕到 0)

  • 控制器进入错误被动(Error Passive)状态的次数(超过 65535 后回绕到 0)

  • 控制器进入总线关闭(Bus Off)状态的次数(超过 65535 后回绕到 0)

  • 待发送 TX 消息的数量

  • fifo 0 上待接收 RX 消息的数量

  • fifo 1 上待接收 RX 消息的数量

setfilter(bank: int, mode: int, fifo: int, params: Tuple[int, ...], *, rtr: Tuple[bool, ...] | None = None, extframe: bool = False) None

配置一个滤波器组:

  • bank 是要配置的经典 CAN 控制器滤波器组,或 CAN FD 滤波器索引。

  • mode 是滤波器应当工作的模式,参见下面的表格。

  • fifo 指定如果消息被此滤波器接受,应存储到哪个 fifo(0 或 1)。

  • params 是一个定义滤波器的值数组。该数组的内容取决于 mode 参数。

经典 CAN 控制器(OpenMV Cam M4 / M7)的 params 数组内容:

mode

params 的内容

CAN.LIST16

四个将被接受的 16 位 ID。

CAN.LIST32

两个将被接受的 32 位 ID。

CAN.MASK16

两个 16 位的 id/掩码对,例如 (1, 3, 4, 4)。第一对(1, 3)接受所有位 0 = 1 且位 1 = 0 的 ID;第二对(4, 4)接受所有位 2 = 1 的 ID。

CAN.MASK32

一个 32 位的 id/掩码对(其余与 CAN.MASK16 相同)。

CAN FD 控制器(OpenMV Cam H7 / H7 Plus / Pure Thermal)的 params 数组内容:

mode

params 的内容

CAN.RANGE

两个 ID,构成接受 ID 的一个范围。

CAN.DUAL

两个将被接受的 ID(例如 (1, 2))。

CAN.MASK

一个 (id, mask) 对(例如 (0x111, 0x7FF))。

  • rtr 对于经典 CAN 控制器,这是一个布尔值数组,用于指定滤波器是否应接受远程传输请求消息。如果未给出此参数,则所有条目默认为 False。其长度取决于 mode

    mode

    len(rtr)

    说明

    CAN.LIST16

    4

    CAN.LIST32

    2

    CAN.MASK16

    2

    CAN.MASK32

    1

    对于 CAN FD,此参数将被忽略。

  • extframe 如果为 True,则帧将使用扩展标识符(29 位),否则使用标准标识符(11 位)。

clearfilter(bank: int, extframe: bool = False) None

清除并禁用一个滤波器组:

  • bank 是要清除的经典 CAN 控制器滤波器组,或 CAN FD 滤波器索引。

  • extframe 对于 CAN FD 控制器,如果为 True,则清除扩展滤波器(以 extframe=True 配置的),否则清除标准标识符(以 extframe=False 配置的)。

any(fifo: int) bool

如果 FIFO 上有任何消息在等待,则返回 True,否则返回 False

recv(fifo: int, list: list | None = None, *, timeout: int = 5000) list

在总线上接收数据:

  • fifo 是一个整数,表示要在其上接收数据的 FIFO

  • list 是一个可选的列表对象,用作返回值

  • timeout 是等待接收的超时时间,以毫秒为单位。

返回值:一个包含五个值的列表。

  • 消息的 id。

  • 一个布尔值,指示消息 ID 是标准的还是扩展的。

  • 一个布尔值,指示消息是否为 RTR 消息。

  • FMI(滤波器匹配索引)值。

  • 一个包含数据的数组。

如果 listNone,则会分配一个新列表,以及一个用于存放数据的新 bytes 对象(作为列表中的第五个元素)。

如果 list 不为 None,则它应当是一个至少包含五个元素的列表对象。第五个元素应当是一个 memoryview 对象,由 bytearray 或类型为 'B' 或 'b' 的 array 创建而来,且该数组必须至少有容纳 8 个字节的空间。然后列表对象将被填入上述前四个返回值,memoryview 对象将原地调整为数据的大小并填入相应数据。可以在后续对此方法的调用中重复使用同一个列表和 memoryview 对象,从而提供一种无需使用堆的接收数据方式。例如:

buf = bytearray(8)
lst = [0, 0, 0, 0, memoryview(buf)]
# No heap memory is allocated in the following call
can.recv(0, lst)
send(data: int | bytes | bytearray, id: int, *, timeout: int = 0, rtr: bool = False, extframe: bool = False, fdf: bool = False, brs: bool = False) None

在总线上发送一条消息:

  • data 是要发送的数据(一个要发送的整数,或一个缓冲区对象)。

  • id 是要发送的消息的 id。

  • timeout 是等待发送的超时时间,以毫秒为单位。

  • rtr 是一个布尔值,指定该消息是否应作为远程传输请求发送。如果 rtr 为 True,则只使用 data 的长度来填充帧的 DLC 字段;data 中的实际字节不会被使用。

  • extframe 如果为 True,则帧将使用扩展标识符(29 位),否则使用标准标识符(11 位)。

  • fdf 对于 CAN FD 控制器,如果设置为 True,则帧将采用 FD 帧格式,支持最多 64 字节的数据载荷。

  • brs 对于 CAN FD 控制器,如果设置为 True,则启用比特率切换模式,此时数据阶段将以不同的比特率传输。数据位时序的配置参数请参阅 CAN.init()

如果 timeout 为 0,则消息将被放入三个硬件缓冲区之一中,方法立即返回。如果三个缓冲区都在使用中,则抛出异常。如果 timeout 不为 0,则方法会等待直到消息被发送。如果消息无法在指定时间内发送,则抛出异常。

返回值:None

rxcallback(fifo: int, fun: Callable[[CAN, int], None] | None) None

注册一个函数,当消息被接受进入一个空 FIFO 时调用:

  • fifo 是接收用的 FIFO。

  • fun 是当 FIFO 变为非空时要调用的函数。

回调函数接受两个参数:第一个是 CAN 对象本身;第二个是一个整数,指示回调的原因:

原因

含义

0

一条消息已被接受进入空 FIFO。

1

FIFO 已满。

2

由于 FIFO 已满,一条消息已丢失。

rxcallback 的使用示例:

def cb0(bus, reason):
  print('cb0')
  if reason == 0:
      print('pending')
  if reason == 1:
      print('full')
  if reason == 2:
      print('overflow')

can = CAN(1, CAN.LOOPBACK)
can.rxcallback(0, cb0)

常量

总线模式常量(init()mode 参数):

NORMAL: int

控制器正常参与总线活动 —— 发送自己的帧并对有效的接收帧进行应答。

LOOPBACK: int

内部回环模式:控制器与引脚断开连接,将发送的帧直接路由回接收路径。适用于无收发器的自检。

SILENT: int

只听模式:控制器接收帧,但从不驱动总线(不应答,不发送)。适用于总线嗅探。

SILENT_LOOPBACK: int

组合 SILENTLOOPBACK:没有引脚活动也没有应答,同时将 TX 内部回环到 RX。

控制器状态常量(由 state() 返回):

STOPPED: int

控制器完全关闭并已复位。

ERROR_ACTIVE: int

控制器已开启并处于错误活动(Error Active)状态(TEC 和 REC 均小于 96)。

ERROR_WARNING: int

控制器已开启并处于错误警告(Error Warning)状态(TEC 或 REC 至少有一个达到或超过 96)。

ERROR_PASSIVE: int

控制器已开启并处于错误被动(Error Passive)状态(TEC 或 REC 至少有一个达到或超过 128)。

BUS_OFF: int

控制器已开启但不参与总线活动(TEC 溢出超过 255)。

经典 CAN 滤波器模式(OpenMV Cam M4 / M7 上 setfilter()mode 参数):

LIST16: int

滤波器 params 数组保存四个将被接受的 16 位 ID。

LIST32: int

滤波器 params 数组保存两个将被接受的 32 位 ID。

MASK16: int

滤波器 params 数组保存两个 16 位的 (id, mask) 对。

MASK32: int

滤波器 params 数组保存一个 32 位的 (id, mask) 对。

CAN FD 滤波器模式(OpenMV Cam H7 / H7 Plus / Pure Thermal 上 setfilter()mode 参数):

RANGE: int

滤波器 params 数组保存两个 ID,构成接受 ID 的一个范围。

DUAL: int

滤波器 params 数组保存两个要接受的特定 ID。

MASK: int

滤波器 params 数组保存一个 (id, mask) 对。