Skip to content

Conversation

@unnamed2
Copy link
Contributor

@unnamed2 unnamed2 commented Jun 2, 2025

修复CAN总线在出错时没能处理的问题

拉取/合并请求描述:(PR description)

[

为什么提交这份PR (why to submit this PR)

尝试解决CAN总线出现波动的情况下,can发送阻塞的问题。

你的解决方案是什么 (what is your solution)

在CAN错误中断发生BITPAD错误时,和ACK错误一样,检测发送完成状态。

请提供验证的bsp和config (provide the config and bsp)

  • BSP: 基于STM32F407VET6的自定义板子
  • .config:
  • action:

]

当前拉取/合并请求的状态 Intent for your PR

必须选择一项 Choose one (Mandatory):

  • 本拉取/合并请求是一个草稿版本 This PR is for a code-review and is intended to get feedback
  • 本拉取/合并请求是一个成熟版本 This PR is mature, and ready to be integrated into the repo

代码质量 Code Quality:

我在这个拉取/合并请求中已经考虑了 As part of this pull request, I've considered the following:

  • 已经仔细查看过代码改动的对比 Already check the difference between PR and old code
  • 代码风格正确,包括缩进空格,命名及其他风格 Style guide is adhered to, including spacing, naming and other styles
  • 没有垃圾代码,代码尽量精简,不包含#if 0代码,不包含已经被注释了的代码 All redundant code is removed and cleaned up
  • 所有变更均有原因及合理的,并且不会影响到其他软件组件代码或BSP All modifications are justified and not affect other components or BSP
  • 对难懂代码均提供对应的注释 I've commented appropriately where code is tricky
  • 代码是高质量的 Code in this PR is of high quality
  • 已经使用formatting 等源码格式化工具确保格式符合RT-Thread代码规范 This PR complies with RT-Thread code specification
  • 如果是新增bsp, 已经添加ci检查到.github/workflows/bsp_buildings.yml 详细请参考链接BSP自查

修复CAN总线在出错时没能处理的问题
@github-actions github-actions bot added BSP: STM32 BSP related with ST/STM32 BSP labels Jun 2, 2025
@CLAassistant
Copy link

CLAassistant commented Jun 2, 2025

CLA assistant check
All committers have signed the CLA.

@wdfk-prog
Copy link
Contributor

wdfk-prog commented Jun 4, 2025

#10341

所以是测试这么修改成功解决问题了是吗?

有条件可以测试一下其他SCE中断触发的错误是否也有这个情况(^▽^)

@unnamed2
Copy link
Contributor Author

unnamed2 commented Jun 4, 2025

