RT1052 rtthread 报错"FPU active!" "UNALIGNED"

RT1052rtthread浮点数对齐问题

RT1052 rtthread 报错"FPU active!" “UNALIGNED”

问题
RT1052 rtthread 报错"FPU active!" “UNALIGNED”

开发环境
RT-Thread: v4.0.2(master)
SOC: i.MX RT1050
Board: 野火 RT1052

问题背景
我创建了一个线程去解析UDP数据, 而数据形式是我定义好的一个结构体的形式, 我使用结构体指针去取对应的值, 取前面的值都可以, 但取到float类型的成员时, 程序崩溃, 报如下错误:
FPU active 错误
使用到的结构体

typedef struct
{
    unsigned char protocol_flag;
    unsigned char protocol_version;
    unsigned char direction;
    unsigned char cmd;
    unsigned int len;
} UdpProtocolHead;

typedef struct
{
    UdpProtocolHead head;
    unsigned int data1;
    unsigned int data2;
    unsigned int data3;
    unsigned int data4;
    float data5;
    float data6;
} UdpProtocolData;

问题代码

int8_t handle_data_tophalf(uint8_t* data, uint32_t len, struct sockaddr_in* client_addr){
    UdpProtocolData* data = (UdpProtocolData*)data;
    
    uint8_t* p = (uint8_t*)&data->data5;
    printf("data5: %x %x %x %x\r\n", p[0], p[1], p[2], p[3]);
    printf("data5: %f\r\n", data->data5);
    p = (uint8_t*)&data->fy; 
    printf("data6: %x %x %x %x\r\n", p[0], p[1], p[2], p[3]);
    printf("data6: %f\r\n", data->data6);
}

问题自测
我在main中编写了自测代码来模拟现场, 运行正常, 代码如下:

char data2[] = {0xff, 0x01, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x20, 0x2d, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x3f};
uint8_t* p2 = rt_malloc(sizeof(data2));
memcpy(p2, data2, sizeof(data2));
UdpProtocolData* pdata = (UdpProtocolData*)p2;
printf("head: %x %x %x %x %d\r\n", pdata->head.protocol_flag, pdata->head.protocol_version, pdata->head.direction, pdata->head.cmd, pdata->head.len);
printf("head: %x %x %x %x\r\n", pdata->data_type, pdata->data_index, pdata->timestamp_s, pdata->timestamp_ns);
printf("data: %f %f\r\n", pdata->fy, pdata->fx);

运行结果如下
问题自测结果

解决办法

我首先将问题发布到了RT-Thread官方论坛上寻求大家的帮助, 等待了一会, 官方大牛给了回复

类型强转必然出错,还要留意对齐和填充问题。
data地址是多少?
data->data6 地址多少?
float 要求地址对齐到4字节。

这些给了我思路, 然后进行实验检测. 发现

全局变量定义的是 uint32_t 的数据类型, 而该数组地址非四字节对齐, 在使用中强转为结构体指针, 再引用float成员导致字节未对齐问题, 打印查看到 float成员地址也非四字节对齐. 同时又产生了新的疑问: int 类型为什么没有出错, 而float却出错了呢? 是float有什么特殊要求吗?

这里也给我提了一个醒, RT-Thread 报错"FPU active"或"UNALIGNED" 一般都是字节对齐问题.
同时, 我也有遇到过空地址引用成员, 导致"UNALIGNED"错误

原贴地址:
RT1052 rtthread 报错"FPU active!" “UNALIGNED” 原贴
相关文章地址:
单片机开发重点-字节对齐问题


补充"FPU active"代码跟踪

void rt_hw_hard_fault_exception(struct exception_info *exception_info)
{
    ...//省略

    if (exception_info->exc_return & (1 << 2))
    {
        rt_kprintf("hard fault on thread: %s\r\n\r\n", rt_thread_self()->name);

#ifdef RT_USING_FINSH
        list_thread();
#endif
    }
    else
    {
        rt_kprintf("hard fault on handler\r\n\r\n");
    }

    if ( (exception_info->exc_return & 0x10) == 0)
    {
        rt_kprintf("FPU active!\r\n");
    }

#ifdef RT_USING_FINSH
    hard_fault_track();
#endif /* RT_USING_FINSH */

    while (1);
}
HardFault_Handler    PROC
MemManage_Handler

    ; get current context
    TST     lr, #0x04               ; if(!EXC_RETURN[2])
    ITE     EQ
    MRSEQ   r0, msp                 ; [2]=0 ==> Z=1, get fault context from handler.
    MRSNE   r0, psp                 ; [2]=1 ==> Z=0, get fault context from thread.

    STMFD   r0!, {r4 - r11}         ; push r4 - r11 register
    IF      {FPU} != "SoftVFP"
    STMFD   r0!, {lr}               ; push dummy for flag
    ENDIF
    STMFD   r0!, {lr}               ; push exec_return register

    TST     lr, #0x04               ; if(!EXC_RETURN[2])
    ITE     EQ
    MSREQ   msp, r0                 ; [2]=0 ==> Z=1, update stack pointer to MSP.
    MSRNE   psp, r0                 ; [2]=1 ==> Z=0, update stack pointer to PSP.

    PUSH    {lr}
    BL      rt_hw_hard_fault_exception
