Forum: Compiler & IDEs [STM32/CLion] snprintf verursacht HardFault


von Otto D. (Gast)


Lesenswert?

Hallo zusammen,

ich reihe mich in die Schlange der Personen ein, bei denen der Aufruf 
von s(n)printf bei Umwanldung einer beliebigen Ganzzahl (kein float) in 
einem HardFault mündet. Leider kann ich den Grund dafür nicht finden.

Soll heißen, wenn ich den Code Step-by-Step mit dem Debugger durchgehe, 
komme ich bis zum Aufruf von snprintf(). Danach hängt alles, bis ich den 
Debugger interrupte, woraufhin ich mich in der HardFault Schleife 
wiederfinde. Ein schrittweise Step-In in die snprinft() Funktion klappt 
ebenfalls nicht, da ich sofort in oben beschriebener Schleife hänge.

Ich hoffe ihr könnt mir weiterhelfen.

Verwendet werden in meiner Umgebung:
- CubeMX zur Erzeugung des "Basiscodes" sowie der Chip Konfiguration
- CLion als IDE für die eigentliche Entwicklung
- cmake i.V.m. arm-none-eabi-gcc für die Kompilierung
- openocd für das flashen und debuggen mit einem ST-Link v2

Der Quellcode wurde vollständig durch cubeMX erstellt, somit gehe ich 
davon aus das die "üblichen" Probleme (bspw. eine falsche 
Implementierung von _sbrk ausgeschlossen sind, da dann ja alle davon 
betroffen wären). Habe diese trotzdem in der syscalls.c kontrolliert und 
sie entspricht den gängigen Varianten.

Weiterhin habe ich die Toolchain bereits gegen die vorkompilierte von 
arm ausgetauscht, jedoch ohne Änderung im Ergebnis.

Die linker Datei (STM32F103C8Tx_FLASH.ld) stammt ebenfalls original aus 
dem cubeMX. Auch der (häufig) vorgebrachte Vorschlag testweise heap und 
stack von 0x200/0x400 auf 0x1000 zu erhöhen bracht keine Änderung.

Folgend einmal sowohl die main.c (enthält den Testaufruf von snprintf) 
sowie die von CLion erzeugte CMakeList. Hierbei handelt es sich um die 
einzigen beiden Änderungen (Aufruf von snprintf() in main.c) und die von 
CLion erstellte CMakeList von dem von cubeMX erzeugten Basisdaten.

main.c
1
#include "main.h"
2
#include "spi.h"
3
#include "tim.h"
4
#include "gpio.h"
5
6
#include <stdio.h>
7
8
void SystemClock_Config(void);
9
10
int main(void)
11
{
12
  HAL_Init();
13
  SystemClock_Config();
14
  MX_GPIO_Init();
15
  MX_SPI1_Init();
16
  MX_TIM1_Init();
17
18
  // Testaufruf von snprinft
19
  char buffer[64];
20
  snprintf(buffer, sizeof(buffer), "%d", 12); // <<-- HardFault
21
22
  while (1)
23
  {
24
25
  }
26
}
27
28
void SystemClock_Config(void)
29
{
30
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
31
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
32
33
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
34
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
35
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
36
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
37
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
38
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
39
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
40
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
41
  {
42
    Error_Handler();
43
  }
44
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
45
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
46
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
47
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
48
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
49
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
50
51
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
52
  {
53
    Error_Handler();
54
  }
55
}
56
57
void Error_Handler(void)
58
{
59
60
}
61
62
#ifdef  USE_FULL_ASSERT
63
void assert_failed(uint8_t *file, uint32_t line)
64
{ 
65
}
66
#endif

