RT-Thread论坛
直播中

李猛

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

IAR下全志T113-S3 ARM Cortex-A7开启FPU后异常怎么解决?

花了几天移植rt-thread到IAR,目前测试线程正常运行,但是想尝试开启FPU,开启了宏定义 RT_USING_FPU  后启动后出现异常,程序运行后进入 Undef_Handler 异常中断中

上面是没有开启RT_USING_FPU  程序能正常启动,目前就空跑线程,1秒输出一个数字,并且还没有进行任何浮点运算或输出;


通过异常时的LR定位到出问题前的位置,这个应该是RT-Thread异常处理的位置,不是真实位置

通过rtt异常定位pc位置

IAR中FPU设置

程序启动后就初始化了FPU

  • #include "core_ca7.h"
  • //系统底层初始化,汇编中调用
  • void rt_low_level_init(void)
  • {
  •   unsigned int cpacr, fpexc;

  •   cpacr = __get_CPACR();
  •   /* Enable NEON and FPU */
  •   cpacr = (cpacr & ~(CPACR_ASEDIS_Msk | CPACR_D32DIS_Msk))
  •          |  (3UL << CPACR_cp10_Pos) | (3UL << CPACR_cp11_Pos);
  •   __set_CPACR(cpacr);

  •   fpexc = __get_FPEXC();
  •   fpexc |= 0x40000000UL;  /* Enable NEON and FPU */
  •   __set_FPEXC(fpexc);
  • }



回帖(1)

李刚

2025-10-21 17:56:26

针对在IAR环境下移植RT-Thread到全志T113-S3(ARM Cortex-A7)时开启FPU后触发Undef_Handler异常的问题,以下是系统的分析和解决方案:




问题根源分析




  1. FPU初始化时机问题

    系统启动早期(如C库初始化、静态构造函数)可能隐含浮点操作,若FPU未及时使能,会触发未定义指令异常。




  2. FPU寄存器未正确配置  



    • Cortex-A7需通过CPACR寄存器使能FPU访问权限(CP10/CP11)。

    • 缺少必要的内存屏障指令(ISB/DSB)。




  3. 编译器FPU设置不匹配

    IAR项目选项中的FPU配置需与代码设置一致。




  4. 上下文切换未适配FPU

    开启RT_USING_FPU后,RT-Thread需在上下文切换时保存/恢复FPU寄存器(s0-s31, FPSCR)。






解决方案


1. 提前初始化FPU(关键步骤)


修改启动流程,在任何浮点操作前完成FPU初始化:


// 在汇编启动文件中调用(如reset_handler)
PUBLIC __iar_program_start
EXTERN rt_hw_fpu_init_early

RESET_HANDLER:
    BL      rt_hw_fpu_init_early  // 提前初始化FPU
    LDR     R0, =__iar_program_start
    BX      R0

新增早期FPU初始化函数(rt_hw_fpu_init_early.c):


#include 
#include

void rt_hw_fpu_init_early(void) {
    // 启用CP10和CP11访问权限(置为0b11)
    uint32_t cpacr = __get_CPACR();
    cpacr |= (3 << 20) | (3 << 22);  // 设置CP10 & CP11
    __set_CPACR(cpacr);

    // 确保配置生效
    __ISB();
    __DSB();
}

2. 完善FPU上下文切换


检查并修改上下文切换代码(context_iar.S):


; 添加FPU寄存器保存/恢复
.macro SAVE_FPU_REGS
    VSTMDB  r0!, {d0-d15}   ; 保存D0-D15(覆盖S0-S31)
    VMRS    r1, FPSCR       ; 保存FPSCR
    STMFD   r0!, {r1}
.endm

.macro RESTORE_FPU_REGS
    LDMFD   r0!, {r1}
    VMSR    FPSCR, r1       ; 恢复FPSCR
    VLDMIA  r0!, {d0-d15}   ; 恢复D0-D15
.endm

; 在线程切换中使用
rt_hw_context_switch:
    SAVE_FPU_REGS        ; 保存当前线程FPU上下文
    ...                  ; 原有寄存器保存
    RESTORE_FPU_REGS     ; 恢复新线程FPU上下文
    ...                  ; 原有寄存器恢复

3. 校对IAR项目设置


确保IAR选项匹配:



  • Project > Options > General Options > Target  

    • Floating-point: VFPv4-D16  

    • FPU hardware: Enabled


  • C/C++ Compiler > Language  

    • C dialect: C99  

    • Allow VFP instructions: Yes



4. 验证初始化顺序


rt_low_level_init()中保留FPU初始化,但确认其调用顺序:


void rt_low_level_init() {
    rt_hw_fpu_init();  // 保留此处初始化(确保无冗余)
    ...                // 其他初始化
}



验证步骤



  1. 编译并下载固件。

  2. 单步调试观察rt_hw_fpu_init_early()执行后的CPACR寄存器值(应为0x00F00000)。

  3. 检查首次浮点指令执行前FPU是否已使能。

  4. 若仍异常,在Undef_Handler中打印触发地址,反汇编排查指令是否隐含浮点操作。




补充建议



  • 排查C库初始化:确认IAR的启动文件(__iar_init_core/__iar_init_vfp)是否自动开启FPU(若存在则删除冗余代码)。

  • 安全扩展支持:若使用TrustZone,需额外设置NSACR
    __set_NSACR(__get_NSACR() | (3 << 10));  // 使能非安全访问


通过以上步骤,FPU应在系统启动最早阶段生效,避免未定义指令异常,确保RT-Thread正常调度含浮点操作的线程。

举报

更多回帖

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