You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于CMSIS-OS V2/FreeRTOS的STM32队列传结构体触发HardFault问题

问题:FreeRTOS/CMSIS-OS V2队列传递结构体触发HardFault错误

我基于STM32CubeMX生成的CMSIS-OS V2/FreeRTOS框架开发,在任务间通过队列传递结构体时出现HardFault错误。调试发现,执行osMessageQueuePut相关代码时会跳转到HardFault错误处理函数。

任务代码

void pmt_task_RX_uart_func(void *argument)
{
  /* USER CODE BEGIN pmt_task_RX_uart_func */
    char msg[60];
    Fuente_MPPC_C11204 Pmt_AUX;
    osStatus_t eventPMT_buffer;
  /* Infinite loop */
  for(;;)
  {
        eventPMT_buffer = osMessageQueueGet(PMT_Buffer_QueueHandle, &msg, NULL, osWaitForever);   // 等待消息
        if(eventPMT_buffer==osOK){
            // 消息已从队列取出
            osStatus_t eventPMT_struct = osMessageQueueGet(PMT_Struct_QueueAUXHandle, &Pmt_AUX, NULL, osWaitForever);
            if(eventPMT_struct==osOK){
                // 结构体已从队列取出
                strcpy((char*) Pmt_AUX.cmd_recieved_buffer, msg);
                Pmt_AUX = hps_recivecmd(&Pmt_AUX);
                osStatus_t eventSen = osMessageQueuePut(PMT_RX_QueueHandle, &Pmt_AUX, 0U, osWaitForever);
                if(eventPMT_struct==osOK){
                    // 消息已入队
                    
                    osThreadYield(); 
                } else if(eventPMT_struct==osErrorResource){
                // 队列已满
                } else if(eventPMT_struct==osErrorTimeout){
                // 消息入队超时
                }   else if(eventPMT_struct==osErrorParameter){
                // 参数mq_id为空或无效,ISR中指定了非零超时时间
                }
            } else if(eventPMT_struct==osErrorResource){
                // 队列已满
            } else if(eventPMT_struct==osErrorTimeout){
                // 消息入队超时
            }   else if(eventPMT_struct==osErrorParameter){
                // 参数mq_id为空或无效,ISR中指定了非零超时时间
            }
        } else if(eventPMT_buffer==osErrorResource){
            // 队列已满
        } else if(eventPMT_buffer==osErrorTimeout){
            // 消息入队超时
        }   else if(eventPMT_buffer==osErrorParameter){
            // 参数mq_id为空或无效,ISR中指定了非零超时时间
        }
  }
  /* USER CODE END pmt_task_RX_uart_func */
}

触发错误的代码段

调试确认,执行以下代码时触发HardFault:

osStatus_t eventSen = osMessageQueuePut(PMT_RX_QueueHandle, &Pmt_AUX, 0U, osWaitForever);
if(eventPMT_struct==osOK){
    // 消息已入队
    
    osThreadYield(); 
} 

结构体定义

/*Typedef start*/
typedef enum
{
    HST = 0,
    HRT,
    HPO,
    HGS,
    HGV,
    HGC,
    HGT,
    HFI,
    HGN,
    HOF,
    HON,
    HRE,
    HCM,
    HSC,
    HRC,
    HBV
}hps_cmd_t;


typedef struct Fuente_MPPC_C11204{
    
    UART_HandleTypeDef * uart;
    uint8_t cmd_recieved_buffer[60];
    uint8_t buffer_PMT_INDEX;
    char data2send[32];
    hps_cmd_t comSend;      // 发送的命令(hps_cmd_t格式)
    char cmdAwait[5];       // 等待接收的命令
    uint8_t statusUart;     // 命令响应接收状态:0成功,1失败
    char error[5];              // 电源错误信息
    
    char secondCoefT1[5];   // 温度系数
    char secondCoefT2[5];   //
    char FirstCoefT1[5];    //
    char FirstCoefT2[5];    //
    char RefVoltage[5];     // 电源基准电压Vb
    char RefTemp[5];            // 电源基准温度Tb
    
    char status[5];             // 电源状态
    char OutVoltage[5];     // 输出电压
    char OutCurrent[5];     // 输出电流
    char MPPCTemp[5];           // 电源温度
    
    char deviceName[17];    // 电源设备名称
    char Version[17];           // 版本号
    char BuildDate[12];     // 构建日期
    char SerialNum[17];     // 序列号
    
    uint8_t mode;                           // 温度补偿模式:启用/禁用
    char FunctionSettings[5];   // 电源功能设置

}Fuente_MPPC_C11204;

