尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

CanFestival 协议栈解析笔记(一)

CanFestival 协议栈解析笔记(一)
📅 发布时间:2026/7/12 9:07:28

一、协议栈分层架构

┌──────────────────────────────────────────────┐
│ CiA 402 驱动层 (cia402_fsm / modes / servo) │ ← 应用层状态机
├──────────────────────────────────────────────┤
│ CANopen 协议核心 │
│ ┌────────┬───────┬──────┬───────┬─────────┐ │
│ │ NMT │ SDO │ PDO │ EMCY │ SYNC │ │ ← CiA 301 协议栈
│ │ co_nmt │co_sdo │co_pdo│co_emcy│co_sync │ │
│ └────────┴───────┴──────┴───────┴─────────┘ │
├──────────────────────────────────────────────┤
│ 对象字典 OD (co_od) — 二分查找 + 回调机制 │ ← 数据总线层
├──────────────────────────────────────────────┤
│ 硬件抽象层 (can_send 函数指针) │ ← 驱动接口
├──────────────────────────────────────────────┤
│ CAN 控制器中断 / 定时器中断 │ ← 中断层
└──────────────────────────────────────────────┘

关键设计特点:

模块核心函数被调用上下文
NMTco_nmt_process_command()CAN RX 中断
NMTco_nmt_tick()定时器中断 (心跳)
SDOco_sdo_server_process()CAN RX 中断
SDOco_sdo_server_tick()定时器中断 (超时)
PDOco_pdo_on_rpdo()CAN RX 中断
PDOco_pdo_on_sync()CAN RX 中断 (SYNC帧)
PDOco_pdo_mark_changed()应用层/主循环
PDOco_pdo_tick()/co_pdo_tick_ms()定时器中断
EMCYco_emcy_trigger()任意上下文
EMCYco_emcy_tick()定时器中断 (重发)

二、canDispatch与TimeDispatch的中断关系

在经典 CanFestival 中,两者都存在,且都需要在中断上下文中被调用:

canDispatch() ← 在 CAN RX 中断 ISR 中调用 TimeDispatch() ← 在硬件定时器 ISR(如 SysTick)中调用
场景分析(以 ARM Cortex-M 为例)
NVIC 优先级配置 (数字越小优先级越高): 场景 A — 同优先级(推荐): CAN_RX_IRQ 优先级 = 4 TIMER_IRQ 优先级 = 4 → 不会互相抢占 (Cortex-M 对同优先级用尾链 Tail-Chaining) → canDispatch 和 TimeDispatch 是原子的,不会嵌套 场景 B — CAN 优先级高于定时器: CAN_RX_IRQ 优先级 = 2 TIMER_IRQ 优先级 = 4 → canDispatch 可以抢占 TimeDispatch ⚠️ 危险 → TimeDispatch 修改 OD 数据时,canDispatch 也可能读写同一 OD 条目 场景 C — 定时器优先级高于 CAN: → TimeDispatch 可以抢占 canDispatch ⚠️ 同样危险

同优先级是安全

看关键代码路径。以RPDO 写入 OD为例,在co_pdo_on_rpdo()中:

// src/canopen/co_pdo.c — co_pdo_on_rpdo() od_write(pdo->od, me->index, me->subindex, buf, byte_len); 而 od_write() 内部是纯 memcpy(src/canopen/co_od.c:73): memcpy(entry->pdata, buf, size);

没有任何锁保护。如果TimeDispatch(定时器中断)正在通过co_pdo_tick_ms()遍历 TPDO 并调用od_read(),而canDispatch(CAN 中断)同时通过co_pdo_on_rpdo()写入同一个 OD 条目——这就是典型的数据竞争。

但若两者同优先级,Cortex-M 内核保证:

  • 当 CPU 正在处理 TIMER_IRQ 时,同优先级的 CAN_RX_IRQ 不会被响应,而是等到 TIMER_IRQ 返回后才进入
  • 反之亦然

结论:canDispatch和TimeDispatch在设计良好的系统中不会互相打断,前提是 CAN RX 中断和定时器中断配置为同一优先级。

三、高优先级 ADC 中断能否抢占它们?

能,而且这是一个需要特别注意的问题。

NVIC 优先级: ADC_IRQ 优先级 = 1 (最高) CAN_RX_IRQ 优先级 = 4 TIMER_IRQ 优先级 = 4 当 canDispatch 或 TimeDispatch 正在执行时,优先级更高的 ADC 电流采样中断会直接抢占: 时间轴: ──────────────────────────────────────────────────── TIMER_IRQ 开始 → TimeDispatch() 执行到一半 ↓ ADC 触发 ADC_IRQ 抢占 ───── ADC_ISR 执行 ───── 返回 ↓ TimeDispatch() 继续执行 ────────────────────────────────────────────────────
这是否危险?取决于 ADC ISR 做了什么。

