Forum: Compiler & IDEs sqrtf() ist immer 1 - STM32F401


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Martin K. (dschadu)


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.

von (prx) A. K. (prx)


Lesenswert?

Versehentlich mit Optimierung übersetzt?

Keine der Variablen wird im gezeigten Code letztlich irgendwo genutzt. 
Kann dazu führen, dass sie verschwinden und die Rechnungen nicht 
durchgeführt werden.

Wer behauptet, der Wert sei -1?

: Bearbeitet durch User
von Martin K. (dschadu)


Angehängte Dateien:

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
}

: Bearbeitet durch User
Beitrag #7555108 wurde vom Autor gelöscht.
von Peter (pittyj)


Lesenswert?

Warum steht eigentlich ein $ in dem Bild vor r0?

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?

von Veit D. (devil-elec)


Lesenswert?


von Martin K. (dschadu)


Angehängte Dateien:

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.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


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

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.