FPU 使用注意事项
RTL8773E 增加了对 FPU的支持,用于硬件加速浮点数的运算,开启方法如图所示:

FPU 开启方法
Watch 工程包含了多个 lib,按照正常编译流程,所有 lib 和 watch 工程需要一起开启 FPU 编译选项。 如果用户引用第三方 lib,若此时 lib 没有开启 FPU 编译选项,而 watch 工程开启了 FPU 编译选项。则会在以下两个场景出现取不到正确浮点值的问题:
函数 funcA 定义在 lib,返回值类型为 float/double,并在 watch 调用 funcA。
函数 funcB 定义在 lib,参数类型为 float/double,并在 watch 调用 funcB。
本文将说明问题出现的原因和在 watch 工程中 workaround 的方法。
备注
如果 lib 工程和 watch 工程都开启/都不开启 FPU 编译选项,则不会出现该问题。
测试代码示例
定义在 filesystem lib 的两个测试函数原型:
float FPU_TestReturnFloat(void)
{
float test_para = 4567.1289f;
return test_para;
}
void FPU_TestParaFloat(float para1, float para2)
{
float test_para1 = para1;
float test_para2 = para2;
APP_PRINT_TRACE2("FPU_TestParaFloat: test_para1 = %f, test_para2 = %f", TRACE_FLOAT(test_para1), TRACE_FLOAT(test_para2));
}
-
Watch project 测试代码:
float FPU_TestReturnFloat(void); void FPU_TestParaFloat(float para1, float para2); float para1 = 12345.6789f; float para2 = 98765.4321f; float para3 = 0.0f; FPU_TestParaFloat(para1, para2); para3 = FPU_TestReturnFloat(); APP_PRINT_TRACE1("FPU_TestReturnFloat: para3 = %f", TRACE_FLOAT(para3));
Filesystem 工程不开启 FPU,watch 工程开启 FPU 测试结果
出现问题的 disasm:
-
Float 传参错误
... ;;;581 float para1 = 12345.6789f; 0x020a9dde: ed9f0a9c .... VLDR s0,[pc,#624] ; [0x20aa050] = 0x4640e6b7 ;;;582 float para2 = 98765.4321f; 0x020a9de2: eddf0a9c .... VLDR s1,[pc,#624] ; [0x20aa054] = 0x47c0e6b7 ;;;584 FPU_TestParaFloat(para1, para2); 0x020a9de6: f020fa34 .4. BL FPU_TestParaFloat ; 0x20ca252 ... ... ;;;899 void FPU_TestParaFloat(float para1, float para2) ;;;900 { 0x020ca252: e92d43f8 -..C PUSH {r3-r9,lr} 0x020ca256: 4605 .F MOV r5,r0 0x020ca258: 460e .F MOV r6,r1 ;;;901 float test_para1 = para1; 0x020ca25a: 462f /F MOV r7,r5 ;;;902 float test_para2 = para2; 0x020ca25c: 4634 4F MOV r4,r6 ...
测试结果:传参前后操作寄存器不一致
错误输出:
[APP] FPU_TestParaFloat: test_para1 = 0.000000, test_para2 = -30800760000000000.000000
-
Float return 错误
... ;;;893 float FPU_TestReturnFloat(void) ;;;894 { ;;;895 float test_para = 4567.1289f; 0x020ca24e: 4861 aH LDR r0,[pc,#388] ; [0x20ca3d4] = 0x458eb908 ;;;896 return test_para; ;;;897 } ... ... ;;;585 para3 = FPU_TestReturnFloat(); 0x020a9dea: f020fa30 .0. BL FPU_TestReturnFloat ; 0x20ca24e 0x020a9dee: 4a5d ]J LDR r2,[pc,#372] ; [0x20a9f64] = 0x88054c4 0x020a9df0: ee103a10 ...: VMOV r3,s0 ...
测试结果: return 前后操作寄存器不一致
错误输出:
[APP] FPU_TestReturnFloat: para3 = 12345.680000
解决方法
通过以下写法 workaround:
-
在 watch project 修改声明:
uint32_t FPU_TestReturnFloat(void); void FPU_TestParaFloat(uint32_t para1, uint32_t para2);
-
使用指针取值的方式传参或使用返回值:
float para1 = 12345.6789f; float para2 = 98765.4321f; uint32_t para3 = 0; uint32_t *p_para1 = (uint32_t *)¶1; uint32_t *p_para2 = (uint32_t *)¶2; float *p_para3 = (float *)¶3; FPU_TestParaFloat(*p_para1, *p_para2); para3 = FPU_TestReturnFloat(); APP_PRINT_TRACE1("FPU_TestReturnFloat: para3 = %f", TRACE_FLOAT(*p_para3));
Workround 后 filesystem 工程不开启 FPU,watch 工程开启 FPU 测试结果
Workaround 后的 disasm:
-
Float 传参正确
... ;;;589 FPU_TestParaFloat(*p_para1, *p_para2); 0x020a9dee: ee101a10 .... VMOV r1,s0 0x020a9df2: 9407 .. STR r4,[sp,#0x1c] 0x020a9df4: 9809 .. LDR r0,[sp,#0x24] 0x020a9df6: f020fa34 .4. BL FPU_TestParaFloat ; 0x20ca262 ... ... ;;;899 void FPU_TestParaFloat(float para1, float para2) ;;;900 { 0x020ca262: e92d43f8 -..C PUSH {r3-r9,lr} 0x020ca266: 4605 .F MOV r5,r0 0x020ca268: 460e .F MOV r6,r1 ;;;901 float test_para1 = para1; 0x020ca26a: 462f /F MOV r7,r5 ;;;902 float test_para2 = para2; 0x020ca26c: 4634 4F MOV r4,r6 ...
测试结果:传参前后操作寄存器一致
测试输出:
[APP] FPU_TestParaFloat: test_para1 = 12345.680000, test_para2 = 98765.430000
-
Float return 正确
... ;;;893 float FPU_TestReturnFloat(void) ;;;894 { ;;;895 float test_para = 4567.1289f 0x020ca25e: 4861 aH LDR r0,[pc,#388] ; [0x20ca3e4] = 0x458eb908 ;;;896 return test_para ;;;897 } ... ... ;;590 para3 = FPU_TestReturnFloat() 0x020a9dfa: f020fa30 .0. BL FPU_TestReturnFloat ; 0x20ca25e ;;;591 APP_PRINT_TRACE1("FPU_TestReturnFloat: para3 = %f", TRACE_FLOAT(*p_para3)) 0x020a9dfe: 4a5d ]J LDR r2,[pc,#372] ; [0x20a9f74] = 0x88054c4 0x020a9e00: 4603 .F MOV r3, r0 ...
测试输出:
[APP] FPU_TestReturnFloat: para3 = 4567.129000