RT-Thread论坛
直播中

打马过草原

10年用户 983经验值
擅长:可编程逻辑 电源/新能源
私信 关注
[问答]

ART PI FDCAN卡死在rt_device_write是哪里出了问题?


  • 使用 can_sample 代码

  • int can_sample(int argc, char *argv[])
  • {
  •     struct rt_can_msg msg = {0};
  •     rt_err_t res;
  •     rt_size_t  size;
  •     rt_thread_t thread;
  •     rt_kprintf("CAN_Samplen");
  •     char can_name[RT_NAME_MAX];

  •     if (argc == 2)
  •     {
  •         rt_strncpy(can_name, argv[1], RT_NAME_MAX);
  •     }
  •     else
  •     {
  •         rt_strncpy(can_name, CAN_DEV_NAME, RT_NAME_MAX);
  •     }
  •     /* 查找 CAN 设备 */
  •     can_dev = rt_device_find(can_name);
  •     if (!can_dev)
  •     {
  •         rt_kprintf("find %s failed!n", can_name);
  •         return RT_ERROR;
  •     }
  •     rt_kprintf("rt_sem_initn");
  •     /* 初始化 CAN 接收信号量 */
  •     rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);

  •     /* 以中断接收及发送方式打开 CAN 设备 */
  •     res = rt_device_open(can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
  •     RT_ASSERT(res == RT_EOK);
  •     res = rt_device_control(can_dev, RT_CAN_CMD_SET_MODE, (void *)RT_CAN_MODE_LOOPBACK);
  •     /* 创建数据接收线程 */
  •     rt_kprintf("rt_thread_createn");
  •     thread = rt_thread_create("can_rx", can_rx_thread, RT_NULL, 1024, 25, 10);
  •     if (thread != RT_NULL)
  •     {
  •         rt_thread_startup(thread);
  •     }
  •     else
  •     {
  •         rt_kprintf("create can_rx thread failed!n");
  •     }

  •     msg.id = 0x78;              /* ID 为 0x78 */
  •     msg.ide = RT_CAN_STDID;     /* 标准格式 */
  •     msg.rtr = RT_CAN_DTR;       /* 数据帧 */
  •     msg.len = 8;                /* 数据长度为 8 */
  •     /* 待发送的 8 字节数据 */
  •     msg.data[0] = 0x00;
  •     msg.data[1] = 0x11;
  •     msg.data[2] = 0x22;
  •     msg.data[3] = 0x33;
  •     msg.data[4] = 0x44;
  •     msg.data[5] = 0x55;
  •     msg.data[6] = 0x66;
  •     msg.data[7] = 0x77;
  •     /* 发送一帧 CAN 数据 */
  •     rt_kprintf("rt_device_writen");
  •     size = rt_device_write(can_dev, 0, &msg, sizeof(msg));
  •     if (size == 0)
  •     {
  •         rt_kprintf("can dev write data failed!n");
  •     }
  •     rt_kprintf("returnn");
  •     return res;
  • }


cubeMX设置

这里输入代码return 打不出来,说明死rt_device_write 上了
1 使用 fdcan1
2 GPIO 改为了PB8 和PB9
3 CAN 为 classic mode
4 打开了 FDCAN1 interrupt1和interrupt2
5 由于没有接外部CAN test,所以设置为internal LoopBack mode
还缺什么呢?


回帖(2)

王伟鹏

2025-9-11 16:44:38
有几个地方您希望能确认一下:


  • CAN 的外设的时钟源是多少?
  • CAN 波特率是多少?是在哪里一步步分频配置出来的?
  • internal LoopBack mode 是在哪里配置的?
  • drv_can.c 有做什么修改?                       
举报

感谢相遇

2025-9-15 17:49:11

针对ART PI FDCAN卡死在rt_device_write的问题,结合提供的can_sample代码片段,以下是可能的原因和解决方案:




问题原因分析




  1. 设备未正确打开



    • 未调用rt_device_open()打开设备,导致写操作阻塞。

    • 检查代码中是否有类似如下操作:
      rt_device_t dev = rt_device_find(can_name);
      if (rt_device_open(dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX) != RT_EOK) {
      rt_kprintf("Open device failed!n");
      return;
      }




  2. CAN设备配置错误



    • 波特率、模式(标准帧/扩展帧)配置不匹配。

    • 需在打开设备后配置参数:
      struct rt_can_config cfg = {
      .baud_rate = BAUD_RATE_500K,  // 确认与实际波特率一致
      .mode = RT_CAN_MODE_NORMAL    // 或RT_CAN_MODE_LISTEN
      };
      rt_device_control(dev, RT_CAN_CMD_CONFIG, &cfg);




  3. 发送缓冲池耗尽



    • CAN驱动内部发送缓冲池满时,rt_device_write会阻塞等待。

    • 原因:连续快速发送未处理发送完成标志。




  4. 硬件或驱动问题



    • FDCAN控制器未初始化(如时钟、引脚配置)。

    • STM32H7驱动drv_fdcan.c存在缺陷(如中断未正确处理)。




  5. 总线状态异常



    • CAN总线无终端电阻导致信号反射。

    • 其他节点未应答或总线短路。






解决方案


1. 检查设备初始化流程


   // 完整初始化示例
   rt_device_t dev = rt_device_find("fdcan1");
   RT_ASSERT(dev != RT_NULL);

   if (rt_device_open(dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX) != RT_EOK) {
       rt_kprintf("CAN device open failed!n");
       return -1;
   }

   // 配置波特率(必须与物理总线一致)
   struct rt_can_config cfg = {.baud_rate = 500000}; // 500kbps
   rt_device_control(dev, RT_DEVICE_CTRL_CONFIG, &cfg);

2. 添加发送超时机制



  • 避免无限阻塞:
     rt_uint32_t timeout = 100; // 超时时间(tick数)
    size = rt_device_write(dev, 0, &msg, sizeof(msg), timeout);
    if (size == 0) {
         rt_kprintf("Send timeout!n");
    }


3. 检查发送缓冲池状态



  • 在发送前查询空闲邮箱数量:
     rt_uint32_t free_mbox;
    rt_device_control(dev, RT_CAN_CMD_GET_STATUS, &free_mbox);
    if (free_mbox == 0) {
         rt_kprintf("No free TX mailbox!n");
         return;
    }


4. 验证CAN总线物理层



  • 确保CAN_H/CAN_L间连接120Ω终端电阻。

  • 用示波器检查总线波形是否正常。


5. 更新驱动程序



  • 确认使用的RT-Thread版本是否修复已知FDCAN问题(如GitHub提交记录)。

  • 检查drv_fdcan.c中:

    • 发送中断是否清除TX_EFLG寄存器标志。

    • 是否启用FDCAN时钟(__HAL_RCC_FDCAN_CLK_ENABLE())。





调试建议




  1. 打印错误日志


    rt_err_t err = rt_device_write(dev, ...);
    if (err != RT_EOK) {
       rt_kprintf("Write error: %dn", err);
    }



  2. 启用调试宏



    • rtconfig.h中打开CAN调试:
      #define RT_DEBUG_CAN




  3. 简化测试



    • 使用回环模式验证驱动:
      cfg.mode = RT_CAN_MODE_LOOPBACK; // 数据自发自收






通过逐步检查设备初始化、配置、发送流程及硬件状态,可定位问题根源。重点排查设备打开状态和驱动中断处理逻辑。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分