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

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

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

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

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

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

你可能感兴趣的:(#,嵌入式OS之RTThread,#,嵌入式SOC之RT1052)