<think>好的,用户现在的问题是STM32在RT-Thread环境下,由于FPU active导致Bus Fault的可能原因及解决方法。我需要结合之前的对话内容和用户提供的站内引用来分析。 首先,回顾之前的对话,用户之前遇到了开启定时器后程序进入死循环的问题,主要原因是中断服务函数缺失、开发环境冲突或硬件配置错误。现在的新问题涉及到FPU(浮点单元)激活导致的Bus Fault,这属于硬件异常的一种。需要从FPU配置、编译器设置、堆栈对齐、中断处理等方面考虑。 用户提供的引用[1]中提到,缺少头文件导致初始化参数缺失,从而引发硬件错误。这可能提示需要检查FPU相关的头文件或配置是否正确定义。另外,栈空间不足也可能导致问题,用户之前通过增加主线程栈空间解决了部分问题,所以可能需要考虑FPU使用是否增加了栈的使用量。 引用[2]提到了外部中断的配置,虽然不直接相关,但中断配置错误可能导致异常,需要确认FPU相关的中断或异常处理是否正确设置。 接下来,用户现在的问题可能的原因包括: 1. 编译器未正确启用FPU支持,导致指令无法识别。 2. 上下文切换时未保存/恢复FPU寄存器,导致状态丢失。 3. 堆栈对齐不符合FPU要求(如8字节对齐)。 4. 中断服务函数中使用了FPU指令但未正确保存状态。 5. 内存访问错误,如未对齐访问触发Bus Fault。 解决方法可能涉及检查编译器选项,确保启用FPU;修改RT-Thread的上下文切换代码以处理FPU寄存器;调整堆栈对齐设置;在中断中使用FPU时保存相关寄存器;检查代码中的内存访问是否合规。 同时,需要参考RT-Thread的文档或社区经验,确认在启用FPU时的必要配置步骤。例如,在rtconfig.h中定义相关的宏,或在链接脚本中确保堆栈对齐。此外,调试方法如查看SCB寄存器、使用HardFault诊断工具等也是关键步骤。 最后,用户可能需要具体的代码示例和配置步骤,比如如何修改启动文件、编译器选项,以及如何调整线程栈大小和对齐方式。同时,生成的相关问题需要围绕FPU配置、Bus Fault调试、RT-Thread的FPU支持等方面展开。</think>### STM32在RT-Thread环境下FPU激活导致Bus Fault的原因及解决方案 #### 一、核心原因分析 1. **FPU未正确初始化** - 未在编译选项中启用FPU支持(需添加`-mfloat-abi=hard -mfpu=fpv4-sp-d16`编译参数)[^1] - 系统启动文件(如`startup_stm32f4xx.s`)未配置FPU控制寄存器`CPACR` 2. **上下文切换未保存FPU寄存器** RT-Thread默认的上下文切换仅保存基本寄存器,若线程使用FPU指令但未配置`ARCH_USING_FPU`宏,会导致寄存器丢失触发Bus Fault[^1] 3. **堆栈对齐问题** FPU操作需要8字节对齐的栈空间(Cortex-M4/M7),若线程栈未满足对齐要求,执行浮点指令时会产生Bus Fault[^2] 4. **中断服务函数使用FPU未保护** 在中断处理函数中使用浮点运算但未添加`__attribute__((naked))`或手动保存`FPU`状态,导致上下文污染 --- #### 二、具体解决方法 ##### 1. 编译器配置 - **Keil/IAR**:在工程选项中启用FPU支持 ```c // Keil设置路径:Options → Target → Floating Point Hardware → Use FPU ``` - **GCC**:修改编译选项 ```makefile CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 ``` ##### 2. 修改RT-Thread配置 在`rtconfig.h`中添加以下宏定义: ```c #define ARCH_USING_FPU // 启用FPU上下文保存 #define RT_USING_FPU // 声明系统使用FPU #define RT_ALIGN_SIZE 8 // 强制8字节对齐 ``` ##### 3. 调整线程栈配置 ```c // 示例:主线程栈配置(需8字节对齐且足够大) #define RT_MAIN_THREAD_STACK_SIZE 1024 static struct rt_thread main_thread; ALIGN(8) // 关键对齐声明 static rt_uint8_t main_stack[RT_MAIN_THREAD_STACK_SIZE]; ``` ##### 4. 修改启动文件 在`startup_stm32f4xx.s`中初始化FPU: ```asm ; 启动文件中添加FPU使能代码 LDR.W R0, =0xE000ED88 LDR R1, [R0] ORR R1, R1, #(0xF << 20) STR R1, [R0] ``` ##### 5. 中断服务函数保护 在含FPU操作的中断函数中添加保护: ```c __attribute__((naked)) void USART1_IRQHandler(void) { __asm volatile ( "push {lr}\n" "vpush {s0-s31}\n" // 保存FPU寄存器 "bl USART1_RealHandler\n" "vpop {s0-s31}\n" "pop {pc}\n" ); } ``` --- #### 三、调试验证方法 1. **查看SCB寄存器** ```c void HardFault_Handler(void) { uint32_t cfsr = SCB->CFSR; // 0xE000ED28 uint32_t hfsr = SCB->HFSR; // 0xE000ED2C // IMPRECISERR标志(CFSR bit 1)表示FPU相关总线错误 } ``` 2. **使用RT-Thread的HardFault诊断工具** 在`components/libcpu/arm/common`中启用`RT_DEBUGING_HARD_FAULT`宏,可自动打印错误现场寄存器 3. **检查内存访问** 使用`__attribute__((aligned(8)))`修饰浮点数组,避免未对齐访问: ```c __attribute__((aligned(8))) float fpu_buffer[32]; ``` --- #### 四、典型错误场景 ```c // 错误示例:未对齐的浮点操作 void thread_entry(void *param) { float data[4] = {1.1, 2.2}; // 默认4字节对齐,FPU操作会触发Bus Fault float sum = data[0] + data[1]; // 此处产生异常 } // 修正:强制8字节对齐 RT_ALIGN(8) float data[4] = {1.1, 2.2}; ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值