platformio / platform-ststm32

ST STM32: development platform for PlatformIO
https://registry.platformio.org/platforms/platformio/ststm32
Apache License 2.0
388 stars 305 forks source link

Make FPU and CMSIS-DSP configuration easier #591

Open maxgerhardt opened 2 years ago

maxgerhardt commented 2 years ago

When using a minimal platformio.ini of

[env:nucleo_l476rg]
platform = ststm32
board = nucleo_l476rg
framework = stm32cube

with src/main.c of

#include "stm32l4xx_hal.h"
#include <arm_math.h>

int main(void)
{
  HAL_Init();

  float32_t cosOutput;
  float32_t cosSquareOutput;
  while(1) {
     cosOutput = arm_cos_f32(1.2345f);
     arm_mult_f32(&cosOutput, &cosOutput, &cosSquareOutput, 1);
  }
}

void SysTick_Handler(void)
{
  HAL_IncTick();
}

Linking will fail.

Linking .pio\build\nucleo_l476rg\firmware.elf
.pio/build/nucleo_l476rg/src/main.o: In function `main':
main.c:(.text.startup.main+0xa): undefined reference to `arm_cos_f32'
main.c:(.text.startup.main+0x18): undefined reference to `arm_mult_f32'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\nucleo_l476rg\firmware.elf] Error 1
============[FAILED] Took 5.45 seconds ===============

This is because the STM32Cube builder script does not add the -larm_cortex... switch to actually link in the library.

Adding in

build_flags =
  -larm_cortexM4l_math

fixes that,

RAM:   [          ]   0.0% (used 44 bytes from 98304 bytes)
Flash: [          ]   0.4% (used 4660 bytes from 1048576 bytes)
Building .pio\build\nucleo_l476rg\firmware.bin
===============[SUCCESS] Took 5.48 seconds =============

but it's unintuitive and undocumented.

Further, above I explicitly linked in arm_cortexM4l_math (softfloat) instead of arm_cortexM4lf_math (hardfloat). This is because the STM32Cube builder script does not add any -mfpu or -mfloat-abi flags by default (source in the compilation process, so everything is compiled as default softfloat, which leads to a ton of linker errors if a user attempts to link with the hardfloat library

Linking .pio\build\nucleo_l476rg\firmware.elf
c:/users/max/.platformio/packages/toolchain-gccarmnoneeabi@1.70201.0/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/bin/ld.exe: error: C:/Users/Max/.platformio/packages/framework-stm32cubel4/Drivers/CMSIS/DSP/Lib/GCC\libarm_cortexM4lf_math.a(arm_cos_f32.o) uses VFP register arguments, .pio/build/nucleo_l476rg/firmware.elf does not
c:/users/max/.platformio/packages/toolchain-gccarmnoneeabi@1.70201.0/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/bin/ld.exe: failed to merge target specific data of file C:/Users/Max/.platformio/packages/framework-stm32cubel4/Drivers/CMSIS/DSP/Lib/GCC\libarm_cortexM4lf_math.a(arm_cos_f32.o)
c:/users/max/.platformio/packages/toolchain-gccarmnoneeabi@1.70201.0/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/bin/ld.exe: error: C:/Users/Max/.platformio/packages/framework-stm32cubel4/Drivers/CMSIS/DSP/Lib/GCC\libarm_cortexM4lf_math.a(arm_mult_f32.o) uses VFP register arguments, .pio/build/nucleo_l476rg/firmware.elf does not
c:/users/max/.platformio/packages/toolchain-gccarmnoneeabi@1.70201.0/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/bin/ld.exe: failed to merge target specific data of file C:/Users/Max/.platformio/packages/framework-stm32cubel4/Drivers/CMSIS/DSP/Lib/GCC\libarm_cortexM4lf_math.a(arm_mult_f32.o)
c:/users/max/.platformio/packages/toolchain-gccarmnoneeabi@1.70201.0/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/bin/ld.exe: error: C:/Users/Max/.platformio/packages/framework-stm32cubel4/Drivers/CMSIS/DSP/Lib/GCC\libarm_cortexM4lf_math.a(arm_common_tables.o) uses VFP register arguments, .pio/build/nucleo_l476rg/firmware.elf does not
c:/users/max/.platformio/packages/toolchain-gccarmnoneeabi@1.70201.0/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/bin/ld.exe: failed to merge target specific data of file C:/Users/Max/.platformio/packages/framework-stm32cubel4/Drivers/CMSIS/DSP/Lib/GCC\libarm_cortexM4lf_math.a(arm_common_tables.o)
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\nucleo_l476rg\firmware.elf] Error 1
=================[FAILED] Took 5.38 seconds ================

One has to explicitly add an extra script to add in -mfloat-abi=hard -mfpu=fpv4-sp-d16 in the CCFLAGS and LINKFLAGS to make this work (see https://community.platformio.org/t/error-object-uses-vfp-register-arguments-firmware-elf-does-not/25263).

The STM32Cube builder script should provide easier coniguration of the selected CMSIS-DSP library to be linked in, as well as being able to add hardfloat flags for those targets that support it (Cortex-M4, Cortex-M7, Cortex-M33 etc). These options should further be documented.

Note: STM32Duino does this regarding floating point flags and this regarding the library selection.

jnz86 commented 2 years ago

I have to agree with Max (again!).

I am encountering this in the wild right now. Using STM32 but not the framework.

but it's unintuitive

Very. I'm looking into why the linker wouldn't work as expected, but if Max hadn't made the post he did, and the user who first had the issue hadn't been clear enough for me to find it in search results I would be near-defeated. I'm a veteran programmer, but new PIO user. Making a script to add flags would be so far down the list of things I tried on my own that I would have gone back to STM32CubeIDE.