Affected area
Device drivers
Hardware/BSP vendor
Not applicable / Other
Architecture
Not applicable / Other
Describe problem solved by the proposed feature
目前在使用 RT-Thread CAN 框架实现 CANopen CiA 305 LSS Activate Bit Timing(运行时切换 CAN bitrate)时,需要在切换前后建立一个明确的 TX 静默窗口。
在上层 CANopen 协议栈中,可以通过软件 TX gate 阻止新的 CANopen 报文继续进入发送路径,例如:
Disable CANopen TX
↓
PRE_DELAY
↓
Switch bitrate
↓
POST_DELAY
↓
Enable CANopen TX
但仅有上层 software TX gate 仍不足以形成完整的 TX quiesce,因为在关闭 gate 之前,可能已经存在:
1. RT-Thread CAN non-blocking 软件发送队列中的报文;
2. 已经提交到 CAN controller hardware mailbox 的报文;
3. 正在等待 TX completion 的 blocking sender。
这些报文可能在上层已经停止产生新 TX 后继续发送。
因此希望 RT-Thread CAN framework 能提供一个明确的 TX Full Flush / Hardware Abort 能力,用于建立可靠的发送静默边界。
Describe your preferred solution
当前遇到的问题
当前 CAN framework 已经同时存在 blocking 和 non-blocking TX 路径。
non-blocking TX 在硬件 mailbox busy 时会进入 framework 的软件 ringbuffer;TX complete ISR 后还会继续从该 ringbuffer 中取报文并重新提交到硬件。
blocking TX 则会占用 TX mailbox slot,并等待对应 completion。
对于 STM32 bxCAN,驱动底层本身也具备取消 hardware TX request 的能力,例如可以使用:
或者 bxCAN 的:
CAN_TSR_ABRQ0
CAN_TSR_ABRQ1
CAN_TSR_ABRQ2
但目前 CAN framework 没有一个统一的 API,可以同时完成:
停止新的 TX
+
清空 framework software TX queue
+
abort hardware pending TX
+
正确结束正在等待的 blocking TX
另外,当前 RT_CAN_CMD_START(false) 对 STM32 CAN 的语义更接近 controller deinit,并不适合作为精确的 TX abort / flush API。
希望支持的能力
希望 RT-Thread CAN framework 增加一个明确的 TX quiesce / full flush 能力,至少覆盖以下内容。
1. Framework TX Gate
允许临时禁止新的 rt_device_write() TX 请求继续进入发送路径。
例如可以考虑:
或者等价机制。
同时 TX complete ISR 在继续从 non-blocking software FIFO refill hardware mailbox 前,也需要遵守该 gate。
2. Software TX Queue Flush
能够清除尚未提交到硬件的 non-blocking TX queue,例如当前 CAN device 内部的:
这样 flush 返回后,不会因为后续 TX interrupt 又把旧报文重新送入 hardware mailbox。
3. Hardware Pending TX Abort
为底层 CAN driver 提供统一的 hardware abort capability,例如:
STM32 bxCAN 可以实现为:
该接口只负责取消已经进入 CAN controller mailbox 的 TX request,不负责操作 framework software queue。
其他不支持 hardware abort 的 CAN driver 可以明确返回:
而不是静默成功。
4. Blocking TX Cancellation
如果某个线程已经进入 blocking CAN TX,并正在等待 TX completion,full flush 需要能够让该 sender 正常退出。
这里希望保持原 sender 对 mailbox slot 的 ownership。
也就是说,flush 不应该直接替 sender 重置 semaphore / freelist,而是将该 TX 标记为 abort,并唤醒 waiter,由原 sender 按正常错误退出路径完成 slot 回收,避免:
double sem release
freelist corruption
completion 状态失配
Describe possible alternatives
建议方案
我计划按下面的分层方式实现并提交:
RT_CAN_CMD_SET_TX_ENABLE
↓
RT-Thread CAN framework TX gate
RT_CAN_CMD_FLUSH_TX
↓
CAN framework
├─ disable TX gate
├─ clear software TX queue
├─ snapshot/cancel blocking TX
└─ call driver hardware abort
↓
RT_CAN_CMD_ABORT_TX
↓
STM32 CAN driver
↓
HAL_CAN_AbortTxRequest()
其中建议明确区分:
仅表示 driver 层的 hardware pending TX abort;
而:
表示 framework 层完整的 TX full flush transaction。
这样上层协议栈不需要直接依赖 STM32 HAL 或具体 mailbox 实现。
预期使用方式
以 CANopen CiA 305 LSS Activate Bit Timing 为例,后续可以采用:
Disable CANopen TX
↓
RT_CAN_CMD_FLUSH_TX
│
├─ disable RT-Thread CAN TX
├─ clear software TX FIFO
├─ abort hardware pending TX
└─ terminate blocking TX waiter
↓
PRE_DELAY
↓
RT_CAN_CMD_SET_BAUD
↓
POST_DELAY
↓
Enable RT-Thread CAN TX
↓
Enable CANopen TX
这样能够同时解决两个不同层面的问题:
software TX gate
-> 不再产生/接受新的 TX
full flush + hardware abort
-> 已经进入 software queue / hardware mailbox 的旧 TX 也被清除
为什么需要这个特性
这个需求最初来自 CANopen LSS runtime bitrate activation,但并不局限于 CANopen。
类似能力对于以下场景也有通用价值:
- CAN bitrate / mode 动态切换;
- bus recovery / bus-off recovery 前清理历史 TX;
- controller suspend / reconfigure;
- bootloader / application CAN ownership 切换;
- 协议要求建立严格 TX silence window 的场景。
相比直接 HAL_CAN_DeInit() 或完整 stop/restart CAN controller,一个专门的 TX flush / abort API 可以提供更明确、更小副作用的语义,同时保持 CAN framework 与具体硬件驱动之间的分层。
计划
如果这个方向没有问题,我将按照上述方案先完成:
1. CAN framework TX gate;
2. software TX queue full flush;
3. blocking TX abort/wakeup;
4. STM32 bxCAN hardware abort;
5. 对应的并发和 TX queue 测试。
实现时会尽量控制改动范围,并优先通过 control command 扩展,避免第一版直接修改 struct rt_can_ops 而影响所有现有 CAN driver。
也欢迎对 API 命名、flush 语义以及 driver capability 分层方式提出建议。
Affected area
Device drivers
Hardware/BSP vendor
Not applicable / Other
Architecture
Not applicable / Other
Describe problem solved by the proposed feature
目前在使用 RT-Thread CAN 框架实现 CANopen CiA 305 LSS
Activate Bit Timing(运行时切换 CAN bitrate)时,需要在切换前后建立一个明确的 TX 静默窗口。在上层 CANopen 协议栈中,可以通过软件 TX gate 阻止新的 CANopen 报文继续进入发送路径,例如:
但仅有上层 software TX gate 仍不足以形成完整的 TX quiesce,因为在关闭 gate 之前,可能已经存在:
这些报文可能在上层已经停止产生新 TX 后继续发送。
因此希望 RT-Thread CAN framework 能提供一个明确的 TX Full Flush / Hardware Abort 能力,用于建立可靠的发送静默边界。
Describe your preferred solution
当前遇到的问题
当前 CAN framework 已经同时存在 blocking 和 non-blocking TX 路径。
non-blocking TX 在硬件 mailbox busy 时会进入 framework 的软件 ringbuffer;TX complete ISR 后还会继续从该 ringbuffer 中取报文并重新提交到硬件。
blocking TX 则会占用 TX mailbox slot,并等待对应 completion。
对于 STM32 bxCAN,驱动底层本身也具备取消 hardware TX request 的能力,例如可以使用:
HAL_CAN_AbortTxRequest()或者 bxCAN 的:
但目前 CAN framework 没有一个统一的 API,可以同时完成:
另外,当前
RT_CAN_CMD_START(false)对 STM32 CAN 的语义更接近 controller deinit,并不适合作为精确的 TX abort / flush API。希望支持的能力
希望 RT-Thread CAN framework 增加一个明确的 TX quiesce / full flush 能力,至少覆盖以下内容。
1. Framework TX Gate
允许临时禁止新的
rt_device_write()TX 请求继续进入发送路径。例如可以考虑:
RT_CAN_CMD_SET_TX_ENABLE或者等价机制。
同时 TX complete ISR 在继续从 non-blocking software FIFO refill hardware mailbox 前,也需要遵守该 gate。
2. Software TX Queue Flush
能够清除尚未提交到硬件的 non-blocking TX queue,例如当前 CAN device 内部的:
nb_tx_rb这样 flush 返回后,不会因为后续 TX interrupt 又把旧报文重新送入 hardware mailbox。
3. Hardware Pending TX Abort
为底层 CAN driver 提供统一的 hardware abort capability,例如:
RT_CAN_CMD_ABORT_TXSTM32 bxCAN 可以实现为:
HAL_CAN_AbortTxRequest()该接口只负责取消已经进入 CAN controller mailbox 的 TX request,不负责操作 framework software queue。
其他不支持 hardware abort 的 CAN driver 可以明确返回:
而不是静默成功。
4. Blocking TX Cancellation
如果某个线程已经进入 blocking CAN TX,并正在等待 TX completion,full flush 需要能够让该 sender 正常退出。
这里希望保持原 sender 对 mailbox slot 的 ownership。
也就是说,flush 不应该直接替 sender 重置 semaphore / freelist,而是将该 TX 标记为 abort,并唤醒 waiter,由原 sender 按正常错误退出路径完成 slot 回收,避免:
Describe possible alternatives
建议方案
我计划按下面的分层方式实现并提交:
其中建议明确区分:
仅表示 driver 层的 hardware pending TX abort;
而:
表示 framework 层完整的 TX full flush transaction。
这样上层协议栈不需要直接依赖 STM32 HAL 或具体 mailbox 实现。
预期使用方式
以 CANopen CiA 305 LSS
Activate Bit Timing为例,后续可以采用:这样能够同时解决两个不同层面的问题:
为什么需要这个特性
这个需求最初来自 CANopen LSS runtime bitrate activation,但并不局限于 CANopen。
类似能力对于以下场景也有通用价值:
相比直接
HAL_CAN_DeInit()或完整 stop/restart CAN controller,一个专门的 TX flush / abort API 可以提供更明确、更小副作用的语义,同时保持 CAN framework 与具体硬件驱动之间的分层。计划
如果这个方向没有问题,我将按照上述方案先完成:
实现时会尽量控制改动范围,并优先通过
control command扩展,避免第一版直接修改struct rt_can_ops而影响所有现有 CAN driver。也欢迎对 API 命名、flush 语义以及 driver capability 分层方式提出建议。