首页 > 解决方案 > 浮点数及其对 8 位微控制器内存的影响

问题描述

我目前正在开发一个项目,该项目包括在 stm-8 微控制器上使用 linux 中的 SDCC 编译器进行裸机编程。芯片中的内存非常低,所以我试图保持精简。我已经使用了 8 位和 16 位变量,一切都很顺利。但最近我遇到了一个问题,我真的需要一个浮点变量。因此,我编写了一个函数,该函数将 16 位值转换为浮点数,并执行我需要的数学运算并返回一个 8 位数字。这导致我在 MCU 上的最终编译代码从 1198 字节变为 3462 字节。现在我明白了使用浮点是内存密集型的,并且可能需要调用许多函数来处理浮点数的使用,但是将程序的大小增加这么多似乎很疯狂。

规格:MCU stm8151f2 编译器:带有 --opt_code_size 选项的 SDCC

int roundNo(uint16_t bit_input) 
{ 
    float num = (((float)bit_input) - ADC_MIN)/124.0;
    return num < 0 ? num - 0.5 : num + 0.5; 
}

标签: cembeddedsdcc

解决方案


要确定为什么代码在您的特定工具链上如此之大,您需要查看生成的汇编代码,并查看 FP 支持调用它的内容,然后查看映射文件以确定每个函数的大小。

作为使用 GCC 5.4.0 的Godbolt-Os for AVR 的示例(Godbolt 不支持 STM8 或 SDCC,因此这是作为 8 位架构进行比较),您的代码生成 6364 字节,而空函数生成 4081 字节。所以代码体所需的附加代码是 2283 字节。现在考虑到您同时使用不同的编译器和体系结构这一事实,这些与您的结果并没有什么不同。在生成的代码(下面)中rcall查看子例程的 s,例如__divsf3- 这些是大部分代码所在的位置,我怀疑 FP 除法是迄今为止更大的贡献者。

roundNo(unsigned int):
        push r12
        push r13
        push r14
        push r15
        mov r22,r24
        mov r23,r25
        ldi r24,0
        ldi r25,0
        rcall __floatunsisf
        ldi r18,0
        ldi r19,0
        ldi r20,0
        ldi r21,lo8(69)
        rcall __subsf3
        ldi r18,0
        ldi r19,0
        ldi r20,lo8(-8)
        ldi r21,lo8(66)
        rcall __divsf3
        mov r12,r22
        mov r13,r23
        mov r14,r24
        mov r15,r25
        ldi r18,0
        ldi r19,0
        ldi r20,0
        ldi r21,0
        rcall __ltsf2
        ldi r18,0
        ldi r19,0
        ldi r20,0
        ldi r21,lo8(63)
        sbrs r24,7
        rjmp .L6
        mov r25,r15
        mov r24,r14
        mov r23,r13
        mov r22,r12
        rcall __subsf3
        rjmp .L7
.L6:
        mov r25,r15
        mov r24,r14
        mov r23,r13
        mov r22,r12
        rcall __addsf3
.L7:
        rcall __fixsfsi
        mov r24,r22
        mov r25,r23
        pop r15
        pop r14
        pop r13
        pop r12
        ret

您需要对工具链生成的代码执行相同的分析才能回答您的问题。毫无疑问,SDCC 能够生成汇编列表和映射文件,这将允许您准确确定正在生成和链接的代码和 FP 支持。

最终,尽管在这种情况下您完全没有必要使用 FP:

int roundNo(uint16_t bit_input) 
{ 
  int s = (bit_input - ADC_MIN) ;
  s += s < 0 ? -62 : 62 ;
  return s / 124 ;
}

空函数相比,Godbolt 2283 字节。仍然有点大,但最有可能的问题是 AVR 缺少DIV指令所以调用__divmodhi4. STM8 具有DIV16 位除数和 8 位除数,因此在您的目标上它可能会明显更小(并且更快)。


推荐阅读