sqrtf() ist immer 1 - STM32F401

OP #7555091
Lesenswert?

Hi,

ich bin auf ein sehr seltsames Problem gestoßen: In einem Minimal-Test Programm ist der Rückgabewert von sqrtf() immer 1. Identisch mit sqrt(). Egal was ich der Funktion an Wert übergebe (Variable oder Festwert). Folgendes Setup: GCC 12.3.1, cmake 3.20.3.2, STM32F401CCU6

Projekt erstellt mit VisualGDB und STM32CubeMX

Da der Code der main.c sehr lang ist, nur das was ich hinzugefügt habe zu der generierten Datei:

1
/* Private includes ----------------------------------------------------------*/
2
/* USER CODE BEGIN Includes */
3
#include <math.h>
4
/* USER CODE END Includes */
1
int main(void)
2
{
3
  // [Gekürzt]
4

5
  /* Initialize all configured peripherals */
6
  MX_GPIO_Init();
7
  /* USER CODE BEGIN 2 */
8

9
  float x = 125;
10
  float y = 125;
11
  float xx = powf(x, 2);     // Ist korrekt: 15625
12
  float yy = powf(y, 2);     // Ist korrekt: 15625
13
  float xxyy = xx + yy;      // Ist korrekt: 31250
14
  float r0 = sqrtf(xxyy);    // Ist falsch: 1
15
  
16
  float r1 = r0 - 36;
17
  
18
  /* USER CODE END 2 */
19

20
  /* Infinite loop */
21
  /* USER CODE BEGIN WHILE */
22
  while (1)
23
  {
24
    /* USER CODE END WHILE */
25

26
    /* USER CODE BEGIN 3 */
27
  }
28
  /* USER CODE END 3 */
29
}

Ich habe schon versucht die Math-Library manuell dem Linker mit zu geben über die cmake. Und auch explizit die FPU deaktiviert. Beides brachte keinen Erfolg.

1
cmake_minimum_required(VERSION 3.15)
2

3
project(MathTest LANGUAGES C CXX ASM)
4

5
find_bsp(ID com.sysprogs.project_importers.stm32.cubemx SOURCE_PROJECT MathTest.ioc)
6

7
add_bsp_based_executable(NAME MathTest
8
  GENERATE_BIN
9
  GENERATE_MAP)
10

11
  target_link_libraries(MathTest PRIVATE m)
12
  target_compile_options(MathTest PRIVATE -mfloat-abi=soft)

Ich komm hier nicht mehr weiter und hoffe auf eure Hilfe.

OP #7555104
Lesenswert?

Das ganze wird ohne Optimierung compiliert. Im Anhang ein Screenshot vom Debugging mit SWD.

Ich bin jetzt aber einen Schritt weiter: Es wird noch eine weiter cmake Datei eingebunden, mit den folgenden Flags:

1
set(_core_commonflags -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard)

Ändere ich -mfloat-abi=hard zu -mfloat-abi=soft, ist r0 = 1127270102. Immerhin nicht mehr 1, aber weit entfernt von richtig.

SystemInit wird auch korrekt aufgerufen, um die Hardware FPU zu aktivieren:

1
void SystemInit(void)
2
{
3
  /* FPU settings ------------------------------------------------------------*/
4
  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
5
    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
6
  #endif
7
// [Gekürzt]
8
}
Angehängte Dateien:
Beitrag #7555108 wurde von einem Moderator gelöscht.
OP #7555302
Lesenswert?

Vielen dank für eure Hilfe schon einmal! Ich habe ein Minimalprojekt identisch zu dem in VisualGDB einmal mit der STM32CubeIDE erstellt. Damit geht das problemlos (Auch mit Hardware FPU). Ich vermute hier also eine falsche Einstellung irgendwo in den Tiefen der cmake-files in Zusammenhang mit der Hardware FPU. Ich melde mich, wenn ich eine Lösung gefunden habe.

Peter schrieb:

Warum steht eigentlich ein $ in dem Bild vor r0?

Das ist eine gute Frage

Edit:

Kann es sein, dass der Debugger einfach nur das CPU Register r0 ausgibt, und nicht den Inhalt einer Variablen, die auch zufällig r0 heisst?

Oh mein gott, das ist es! Da wäre ich ja im leben nicht drauf gekommen. Vielen vielen Dank für diesen Hinweis! Habe meinen Fehler also die ganze Zeit an der falschen stelle gesucht, weil dass das erste "falsche" Ergebnis war in der Formel.

Angehängte Dateien:
Persönliche Seite #7555315
Lesenswert?

Martin K. schrieb:

Ändere ich -mfloat-abi=hard zu -mfloat-abi=soft

Macht wenig Sinn bei einem Prozessor mit FPU sofern du keine externen Bibliotheken einbindest (außer den Standard Bibliotheken), weil unnötig langsam.

Übergebe

-mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard

an alle (!) Compiler-Aufrufe und den Linker-Aufruf (!). Prüfe ob das auch wirklich von CMake übergeben wird, und nicht noch von irgendwo anders her noch "soft" übergeben wird. Dann sollte es "einfach so" funktionieren. Der Rückgabewert wird dann aber nicht in r0 zurück gegeben, sondern im FPU Register s0 ¹. Funktioniert auch mit Optimierungen.

Das funktioniert so mit dem GCC-ARM-Embedded, welcher u.a. bei der STM32CubeIDE mitgeliefert wird, und auch einzeln hier bezogen werden kann:

https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads

Bei manchen anderen (alten) GCC Distributionen klappt es so nicht.

1: AAPCS https://github.com/ARM-software/abi-aa/blob/2a70c42d62e9c3eb5887fa50b71257f20daca6f9/aapcs32/aapcs32.rst#procedure-calling

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren