[STM32/CLion] snprintf verursacht HardFault

Gast #6319653
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}")
Gast #6319702
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.
Gast #6319833
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.
Gast #6319852
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".
Gast #6319913
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).

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