RT-Thread论坛
直播中

江根磊

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

rtthread 报错”FPU active!” “SCB_CFSR_UFSR:0x100 UNALIGNED”的原因?

开发环境:
RT-Thread: v5.1.0
MCU: STM32F429
我在一个线程中向另一个线程发送消息队列,使用的是传结构体,然后就出现报错
FPU active!
usage fault:
SCB_CFSR_UFSR:0x100 UNALIGNED
代码如下

  • #define intercom_msg_data_size 63
  • typedef struct
  • {
  •     uint8_t cmd;
  •     uint8_t data[intercom_msg_data_size];
  • }Intercom_msg_t;

  • void Intercom_control(uint8_t cmd,uint8_t *data,uint8_t length)
  • {
  •     uint8_t i;
  •     Intercom_msg_t send_msg;
  •     rt_err_t ret=0;

  •     send_msg.cmd = cmd;
  •     for(i=0;imsg_queue_free = msg->next;

  •     rt_spin_unlock_irqrestore(&(mq->spinlock), level);

  •     /* the msg is the new tailer of list, the next shall be NULL */
  •     msg->next = RT_NULL;




回帖(1)

温暖镜头

2025-9-19 17:42:35

根据你提供的错误信息和代码,FPU active!SCB_CFSR_UFSR:0x100 UNALIGNED 报错的原因是非对齐内存访问(Unaligned Access)导致的异常。以下是详细分析和解决方案:




根本原因分析




  1. 非对齐访问错误 (0x100 UNALIGNED)



    • ARM Cortex-M系列(如STM32F429)要求某些数据类型(如 uint32_tfloat)在内存中必须按特定地址对齐(如4字节对齐)。

    • 当尝试从一个非对齐地址读取/写入这些数据时,会触发 UsageFault 异常。

    • 错误码 0x100 明确指示了非对齐访问问题。




  2. FPU激活状态 (FPU active!)



    • STM32F429自带硬件FPU(浮点单元)。

    • 如果代码中使用了浮点运算,FPU会自动激活。

    • 关键点:FPU操作要求浮点数据在内存中严格4字节对齐。如果消息队列传递的结构体包含 float/double 成员或结构体本身未对齐,会触发此错误。




  3. 你的代码问题



    • 你通过消息队列传递结构体 Intercom_msg_t,但未显式指定对齐方式。

    • 如果接收线程从消息队列读取结构体时,其内存地址不符合对齐要求(尤其是FPU相关数据),会触发异常。

    • 即使结构体当前没有浮点成员,如果未来添加或编译器插入填充字节导致偏移,也可能引发问题。






解决方案


1. 显式对齐结构体(推荐)


使用 RT_ALIGN 宏强制结构体4字节对齐:


   typedef struct {
       uint8_t cmd;
       uint8_t data;
   } RT_ALIGN(4) Intercom_msg_t; // 4字节对齐


  • RT_ALIGN(4) 确保结构体实例在内存中始终位于4字节对齐的地址。


2. 检查消息队列初始化


确保消息队列的每个消息大小是对齐后的结构体大小:


   #define MSG_QUEUE_SIZE 10 // 队列容量
   rt_mq_t mq_handle = rt_mq_create("mq_demo",
                                    sizeof(Intercom_msg_t), // 对齐后的大小
                                    MSG_QUEUE_SIZE,
                                    RT_IPC_FLAG_FIFO);


  • sizeof(Intercom_msg_t) 必须是4的倍数(如对齐后为4字节)。


3. 发送/接收时验证地址对齐


在发送和接收代码中检查指针是否对齐:


   // 发送端
   Intercom_msg_t send_msg;
   RT_ASSERT(((rt_uint32_t)&send_msg & 0x3) == 0); // 确保地址4字节对齐

   rt_mq_send(mq_handle, &send_msg, sizeof(Intercom_msg_t));

   // 接收端
   Intercom_msg_t recv_msg;
   RT_ASSERT(((rt_uint32_t)&recv_msg & 0x3) == 0); // 确保地址4字节对齐

   rt_mq_recv(mq_handle, &recv_msg, sizeof(Intercom_msg_t), RT_WAITING_FOREVER);

4. 检查FPU使用情况



  • 如果代码中使用了浮点数,确保所有浮点数据(包括结构体内的成员)都4字节对齐。

  • 在FPU初始化代码(如 SystemInit())中确认启用了FPU:
     #if defined(__FPU_USED) && (__FPU_USED == 1)
    SCB->CPACR |= (0xFUL << 20); // 启用FPU
    #endif


5. 排查其他潜在问题



  • 栈对齐:确保线程栈4字节对齐。在创建线程时指定对齐:
     rt_thread_create(..., RT_ALIGN(4), ...);

  • 编译器扩展:添加 __attribute__((aligned(4))) 到结构体定义(GCC):
     typedef struct {
         uint8_t cmd;
         uint8_t data;
    } __attribute__((aligned(4))) Intercom_msg_t;

  • 关闭严格对齐检查(不推荐)

    SCB->CCR 中禁用非对齐检查(可能导致性能下降):
     SCB->CCR &= ~SCB_CCR_UNALIGN_TRP_Msk; // 关闭非对齐检查




预防措施



  1. 统一对齐规则:项目中所有跨线程传递的结构体显式指定对齐(如 RT_ALIGN(4))。

  2. 避免混合数据类型:在消息结构体中慎用浮点数,或确保其位于对齐地址。

  3. 内存诊断:使用RT-Thread的 memtracehardfault 组件捕获非法访问。


通过这些步骤,可解决非对齐访问导致的 UNALIGNED 错误。重点在于确保结构体在内存中始终4字节对齐,尤其是涉及FPU操作时。

举报

更多回帖

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