CMakeList
1
SET(CMAKE_SYSTEM_NAME Generic)
2
SET(CMAKE_SYSTEM_VERSION 1)
3
cmake_minimum_required(VERSION 3.7)
4
5
SET(CMAKE_C_COMPILER_WORKS 1)
6
SET(CMAKE_C_COMPILER arm-none-eabi-gcc)
7
SET(CMAKE_CXX_COMPILER_WORKS 1)
8
SET(CMAKE_CXX_COMPILER arm-none-eabi-g++)
9
set(CMAKE_ASM_COMPILER  arm-none-eabi-gcc)
10
set(CMAKE_AR arm-none-eabi-ar)
11
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
12
set(CMAKE_OBJDUMP arm-none-eabi-objdump)
13
set(SIZE arm-none-eabi-size)
14
15
SET(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/STM32F103C8Tx_FLASH.ld)
16
SET(COMMON_FLAGS
17
    "-mcpu=cortex-m3 ${FPU_FLAGS} -mthumb -mthumb-interwork -ffunction-sections -fdata-sections \
18
    -g -fno-common -fmessage-length=0 -specs=nosys.specs -specs=nano.specs")
19
SET(CMAKE_CXX_FLAGS_INIT "${COMMON_FLAGS} -std=c++11")
20
SET(CMAKE_C_FLAGS_INIT "${COMMON_FLAGS} -std=gnu99")
21
SET(CMAKE_EXE_LINKER_FLAGS_INIT "-Wl,-gc-sections,--print-memory-usage -T ${LINKER_SCRIPT}")
22
23
PROJECT(Test C CXX ASM)
24
set(CMAKE_CXX_STANDARD 11)
25
26
add_definitions(-DUSE_HAL_DRIVER -DSTM32F103xB)
27
28
file(GLOB_RECURSE SOURCES "startup/*.*" "Drivers/*.*" "Src/*.*")
29
30
include_directories(Inc Drivers/STM32F1xx_HAL_Driver/Inc Drivers/STM32F1xx_HAL_Driver/Inc/Legacy Drivers/CMSIS/Device/ST/STM32F1xx/Include Drivers/CMSIS/Include)
31
32
add_executable(${PROJECT_NAME}.elf ${SOURCES} ${LINKER_SCRIPT})
33
34
set(CMAKE_EXE_LINKER_FLAGS
35
    "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map")
36
37
set(HEX_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.hex)
38
set(BIN_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.bin)
39
40
add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD
41
        COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:${PROJECT_NAME}.elf> ${HEX_FILE}
42
        COMMAND ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${PROJECT_NAME}.elf> ${BIN_FILE}
43
        COMMENT "Building ${HEX_FILE}
44
Building ${BIN_FILE}")

von Nop (Gast)


Lesenswert?

printf & co nutzt man auch nicht auf Microcontrollern. Andererseits, wer 
sich den Code von CubeMX erzeugen läßt, nutzt auch printf, wie man 
sieht.

von Otto D. (Gast)


Lesenswert?

Gut, ich gebe offen zu, dass mir die einfache Verwendung von snprintf() 
zur Umwandlung einer int zu einem char[] einfach praktisch erschien und 
ja auch unterstützt wird (wenn sie auch nicht die 
platzsparenste/schnellste Methode darstellt). Da Geschwindigkeit/Platz 
bei meine Programm keine Rolle spielt (da ausreichend vorhanden).

Das ich mir die Chip-Konfiguration (Timer, GPIOs, usw.) von cubeMX 
erzeugen lasse scheint anscheinend auch ein Problem darzustellen. Hier 
sehe ich allerdings ohne begründete Argumente keinen Grund die 
Hardwarekonfiguration "per Fuß" durchzuführen, wenn der Hersteller 
dieser Hardware extra eine Software geschrieben hat, die das (ich setze 
mal fehlerfrei voraus) übernimmt.

von pegel (Gast)


Angehängte Dateien:

Lesenswert?

Mit CubeIDE erzeugtes Projekt hat keine Probleme mit snprintf.

Siehe Debug Ausgabe direkt nach der Funktion im Anhang.

von Michael F. (Gast)


Lesenswert?

Was sagen denn CFSR und HFSR über den Grund für den Hard Fault?

von pegel (Gast)


Lesenswert?

Kannst deine .ioc Projekt Datei mal anhängen.
Ich importiere die dann in CubeIDE.

Mal sehen, ob der Fehler vielleicht doch woanders liegt.

von Otto D. (Gast)


Angehängte Dateien:

Lesenswert?

Anbei die .ioc Projekt Datei von cubeMX.

von pegel (Gast)


Lesenswert?

Funktioniert ohne Probleme.
Das gleiche Ergebnis wie im Bild oben.

Muss an deiner IDE liegen.

von Otto D. (Gast)


Lesenswert?

Michael F. schrieb:
> Was sagen denn CFSR und HFSR über den Grund für den Hard Fault?

Hat leider etwas gedauert, aber hier die beiden Register sobald er in 
den HardFault geht.
1
CFSR = 1024       (0b10000000000)
2
HFSR = 1073741824 (0b1000000000000000000000000000000)

von pegel (Gast)


Lesenswert?

Was steht eigentlich in FPU_FLAGS?

Einen weiteren Unterschied sehe ich in -std=gnu99, ist bei mir 
-std=gnu11.

von samuel (Gast)


Lesenswert?

Bitte vergleiche doch mal deine CMakeLists.txt mit der von CubeMX 
generierten Makefile. Sind wirklich alle Flags identisch, insb. die für 
den Linker?

von samuel (Gast)


Lesenswert?


von Otto D. (Gast)


Lesenswert?

samuel schrieb:
> Bitte vergleiche doch mal deine CMakeLists.txt mit der von CubeMX
> generierten Makefile. Sind wirklich alle Flags identisch, insb. die für
> den Linker?

Oh Mann, da sieht es ja aus wie Kraut und Rüben...
Anscheinend kann cLion zwar STM32, aber keine Makefiles lesen. Zumindest 
sehe ich da doch grössere Abweichungen.

CFlags die im Makefile vorhanden sind, aber in CMakeList fehlen:
1
-Og -Wall -gdwarf-2 -MMD -MP -MF""
Dafür hat cmake aber welche ergänzt:
1
-mthumb-interwork -fno-common -fmessage-length=0 -specs=nosys.specs -specs=nano.specs

Das selbe Spiel sehe ich bei den LDFlags:
Im Makefile vorhanden, aber fehlen in CMakeList:
1
-lc -lm -lnosys
Dafür in CMakeList vorhanden, aber nicht im Makefile:
1
-mthumb-interwork -ffunction-sections -fdata-sections -fno-common -fmessage-length=0 -specs=nosys.specs -g  --print-memory-usage  -Wl

Bin jetzt nicht der Experte was die C/LD Flags angeht, aber so eine 
große Abweichung sollte doch nicht vorkommen da cLion seine Vorgaben ja 
von cubeMX bekommt.

Anscheinend ist die "ach so ausgereifte" STM32 Unterstützung doch nicht 
so toll. Immerhin ist mein Anwendungsfall ein int in char umzuwandeln 
nun doch nicht so speziell.

von Johannes S. (Gast)


Lesenswert?

Das -specs=nosys.specs kommt mir verdächtig vor, kannst du das mal 
rausnehmen?

von pegel (Gast)


Lesenswert?

€199.00 /Benutzer 1. Jahr

€159.00 /2. Jahr

€119.00 /ab dem 3. Jahr

Wau. Ist das fürs Hobby oder Zwang?
Nur für STM32?

von pegel (Gast)


Angehängte Dateien:

Lesenswert?

Johannes S. schrieb:
> Das -specs=nosys.specs kommt mir verdächtig vor

CubeIDE setzt das auch ein.

von Johannes S. (Gast)


Lesenswert?

https://www.embedded-software-engineering.de/amp/bare-bones-mit-gcc-und-c-a-674430/
Nosys ersetzt die Systemfunktionen durch leere stubs.

von Otto D. (Gast)


Lesenswert?

pegel schrieb:
> €199.00 /Benutzer 1. Jahr
>
> €159.00 /2. Jahr
>
> €119.00 /ab dem 3. Jahr
>
> Wau. Ist das fürs Hobby oder Zwang?
> Nur für STM32?

Hobby. Allerdings nicht nur für STM32. Die Einzellizenz für Nutzer 
(nicht Firmen) liegt bei €89 / Jahr. Und dann hat man die Version 
dauerhaft (auch wenn man nicht mehr zahl, man kriegt halt nur keine 
neueren Versionen mehr).

Hab damals mit python (pyCharm IDE) und Java (IntelliJ) angefangen 
(beides gratis Community Versionen vom selben Hersteller). Und in die 
IDE hab ich mich verguckt. Das Handling ist einfach bei allen gleich. 
Wollte deshalb für C/C++ auch eine IDE mit selben Funktionsumfang und 
Handling haben, dann fühlt man sich gleich zuhause.

Das die STM32 können war da nur "der Bonus".

von Otto D. (Gast)


Lesenswert?

Johannes S. schrieb:
> 
https://www.embedded-software-engineering.de/amp/bare-bones-mit-gcc-und-c-a-674430/
> Nosys ersetzt die Systemfunktionen durch leere stubs.

Und wenn ich den Beitrag richtig verstehe, ist der Aufruf von nosys 
ungefährlich/überflüssig, da sie von nano sowieso erzwungen wird.

von pegel (Gast)


Lesenswert?

Also hätte ich jetzt das Problem, würde ich:
${FPU_FLAGS} ersetzen durch -mfloat-abi=soft
-std=gnu99 ersetzen durch -std=gnu11

und hinter -specs=nano.specs noch -lc -lm einfügen und probieren.

von Johannes S. (Gast)


Lesenswert?

ich benutze Mbed, habe nachgesehen und da ist auch ein -lnosys drin.
Aber -specs=nano.specs gehört doch in die Linkerflags, und da fehlt das?

von Otto D. (Gast)


Lesenswert?

pegel schrieb:
> Also hätte ich jetzt das Problem, würde ich:
> ${FPU_FLAGS} ersetzen durch -mfloat-abi=soft
> -std=gnu99 ersetzen durch -std=gnu11
>
> und hinter -specs=nano.specs noch -lc -lm einfügen und probieren.

Danke! Das war die Lösung.
Habe "lc -lm" ergänzt und die FPU_FLAGS mfloat-abi=soft gesetzt (war 
leer).

Und schon ist er trotz nicht mehr gecrasht.
Schaut schonmal sehr gut aus, werde das morgen mal genauer testen und 
dann ein Update geben.

Ich möchte mich bei allen bedanken für die Hilfe.
Mir leuchtet nur nicht ein wieso die Flags falsch sind, da er sie ja von 
cubeMX ausliest. Dann müssten die ja bei ALLEN falsch sein (cubeMX ist 
der offizielle Weg in cLion die Quellen zu erzeugen).

von Daniel -. (root)


Lesenswert?

den gleichen Fehler hatte ich auch
insofern bist du nicht der einzige :)

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.