ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MicroPython pyb.CAN 模块详解:在 pyboard 上使用经典 CAN 与 CAN FD 总线

MicroPython pyb.CAN 模块详解:在 pyboard 上使用经典 CAN 与 CAN FD 总线 MicroPython pyb.CAN 模块详解在 pyboard 上使用经典 CAN 与 CAN FD 总线【免费下载链接】micropythonMicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems项目地址: https://gitcode.com/gh_mirrors/mi/micropython导读pyb.CAN是 MicroPython 面向 STM32 pyboard 系列板卡提供的 CANController Area Network总线通信模块底层直接封装 STM32 的 bxCAN经典 CAN与 FDCANCAN FD外设。本文以官方文档 docs/library/pyb.CAN.rst 为主体结合 ports/stm32/pyb_can.c、ports/stm32/can.c、ports/stm32/can.h 等源码与测试用例完整讲解 CAN 对象构造、位时序参数计算、收发流程、报文过滤、错误状态管理与中断回调帮助你从“能跑通示例”进阶到“能根据波特率、采样点、过滤规则和错误计数调优一套稳定的 CAN 通信方案”。CAN 总线与 pyboard 硬件基础CAN 是广泛用于汽车电子、工业控制和嵌入式设备互联的串行通信协议。pyb.CAN在物理层上仅涉及两根信号线RX接收与 TX发送。需要特别强调的是pyboard 的 GPIO 输出的是 3.3V 逻辑电平无法直接驱动 CAN 总线上的差分信号因此必须外接 CAN 收发器transceiver如 TJA1050、MCP2551 等将逻辑电平转换为总线电平。从源码看模块在两种 STM32 CAN 控制器上共用同一套 Python API由编译开关MICROPY_HW_ENABLE_FDCAN区分经典 CANbxCAN用于 STM32 F4、F7 系列 MCU单帧数据最长 8 字节CAN FDFDCAN用于 STM32 H7及 G4、N6 等系列 MCU支持 FD 帧格式数据载荷最长 64 字节并支持 Bit Rate SwitchBRS双速率。抽象层 API 统一在 ports/stm32/can.h 中声明其注释明确指出该头文件是 ST HAL 两套 CAN 控制器 APIbxCAN 与 FDCAN之上的统一封装底层实现分为 ports/stm32/can.c经典 CAN与 ports/stm32/fdcan.cCAN FD两个文件一块开发板编译时只会包含其一。pyboard 上的 CAN 引脚映射文档给出两块 CAN 总线的固定引脚对应 pyboard 的 Y 系列排针与 STM32 引脚号CAN(1)位于YA(RX, TX) (Y3, Y4) (PB8, PB9)CAN(2)位于YB(RX, TX) (Y5, Y6) (PB12, PB13)构造对象时bus参数既可以是数字1、2也可以传字符串YA或YB。从 pyb_can.c 的pyb_can_make_new可以看到总线编号最终通过machine_can_get_index(args[0])归一化为 0 基索引再映射到具体外设实例。快速上手两个可直接运行的示例示例一经典 CAN 回环无需收发器经典 CAN 控制器支持Loopback回环模式报文在控制器内部自发自收不需要连接总线或收发器非常适合在没有外部硬件的情况下验证 APIfrom pyb import CAN can CAN(1, CAN.LOOPBACK) # 设置过滤器只接收 id 为 123、124、125、126 的报文 can.setfilter(0, CAN.LIST16, 0, (123, 124, 125, 126)) can.send(message!, 123) # 以 id123 发送报文 can.recv(0) # 从 FIFO 0 接收报文示例二CAN FD 全特性配置H7 系列支持 FD 帧 BRS 双速率 扩展帧 ID。下面的配置让仲裁段arbitration phase运行在 500 Kbit/s、数据段data phase运行在 1 Mbit/sfrom pyb import CAN can CAN(1, CAN.NORMAL, baudrate500_000, brs_baudrate1_000_000, sample_point80) can.setfilter(0, CAN.RANGE, 0, (0xFFF0, 0xFFFF)) # 接收扩展 ID 在 [0xFFF0, 0xFFFF] 范围内的报文 can.send(a * 64, 0xFFFF, fdfTrue, brsTrue, extframeTrue) # 发送 64 字节 FD 报文 can.recv(0)两段示例对应的收发逻辑分别由 pyb_can_send 与 pyb_can_recv 实现其中 FD 帧格式、BRS 开关、扩展/标准 ID、数据帧/远程帧的选择均直接映射到 FDCAN 的发送头部结构体字段。构造与初始化构造函数 CAN(bus, ...)CAN(bus, ...)bus1-2部分板卡还支持3或YA/YB不传额外参数时仅创建 CAN 对象但不重新初始化沿用该总线上次初始化留下的配置如果有传入额外参数时立即执行初始化参数与CAN.init()完全一致。从 pyb_can.c 可以看到一个实用细节若对象已启用且再次传入参数代码会先pyb_can_deinit使硬件进入初始化模式再重新配置同时会重置 RX 回调与 FIFO 状态机。init() 与位时序参数CAN.init(mode, prescaler100, *, sjw1, bs16, bs28, auto_restartFalse, baudrate0, sample_point75, num_filter_banks14, brs_sjw1, brs_bs18, brs_bs23, brs_baudrate0, brs_sample_point75)其中brs_*系列参数仅存在于支持 CAN FD 的板卡上用于配置可选的 BRSBit Rate Switch特性。各参数含义与取值范围如下参数含义经典 CAN 范围CAN FD 范围mode总线工作模式NORMAL / LOOPBACK / SILENT / SILENT_LOOPBACK同左prescaler分频系数决定标称位时间量子 tq1 ~ 10241 ~ 512sjw重同步跳转宽度tq 为单位1 ~ 41 ~ 128bs1位段 1采样点位置tq 为单位1 ~ 162 ~ 256bs2位段 2发送点位置tq 为单位1 ~ 82 ~ 128auto_restart进入 bus-off 后是否自动重启通信布尔值—baudrate自动计算标称位时序的目标波特率非 0 时覆盖 prescaler/bs1/bs2同左sample_point采样点位置标称位时间百分比整数默认 75%同左num_filter_banks分配给 CAN(1) 的过滤器组数共 28 组仅经典 CAN—brs_*BRS 数据段位时序prescaler/sjw/bs1/bs2/baudrate/sample_point—prescaler 1~32sjw 1~16bs1 1~32bs2 1~16上述范围与 pyb_can.c 中的宏定义严格对应经典 CAN 的CAN_MAXIMUM_NBRP1024、NBS116、NBS28FD CAN 的CAN_MAXIMUM_NBRP512、NBS1256、NBS2128BRS 数据段的CAN_MAXIMUM_DBRP32、DBS132、DBS216。时间量子与位时序的换算关系CAN 位时序的基本单位是时间量子 tq其计算公式为tq prescaler / PCLK1其中 PCLK1 是 STM32 内部外设总线 1 的频率可用pyb.freq()查询见 pyb 模块文档。一个位bit由以下部分构成同步段Synchronisation Segment固定为 1 tq位段 1BS1同步段之后采样点位于 BS1 结束处位段 2BS2BS2 结束处为发送点。因此bittime (1 BS1 BS2) × tq baudrate 1 / bittime文档给出的示例PCLK1 42 MHz、prescaler 100、sjw 1、bs1 6、bs2 8 时tq 2.38 µsbittime 35.7 µs波特率约 28 kHz。更详细的外设寄存器说明可参考 STM32F405 数据手册文档中提示见第 680 页。baudrate sample_point 自动计算当baudrate非 0 时init()会尝试自动计算标称位时序覆盖 prescaler、bs1、bs2目标是同时满足波特率误差在0.1%以内采样点与目标值误差在1%以内取最接近的整数百分比。如需精确控制时序则直接显式设置 prescaler/bs1/bs2。sample_point仅在设置了baudrate时才生效默认 75%。brs_baudrate/brs_sample_point对数据段同理且源码中有一个细节若未提供brs_sample_point会默认沿用标称段的sample_point见 pyb_can.c。该自动计算由pyb_can_get_bit_timing()完成pyb_can.c其核心是三重循环遍历brp × (1 bs1 bs2)组合逐一校验波特率误差与采样点误差找不到满足组合时抛出ValueErrorcouldnt match baudrate %u and sample point %u。时钟源来自can_get_source_freq()经典 CAN 实现直接返回HAL_RCC_GetPCLK1Freq()can.c。关于 auto_restart 与 num_filter_banks 的补充说明auto_restartTrue时控制器在 bus-off 后自动恢复通信关闭时需手动调用CAN.restart()退出 bus-off见下文。num_filter_banks只影响经典 CANSTM32 的 CAN1/CAN2 共享 28 组过滤器该参数决定分给 CAN(1) 的组数其余归 CAN(2)。源码中对应全局变量can2_start_bankpyb_can.c发送/接收与过滤器配置都会以此为边界做偏移校验。需要指出的是源码注释表明当前machine.CAN实现将过滤器固定为 14/14 分配而pyb.CAN通过本参数支持自定义分配。deinit() 与 restart()CAN.deinit()关闭 CAN 总线。经典 CAN 实现还会按当前can2_start_bank清理本总线负责的过滤器组防止重新初始化时残留旧过滤规则pyb_can.c。CAN.restart()在不重置配置的前提下对控制器执行软件重启。适用于auto_restartFalse时退出 bus-off 状态重启后控制器会遵循 CAN 协议从 bus-off 依次恢复到 error active 状态重新参与总线活动。控制器状态与诊断信息state()五种控制器状态CAN.state()返回控制器当前状态对应常量与判定条件如下状态常量含义判定条件CAN.STOPPED控制器完全关闭并复位—CAN.ERROR_ACTIVE开启且处于 Error ActiveTEC 与 REC 均 96CAN.ERROR_WARNING处于 Error WarningTEC 或 REC ≥ 96CAN.ERROR_PASSIVE处于 Error PassiveTEC 或 REC ≥ 128CAN.BUS_OFF开启但不参与总线活动TEC 溢出超过 255状态枚举定义在 can.h 的can_state_t中与 Python 常量一一对应。state()在对象未启用时直接返回STOPPED。info()错误计数与缓冲区状态CAN.info([list])返回一个包含 8 个元素的列表可传入至少 8 个元素的 list 对象复用否则新建内容依次为TEC发送错误计数REC接收错误计数进入 Error Warning 状态的次数超过 65535 后回绕为 0进入 Error Passive 状态的次数同上回绕进入 Bus Off 状态的次数同上回绕待发送TX pending报文数FIFO 0 中待接收报文数FIFO 1 中待接收报文数前两项来自硬件计数器中间三项由 ISR 中的累计变量维护。从 pyb_can.c 的pyb_can_irq_handler可以看到CAN_INT_ERR_BUS_OFF、CAN_INT_ERR_PASSIVE、CAN_INT_ERR_WARNING三类错误中断只做计数累加不触发 Python 回调。硬件计数器结构can_counters_t定义于 can.h。这些计数对排查“总线是否真的有设备在应答”“发送是否持续失败导致 bus-off”等故障非常有价值。报文过滤setfilter / clearfilterCAN 报文过滤器的作用是让控制器只接收感兴趣 ID 的报文从而降低 CPU 中断负担。pyb.CAN为经典 CAN 与 CAN FD 提供了两套完全不同的过滤 API。setfilter(bank, mode, fifo, params, *, rtr, extframeFalse)参数说明bank经典 CAN 的过滤器组编号或 CAN FD 的过滤器索引mode过滤模式见下表fifo命中过滤的报文存入 FIFO 0 还是 FIFO 1params定义过滤器内容的数值数组元素个数随 mode 变化rtr仅经典 CAN 有效布尔数组声明各过滤条目是否接受远程传输请求RTR帧不传时默认全部为FalseextframeTrue表示使用 29 位扩展标识符False使用 11 位标准标识符。经典 CAN 控制器的过滤模式params 数组内容modeparams 数组内容CAN.LIST164 个 16 位 ID命中任一即接收CAN.LIST322 个 32 位 IDCAN.MASK162 组 16 位 ID/掩码对。例(1, 3, 4, 4)中第一对1, 3接收所有 bit01 且 bit10 的 ID第二对4, 4接收所有 bit21 的 IDCAN.MASK32同 MASK16但仅 1 组 32 位 ID/掩码对CAN FD 控制器的过滤模式params 数组内容modeparams 数组内容CAN.RANGE2 个 ID表示一段可接收的 ID 范围CAN.DUAL2 个 ID例(1, 2)只接收 ID 1 和 2CAN.MASK1 个过滤器 ID 加 1 个掩码例(0x111, 0x7FF)rtr 数组长度仅经典 CANmodertr 数组长度CAN.LIST164CAN.LIST322CAN.MASK162CAN.MASK321从 pyb_can_setfilter 的源码看过滤参数会被编码进硬件过滤器寄存器经典 CAN 的 16 位模式将 ID 左移 5 位填入寄存器并叠加 RTR 掩码位32 位模式按(ID 0x1FFFE000) 13与低 13 位重排CAN FD 则直接构造FDCAN_FilterTypeDef并校验FilterIndex是否超出硬件标准/扩展过滤器数量H7 上标准过滤器最多 64 个、扩展过滤器最多 31 个见 can.h。参数不合法时统一抛出ValueError(CAN filter parameter error)。clearfilter(bank, extframeFalse)bank要清除的过滤器组/索引extframe仅 CAN FD 有效。True清除用extframeTrue配置的扩展过滤器False清除标准过滤器。经典 CAN 下该调用会换算 bank 偏移CAN2 需要加上can2_start_bank后调用硬件清除。报文收发send / recv / anysend(data, id, *, timeout0, rtrFalse, extframeFalse, fdfFalse, brsFalse)data要发送的数据可以是整数或 buffer 对象id报文 IDtimeout发送超时毫秒。0 表示非阻塞报文被放入 3 个硬件发送缓冲之一后立即返回若 3 个缓冲全部占用则抛出异常。非 0 时阻塞等待发送完成超时未完成同样抛异常rtr为True时按远程传输请求帧发送此时只使用data的长度填充 DLC 字段数据字节内容被忽略extframeTrue使用 29 位扩展 ID否则 11 位标准 IDfdfCAN FD 专用True时使用 FD 帧格式载荷最长 64 字节brsCAN FD 专用True时启用位速率切换数据段以init()中配置的 BRS 时序发送。返回值恒为None。发送实现会校验data长度不超过CAN_MAX_DATA_FRAME经典 CAN 为 8FD 为 64超长抛出ValueError见 pyb_can.c。经典 CAN 发送时StdId被 0x7FF截断、扩展 ID 被 0x1FFFFFFF截断超出位宽的高位会被静默丢弃这一点在 测试用例 中也有覆盖发送-1与0x7FF1后验证回环接收结果。recv(fifo, listNone, *, timeout5000)fifo接收的 FIFO 编号0 或 1list可选复用列表timeout接收超时毫秒默认 5000。返回值是一个包含 5 个元素的列表报文 ID布尔值ID 是标准还是扩展布尔值是否为 RTR 报文FMIFilter Match Index命中的过滤器索引数据数组bytes 对象。零堆内存接收技巧默认调用会分配新的列表和 bytes 对象。若要避免堆分配例如在实时性要求高的场景可传入预构建的listmemoryviewbuf bytearray(8) lst [0, 0, 0, 0, memoryview(buf)] # 以下调用不分配任何堆内存 can.recv(0, lst)复用要求list至少 5 个元素第 5 个元素必须是基于bytearray或B/b类型 array 创建的 memoryview且底层缓冲区至少能容纳 8 字节。接收后该 memoryview 会被原地缩放到实际数据长度并填充数据同一组list/memoryview可在后续调用中反复使用。这一机制在 pyb_can.c 中有严格校验第 5 元素必须为可写的bytearray或b类型 memoryview否则抛 TypeError/ValueError并有对应的测试tests/ports/stm32/pyb_can.py中在micropython.heap_lock()下执行发送/接收并断言l is l2。recv还承担 FIFO 状态机的维护在注册了 RX 回调的情况下接收完消息后会根据 FIFO 是否排空重新使能相应中断见 pyb_can.c。any(fifo)返回布尔值指定 FIFO 上是否有等待接收的报文。底层通过can_is_rx_pending()检查硬件 FIFO 填充级别/消息挂起标志经典 CAN 为__HAL_CAN_MSG_PENDING见 can.h。中断回调rxcallback(fifo, fun)CAN.rxcallback(fifo, fun)注册一个回调函数在空 FIFO 接收到报文时被调用fifo接收 FIFO 编号fun回调函数接收两个参数CAN 对象本身、以及表示回调原因reason的整数。reason 取值reason含义0报文被收入一个此前为空的 FIFO1FIFO 已满2因 FIFO 满而丢失报文官方示例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)源码实现细节pyb_can.c 与 pyb_can.c传入None会禁用该 FIFO 的接收中断并清除回调回调已存在时只替换函数对象中断处理函数运行 Python 回调前会先mp_sched_lock()与gc_lock()防止回调执行期间发生调度与垃圾回收导致的重入问题若回调抛出未捕获异常会自动禁用该回调并打印错误信息避免中断风暴。回调 reason 与中断类型的对应关系在 can.h 的can_int_t枚举中有注释说明CAN_INT_MESSAGE_RECEIVED、CAN_INT_FIFO_FULL、CAN_INT_FIFO_OVERFLOW前三个值即对应rxcallback的参数。常量汇总工作模式用于init()/ 构造函数CAN.NORMAL、CAN.LOOPBACK、CAN.SILENT、CAN.SILENT_LOOPBACK控制器状态来自state()CAN.STOPPED、CAN.ERROR_ACTIVE、CAN.ERROR_WARNING、CAN.ERROR_PASSIVE、CAN.BUS_OFF经典 CAN 过滤器模式用于setfilter()CAN.LIST16、CAN.MASK16、CAN.LIST32、CAN.MASK32CAN FD 过滤器模式用于setfilter()CAN.DUAL、CAN.RANGE、CAN.MASK从 pyb_can.c 的常量表可以看到经典 CAN 的 ST 常数被 4压缩为小整数再在 init 时还原这是为了适配 MicroPython 小整数存储的优化CAN FD 分支则直接使用 FDCAN 的过滤模式常量。实践建议与常见问题没有收发器也能先跑通软件栈使用CAN.LOOPBACK模式做自发自收验证配合setfilter限制接收范围。官方测试 tests/ports/stm32/pyb_can.py 与 tests/ports/stm32/pyb_can_classic_rx.py 均基于回环模式可作参考。波特率与采样点优先用baudratesample_point组合让固件自动计算位时序对时序要求苛刻长总线、多节点时再手动调prescaler/bs1/bs2并参考pyb.freq()确认 PCLK1。过滤器划分多节点、多报文类型的场景下用num_filter_banks合理分配 CAN1/CAN2 的 28 组过滤器FIFO 0/1 搭配不同过滤器可以让高优先级报文与普通报文分流处理。总线故障排查通过state()判断是否进入BUS_OFF用info()观察 TEC/REC 与进入各错误态的累计次数判断是发送失败还是总线干扰auto_restart关闭时记得在错误处理后调用restart()。CAN FD 兼容性fdf、brs参数只在支持 FDCAN 的芯片H7 等上可用且 BRS 要求数据段波特率配置brs_*合理接收端必须支持 FD 帧否则会出现通信失败。远程帧经典 CAN 发送 RTR 帧时用rtrTrue接收端可在过滤器rtr参数中声明是否接受远程帧CAN FD 下rtr参数被忽略。参考与延伸阅读模块官方文档docs/library/pyb.CAN.rstPython 层实现方法、常量、IRQ 回调ports/stm32/pyb_can.c底层抽象 API 与硬件常量ports/stm32/can.h经典 CAN 底层驱动ports/stm32/can.cCAN FD 底层驱动ports/stm32/fdcan.c自动化测试tests/ports/stm32/pyb_can.py、tests/ports/stm32/pyb_can_classic_rx.py、tests/ports/stm32/pyb_can_classic_rtr_filter.py获取系统时钟PCLK1参考docs/library/pyb.rst【免费下载链接】micropythonMicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems项目地址: https://gitcode.com/gh_mirrors/mi/micropython创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表