void CAN1_SCE_IRQHandler(void)
{
rt_uint32_t errtype;
CAN_HandleTypeDef *hcan;
hcan = &drv_can1.CanHandle;
errtype = hcan->Instance->ESR;
rt_interrupt_enter();
HAL_CAN_IRQHandler(hcan);
switch ((errtype & 0x70) >> 4)

我使用最新版本进行一些测试确实没问题,但是我仍然不能保证他的正确性
这个是我之前使用的版本,这里面有一个不同的地方是他调用了HAL_CAN_IRQHandler, 在这个函数中会清除RQCP标志。这导致在我的版本中如果SCE中断没有处理,就会导致卡死的问题。
最新的版本中没有调用这个函数,这是不是意味着,不在SCE中断中处理任何发送错误也能避免这样的问题,所以删掉这些东西才是正确的?
我看之前的版本中考虑了自动重发的影响,这里我还没有测试过。

@wdfk-prog
Copy link
Contributor

wdfk-prog commented Jun 5, 2025

void CAN1_SCE_IRQHandler(void)
{
rt_uint32_t errtype;
CAN_HandleTypeDef *hcan;
hcan = &drv_can1.CanHandle;
errtype = hcan->Instance->ESR;
rt_interrupt_enter();
HAL_CAN_IRQHandler(hcan);
switch ((errtype & 0x70) >> 4)

我使用最新版本进行一些测试确实没问题,但是我仍然不能保证他的正确性
这个是我之前使用的版本,这里面有一个不同的地方是他调用了HAL_CAN_IRQHandler, 在这个函数中会清除RQCP标志。这导致在我的版本中如果SCE中断没有处理,就会导致卡死的问题。
最新的版本中没有调用这个函数,这是不是意味着,不在SCE中断中处理任何发送错误也能避免这样的问题,所以删掉这些东西才是正确的?
我看之前的版本中考虑了自动重发的影响,这里我还没有测试过。

不在SCE中断中处理任何发送错误也能避免这样的问题,并不行.发送错误了不会走到TX中断里触发完成量执行发送线程的唤醒.
自动重发的影响,这一块只是个配置问题.也是会进入这个SCE中断的,只是不需要由驱动自行完成错误处理,而是32底层自行执行重发尝试.

  • 或许switch里的错误都应该调用_can_check_tx_complete进行处理.
switch ((errtype & 0x70) >> 4)
{
}

@unnamed2
Copy link
Contributor Author

unnamed2 commented Jun 5, 2025

在这里写了一个简单的程序来实验

void CAN2_SCE_IRQHandler(void) {
  CAN_IRQ_Handler(&hcan2, "CAN2_SCE_IRQHandler");

  // HAL_CAN_IRQHandler(&hcan2);
  
  __HAL_CAN_CLEAR_FLAG(&hcan2, CAN_FLAG_ERRI); 
  CLEAR_BIT(hcan2.Instance->ESR, CAN_ESR_LEC);
}

void CAN2_TX_IRQHandler(void) {
  CAN_IRQ_Handler(&hcan2, "CAN2_TX_IRQHandler");
  // HAL_CAN_IRQHandler(&hcan2);
  if(__HAL_CAN_GET_FLAG(&hcan2, CAN_FLAG_RQCP0)) {
    __HAL_CAN_CLEAR_FLAG(&hcan2, CAN_FLAG_RQCP0);
  }
  
  if(__HAL_CAN_GET_FLAG(&hcan2, CAN_FLAG_RQCP1)) {
    __HAL_CAN_CLEAR_FLAG(&hcan2, CAN_FLAG_RQCP1);
  }

  if(__HAL_CAN_GET_FLAG(&hcan2, CAN_FLAG_RQCP2)) {
    __HAL_CAN_CLEAR_FLAG(&hcan2, CAN_FLAG_RQCP2);
  }
}

其中 CAN_IRQ_Handler 会输出寄存器状态以及中断函数名

void CAN_IRQ_Handler(CAN_HandleTypeDef *hcan, const char *irq_name) {

  struct CANRegisters reg;

  __disable_irq(); 
  reg.MCR = hcan->Instance->MCR;
  reg.MSR = hcan->Instance->MSR;
  reg.TSR = hcan->Instance->TSR;
  reg.RF0R = hcan->Instance->RF0R;
  reg.RF1R = hcan->Instance->RF1R;
  reg.IER = hcan->Instance->IER;
  reg.ESR = hcan->Instance->ESR;
  reg.BTR = hcan->Instance->BTR;

  if (Status_Buffer_Index < 128) {
    // Store the IRQ name and registers in the buffer
    strncpy(Status_Buffer[Status_Buffer_Index].IRQ_name, irq_name,
            sizeof(Status_Buffer[Status_Buffer_Index].IRQ_name) - 1);
    Status_Buffer[Status_Buffer_Index].regs = reg;
    Status_Buffer_Index++;
  }

  __enable_irq(); // Re-enable interrupts
}

状态被保存之后,main函数中会进行输出。

CAN总线发送失败之后,会连续触发SCE和TX中断:

IRQ: CAN2_SCE_IRQHandler
MCR: 0x00010050
MSR: 0x00000C0C
TSR: 0x1C000009
RF0R: 0x00000000
RF1R: 0x00000000
IER: 0x00008C13
ESR: 0x00080030
BTR: 0x00380005

IRQ: CAN2_TX_IRQHandler
MCR: 0x00010050
MSR: 0x00000008
TSR: 0x1C000009
RF0R: 0x00000000
RF1R: 0x00000000
IER: 0x00008C13
ESR: 0x00080000
BTR: 0x00380005

其中TSR寄存器的0x1C000009意味着CAN_TSR_RQCP0 | CAN_TSR_TERR0。
对于产生的ACK错误,如果SCE中断中处理并清掉了CAN_TSR_RQCP0标志,那TX中确实就无法检测到RQCP0标记来执行rt_hw_can_isr了。

SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP0);

自动重发模式经过测试,在成功之前会不停的触发SCE中断,直到发送成功最后产生TX中断为止。
此时SCE中断中 TSR的值为0x19000008,意味着CAN_TSR_TERR0,但是没有CAN_TSR_RQCP0 。

IRQ: CAN2_SCE_IRQHandler
MCR: 0x00010040
MSR: 0x00000C0C
TSR: 0x19000008
RF0R: 0x00000000
RF1R: 0x00000000
IER: 0x00008C13
ESR: 0x00800033
BTR: 0x00380005

这样看感觉在SCE中断中直接检查发送完成好像是可以的,并且HAL好像就是这么做的。直接在switch之前调用_can_check_tx_complete就行了

@wdfk-prog
Copy link
Contributor

wdfk-prog commented Jun 15, 2025

  • 可以是做成直接在switch之后调用_can_check_tx_complete

@unnamed2
Copy link
Contributor Author

  • LGTM

    • 另外可以是做成直接在switch之后调用_can_check_tx_complete

抱歉回复晚了,最近在做其他的事情,没来得及调整这个代码。
我今天或者明天试一下测试新的修改,然后再新提交一个PR

@github-actions
Copy link

github-actions bot commented Jun 22, 2025

📌 Code Review Assignment

🏷️ Tag: bsp_stm32

Path: bsp/stm32
Reviewers: @wdfk-prog

Changed Files (Click to expand)
  • bsp/stm32/libraries/HAL_Drivers/drivers/drv_can.c

📊 Current Review Status (Last Updated: 2025-07-01 03:44 UTC)


📝 Review Instructions

  1. 维护者可以通过单击此处来刷新审查状态: 🔄 刷新状态
    Maintainers can refresh the review status by clicking here: 🔄 Refresh Status

  2. 确认审核通过后评论 LGTM/lgtm
    Comment LGTM/lgtm after confirming approval

  3. PR合并前需至少一位维护者确认
    PR must be confirmed by at least one maintainer before merging

ℹ️ 刷新CI状态操作需要具备仓库写入权限。
ℹ️ Refresh CI status operation requires repository Write permission.

@unnamed2
Copy link
Contributor Author

  • LGTM

    • 另外可以是做成直接在switch之后调用_can_check_tx_complete

我尝试多修改了一些地方;这些修改在我们的设备上测试,没有发现问题。

在检查TX的RQCP标志位时,可能出现多个CAN发送完成的情况,因此去掉了'else',一次性检查了RQCP0-RQCP2的值(HAL库也是一次检查了三个中断)

因为没有调用HAL_CAN_IRQHandler, 因此HAL_CAN_ErrorCallback永远不会执行。

Copy link
Contributor

@wdfk-prog wdfk-prog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@wdfk-prog
Copy link
Contributor

@Rbb666 帮忙看一下^_^

@Rbb666
Copy link
Member

Rbb666 commented Jul 1, 2025

@unnamed2 这份PR的标题麻烦修改下吧,直观体现下修复了什么问题

@unnamed2 unnamed2 changed the title Update drv_can.c 修复stm32 CAN的SCE中断中只在ACK错误检查发送完成导致小概率出错的问题 Jul 1, 2025
@Rbb666 Rbb666 merged commit a1e8651 into RT-Thread:master Jul 2, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

BSP: STM32 BSP related with ST/STM32 BSP

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants