Skip to content

[Feature][CAN] 支持 TX Full Flush 与 Hardware Abort 能力 #11759

Description

@wdfk-prog

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 的能力,例如可以使用:

HAL_CAN_AbortTxRequest()

或者 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 请求继续进入发送路径。

例如可以考虑:

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_TX

STM32 bxCAN 可以实现为:

HAL_CAN_AbortTxRequest()

该接口只负责取消已经进入 CAN controller mailbox 的 TX request,不负责操作 framework software queue。

其他不支持 hardware abort 的 CAN driver 可以明确返回:

-RT_ENOSYS

而不是静默成功。

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()

其中建议明确区分:

RT_CAN_CMD_ABORT_TX

仅表示 driver 层的 hardware pending TX abort;

而:

RT_CAN_CMD_FLUSH_TX

表示 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 分层方式提出建议。

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions