RT-Thread论坛
直播中

贾飞小

8年用户 1851经验值
私信 关注
[问答]

ART-PI 使用CAN硬件过滤器打开后接收中断异常的原因?

开启硬件过滤器后,出现如下断言异常,不开启硬件过滤器,接收数据正常

  • (hdr < can->config.maxhdr && hdr >= 0) assertion failed at function:rt_hw_can_isr, line number:835



  • #include
  • #include
  • #define DBG_TAG "user_can"
  • #define DBG_LVL DBG_LOG


  • #define CAN_DEV_NAME       "fdcan2"      /* CAN 设备名称 */

  • static struct rt_semaphore rx_sem;     /* 用于接收消息的信号量 */
  • static rt_device_t can_dev;            /* CAN 设备句柄 */

  • /* 接收数据回调函数 */
  • static rt_err_t can_rx_call(rt_device_t dev, rt_size_t size)
  • {
  •     /* CAN 接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
  •     rt_sem_release(&rx_sem);

  •     return RT_EOK;
  • }

  • static void can_rx_thread(void *parameter)
  • {
  •     int i;
  •     rt_err_t res;
  •     struct rt_can_msg rxmsg = {0};

  •     /* 设置接收回调函数 */
  •     rt_device_set_rx_indicate(can_dev, can_rx_call);

  • #ifdef RT_CAN_USING_HDR
  •     struct rt_can_filter_item items[5] =
  •     {
  •         RT_CAN_FILTER_ITEM_INIT(0x100, 0, 0, 0, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x100~0x1ff,hdr为-1,设置默认过滤表 */
  •         RT_CAN_FILTER_ITEM_INIT(0x300, 0, 0, 0, 0x700, RT_NULL, RT_NULL), /* std,match ID:0x300~0x3ff,hdr为-1 */
  •         RT_CAN_FILTER_ITEM_INIT(0x211, 0, 0, 0, 0x7ff, RT_NULL, RT_NULL), /* std,match ID:0x211,hdr为-1 */
  •         RT_CAN_FILTER_STD_INIT(0x486, RT_NULL, RT_NULL),                  /* std,match ID:0x486,hdr为-1 */
  •         {0x555, 0, 0, 0, 0x7ff, 7,}                                       /* std,match ID:0x555,hdr为7,指定设置7号过滤表 */
  •     };
  •     struct rt_can_filter_config cfg = {5, 1, items}; /* 一共有5个过滤表 */
  •     /* 设置硬件过滤表 */
  •     res = rt_device_control(can_dev, RT_CAN_CMD_SET_FILTER, &cfg);
  •     RT_ASSERT(res == RT_EOK);
  • #endif

  •     while (1)
  •     {
  •         /* hdr值为-1,表示直接从uselist链表读取数据 */
  •         rxmsg.hdr = -1;
  •         /* 阻塞等待接收信号量 */
  •         rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
  •         /* 从CAN读取一帧数据 */
  •         rt_device_read(can_dev, 0, &rxmsg, sizeof(rxmsg));
  •         /* 打印数据ID及内容 */
  •         rt_kprintf("ID:%x  ", rxmsg.id);
  •         for (i = 0; i < 8; i++)
  •         {
  •             rt_kprintf("%2x ", rxmsg.data);
  •         }

  •         rt_kprintf("n");
  •     }
  • }

  • int can2_sample(int argc, char *argv[])
  • {
  •     struct rt_can_msg msg = {0};
  •     rt_err_t res;
  •     rt_size_t  size;
  •     rt_thread_t thread;
  •     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_dev = rt_device_find(can_name);
  •     if (!can_dev)
  •     {
  •         rt_kprintf("find %s failed!n", can_name);
  •         return RT_ERROR;
  •     }

  •     /* 初始化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);

  •     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数据 */
  •     size = rt_device_write(can_dev, 0, &msg, sizeof(msg));
  •     if (size == 0)
  •     {
  •         rt_kprintf("can dev write data failed!n");
  •     }

  •     return res;
  • }
  • /* 导出到 msh 命令列表中 */
  • MSH_CMD_EXPORT(can2_sample, can2 device sample);

回帖(1)

wufan931111

2025-9-12 18:20:07

原因分析:


ART-PI CAN驱动(fdcan2)的硬件过滤器配置不当触发了RT-Thread的断言异常。断言失败的位置在rt_hw_can_isr第835行,核心条件是:


(hdr < can->config.maxhdr && hdr >= 0)  // 要求 hdr 在合法范围内

当启用硬件过滤器后,驱动在中断中检索消息头索引(hdr)时,获得了无效索引值,原因如下:




根本原因:




  1. 硬件过滤器配置冲突

    使能硬件过滤器时,驱动要求为每个接收的CAN消息分配一个有效的"消息头"(Header),而:



    • maxhdr 值过小(如配置为0或负数)

    • 过滤器数量超出硬件限制(未正确设置接收FIFO深度)

    • 过滤器未绑定到有效的Rx FIFO




  2. 驱动程序初始化缺陷

    STM32的FDCAN驱动需显式配置Rx FIFO深度,而过滤器必须关联到特定FIFO。未正确初始化会导致中断中访问非法索引。






解决方案:


步骤1:初始化时显式设置最大消息头数


在打开设备前,配置CAN的接收缓冲深度:


/* 在 rt_device_open() 前添加 */
struct rt_can_config_item cfg = {
    .maxhdr = 8,          // 典型值:8-64(根据硬件能力调整)
    .mode   = RT_CAN_MODE_NORMAL,
    .ticks  = 50,         // 接收超时ticks
};
rt_device_control(can_dev, RT_CAN_CMD_SET_BAUD, (void*)CAN2K1MBPS); // 设置波特率
rt_device_control(can_dev, RT_CAN_CMD_SET_MODE, (void*)RT_CAN_MODE_NORMAL);
rt_device_control(can_dev, RT_CAN_CMD_SET_MAX_HDR, &cfg); // 关键配置

步骤2:正确初始化硬件过滤器


过滤器必须关联到Rx FIFO:


struct rt_can_filter_config filter = {
    .items = {
        { .id = 0x123, .mode = RT_CAN_FILTER_STD }, // 示例:标准ID过滤器
    },
    .count = 1,  // 过滤器数量
    .fifo  = RT_CAN_FIFO0 // 绑定到FIFO0
};
rt_device_control(can_dev, RT_CAN_CMD_SET_FILTER, &filter); // 启用硬件过滤

步骤3:检查硬件FIFO深度(关键!)


修改驱动源码 drv_fdcan.c


// 在 FDCAN 初始化函数中找到 hw_fdcan_init() 函数
static int hw_fdcan_init(struct rt_can_device *can, const char *name)
{
    ...
    can->config.maxhdr = 8;  // 确保 maxhdr > 0 且小于硬件FIFO容量
    FDCAN_CONFIG->RxFIFO0Size = 8; // 设置Rx FIFO深度为8(匹配maxhdr)
    ...
}

步骤4:更新RT-Thread驱动(如问题仍存在)



  1. 升级到 RT-Thread v4.1.0+(修复了FDCAN驱动问题)

  2. 或手动修补驱动:修改rt_hw_can_isr()函数:
    // 修改断言前的索引检查逻辑:
    // 文件: drv_fdcan.c (约835行)
    if (hdr >= can->config.maxhdr || hdr < 0) {
    rt_kprintf("Invalid hdr=%d! maxhdr=%dn", hdr, can->config.maxhdr);
    break;  // 跳过无效消息
    }




最终验证代码:


#include 
#define CAN_DEV_NAME "fdcan2"

static struct rt_semaphore rx_sem;
static rt_device_t can_dev;

static rt_err_t rx_callback(rt_device_t dev, rt_size_t size)
{
    rt_sem_release(&rx_sem);
    return RT_EOK;
}

int can_sample(void)
{
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);

    can_dev = rt_device_find(CAN_DEV_NAME);
    if (!can_dev) {
        rt_kprintf("CAN device not found!n");
        return -RT_ERROR;
    }

    /* 步骤1&2:配置波特率、模式、缓冲区、过滤器 */
    struct rt_can_config_item cfg = {
        .maxhdr = 8,
        .mode   = RT_CAN_MODE_NORMAL,
        .ticks  = 50
    };
    rt_device_control(can_dev, RT_CAN_CMD_SET_BAUD, (void*)CAN2K1MBPS);
    rt_device_control(can_dev, RT_CAN_CMD_SET_MAX_HDR, &cfg); // 关键!

    struct rt_can_filter_config filter = {
        .items = {{ .id = 0x100, .mode = RT_CAN_FILTER_STD }},
        .count = 1,
        .fifo  = RT_CAN_FIFO0
    };
    rt_device_control(can_dev, RT_CAN_CMD_SET_FILTER, &filter);

    /* 打开设备 */
    rt_device_open(can_dev, RT_DEVICE_OFLAG_RDWR);
    rt_device_set_rx_indicate(can_dev, rx_callback);

    return RT_EOK;
}


注意:  



  • 确保 maxhdr 值 ≤ 硬件FIFO深度(查看MCU手册确认FDCAN FIFO大小)  

  • 过滤器数量不可超过硬件上限(ART-PI的STM32H750支持最多28个过滤器)  

  • 若仍有异常,检查RT-Thread的FDCAN驱动版本是否有已知问题


举报

更多回帖

×
20
完善资料,
赚取积分