队列创建代码

comman_tQueueHandle = osMessageQueueNew (1, sizeof(command_t), &comman_tQueue_attributes);

/* 创建PMT_Struct_Queue */
PMT_Struct_QueueHandle = osMessageQueueNew (1, sizeof(Fuente_MPPC_C11204), &PMT_Struct_Queue_attributes);

/* 创建PMT_Struct_QueueAUX */
PMT_Struct_QueueAUXHandle = osMessageQueueNew (1, sizeof(Fuente_MPPC_C11204), &PMT_Struct_QueueAUX_attributes);

/* 创建PMT_RX_Queue */
PMT_RX_QueueHandle = osMessageQueueNew (1, sizeof(Fuente_MPPC_C11204), &PMT_RX_Queue_attributes);

TxRaspBuffQueueHandle = osMessageQueueNew (1, sizeof(uint8_t[100]), &TxRaspBuffQueue_attributes);

/* 创建RxRaspBuffQueue */
RxRaspBuffQueueHandle = osMessageQueueNew (1, sizeof(uint8_t[100]), &RxRaspBuffQueue_attributes);

/* 创建PMT_Buffer_Queue */
PMT_Buffer_QueueHandle = osMessageQueueNew (1, sizeof(uint8_t[100]), &PMT_Buffer_Queue_attributes);

环境信息

所有任务优先级相同,栈大小均为500字(即2000字节)。我怀疑问题与队列或栈大小有关,但未找到具体原因,希望得到排查方向与解决方案。


排查方向与解决方案

  1. 修复变量判断逻辑错误
    代码中osMessageQueuePut执行后,错误地使用eventPMT_struct(之前osMessageQueueGet的返回值)来判断入队结果,应该使用新定义的eventSen。这个逻辑错误可能导致后续分支执行异常,甚至访问非法内存触发HardFault。修正后的代码:

    osStatus_t eventSen = osMessageQueuePut(PMT_RX_QueueHandle, &Pmt_AUX, 0U, osWaitForever);
    if(eventSen==osOK){
        // 消息已入队
        osThreadYield(); 
    }
    
  2. 检查任务栈溢出
    虽然任务栈配置为2000字节,但仍需确认是否存在栈溢出情况:

    • 临时增大任务栈至3000字节(750字),测试是否还会触发HardFault
    • 调用FreeRTOS API uxTaskGetStackHighWaterMark(pmt_task_RX_uart_Handle)获取任务栈的剩余空间最小值,判断是否接近栈极限
  3. 验证队列句柄有效性
    确认PMT_RX_QueueHandle是否被正确初始化,未被意外篡改。可以在osMessageQueuePut前添加断言检查:

    #include <assert.h>
    // ...
    assert(PMT_RX_QueueHandle != NULL);
    osStatus_t eventSen = osMessageQueuePut(PMT_RX_QueueHandle, &Pmt_AUX, 0U, osWaitForever);
    
  4. 排查hps_recivecmd函数的内存操作
    检查hps_recivecmd函数是否存在非法内存访问:比如越界修改结构体成员、返回无效的结构体实例等。可以单步调试该函数,确认结构体Pmt_AUX在执行前后的内存布局是否正常。

  5. 处理内存对齐问题
    ARM Cortex-M架构对多字节数据类型有对齐要求,若结构体存在对齐异常可能导致HardFault。可以强制结构体按4字节对齐:

    typedef struct __attribute__((aligned(4))) Fuente_MPPC_C11204{
        // 原有结构体成员
    }Fuente_MPPC_C11204;
    

内容的提问来源于stack exchange,提问作者Ignacio Islas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 11:12:00