危险场景 — ADC ISR 访问了 CANopen 数据:

如果 ADC ISR 中通过od_read()读取电流反馈值(如0x6078实际电流),而canDispatch正在通过od_write()修改同一 OD 条目:

// ADC ISR 中: od_read(od, 0x6078, 0, &buf, &size); // 读 current_actual_value // 同时 canDispatch 在 SDO 处理中: od_write(sdo->od, index, sub, &write_data, data_size);

由于od_read/od_write内部是裸memcpy,会导致读到撕裂值 (torn read)——数据部分来自写入前、部分来自写入后。

安全场景 — ADC ISR 只写自己的 buffer:

如果 ADC ISR 使用 DMA 双缓冲,将采集数据写入独立的adc_buffer[],在主循环中再同步到 OD,则抢占是安全的。

仓库的实际情况

查看 OD 回调机制(src/canopen/co_od.c:74-80):

if (od->post_write_cb) { uint32_t r = od->post_write_cb(index, subindex, entry->pdata, size, true); if (r != 0) return r; }
如果 ADC ISR 的高优先级抢占导致 post_write_cb 中的回调函数 (可能触发电机控制参数更新)执行到一半被更高优先级中断嵌套, 会产生不可预期的行为,因为OD 回调函数本身没有可重入保护。

四、总结与建议

问题结论
canDispatch 与 TimeDispatch 能否互抢?不应该。应配置 CAN RX 和 Timer 中断为同优先级,利用 Cortex-M 尾链机制保证原子性
高优先级 ADC ISR 能否抢占?能。ARM NVIC 允许高优先级中断抢占低优先级
抢占是否有风险?有条件:若 ADC ISR 只写独立 buffer 则安全;若读写 OD 结构体则存在数据竞争

推荐的加固措施:

  1. 配置 CAN RX 和 Timer 中断为同一优先级(你已经提到)
  2. 保护 OD 关键区——在od_read/od_write周围使用__disable_irq()/__enable_irq()或 BASEPRI 屏蔽(参考经典 CanFestival 的EnterMutex/LeaveMutex宏)
  3. ADC ISR 使用独立的数据通道——通过 DMA 双缓冲写入,不直接访问od_entry_t.pdata
  4. 使用 BASEPRI 精确屏蔽——只屏蔽 CANopen 相关优先级,不阻断 ADC:
// 进入 CANopen 关键区时 UINT32 oldbasepri = __get_BASEPRI(); __set_BASEPRI(3 << (8 - __NVIC_PRIO_BITS)); // 屏蔽优先级 4-15 od_write(...); // 安全操作 __set_BASEPRI(oldbasepri); // 恢复, ADC (优先级1) 仍可抢占

这样 ADC 仍能实时采样,而 CANopen 协议栈内部的数据一致性得到保障。

以上就是完整的分析。

核心要点:canDispatch 和 TimeDispatch 若配置为同优先级则不会互相打断(利用 Cortex-M 尾链机制),但高优先级 ADC 中断确能抢占它们。是否安全取决于 ADC ISR 是否访问共享数据。如需加固,BASEPRI 是兼顾实时性和数据一致性的最优方案。

相关新闻

  • STM32F205RB直流电机控制实战与Fusion开发技巧
  • BetterNCM-Installer终极指南:3分钟打造你的专属网易云音乐
  • 2026江门卫生间免砸砖防水哪家专业?外墙、地下室、楼顶渗漏维修公司(7月) - 防水企业百科

最新新闻

  • OpenEuler Computing-docs深度解析:sysBoost如何提升程序性能30%以上
  • 5分钟快速上手:小红书无水印批量下载工具终极指南
  • 原生 JS 实现自定义单选日历组件(无 UI 库、纯手写、禁用过去日期)
  • Cesium 热力图教程
  • 3分钟搞定Godot游戏资源提取:终极PCK解包指南
  • 古法黄金饰品多品牌实测:工艺质感与保值性对比评测 - 招财兔数字员工

日新闻

  • IX9104 PCIe5.0 高速交换芯片@ACP#完整规格 + 应用场景总结
  • Unity游戏集成Coze智能体:实现NPC智能对话与知识库联动
  • SAP EPIC 建行回单查询:从标准类CL_EPIC_EXAMPLE_CN_CCB_GHTD到Z类的5处关键修改

周新闻

  • IX9104 PCIe5.0 高速交换芯片@ACP#完整规格 + 应用场景总结
  • Unity游戏集成Coze智能体:实现NPC智能对话与知识库联动
  • SAP EPIC 建行回单查询:从标准类CL_EPIC_EXAMPLE_CN_CCB_GHTD到Z类的5处关键修改

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号