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

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.