Forum: Mikrocontroller und Digitale Elektronik STM32F4 sprintf Problem


von Sebastian T. (sebastian_tsch)


Lesenswert?

Hi,

Ich möchte über die UART Schnittstelle ein paar Daten ausgeben, doch 
leider scheint das Programm bei sprintf(str, "Acceleration X: %d",5) zu 
hängen, alles andere wird nicht mehr ausgeführt. Anscheinend 
funktioniert das mit dem %d nicht, kennt das Problem Jemand? Strings 
kann ich sonst problemlos ausgeben. Ich habe das mit dem Debugger 
getestet, der Wert von i existiert und es crasht nicht vor sprintf.


1
int main(void)
2
{
3
  TM_MPU6050_t MPU6050_Data;
4
  char str[120];
5
  /* Initialize system */
6
  SystemInit();
7
8
9
10
  /* Initialize USART, PB6, PB7*/
11
  TM_USART_Init(USART1, TM_USART_PinsPack_2, 57600);
12
13
  /* Initialize MPU6050 sensor SCL: PA8, SDA: PC9 */
14
  if (TM_MPU6050_Init(&MPU6050_Data, TM_MPU6050_Device_0, TM_MPU6050_Accelerometer_2G, TM_MPU6050_Gyroscope_2000s) != TM_MPU6050_Result_Ok) {
15
    /* Display error to user */
16
    TM_USART_Puts(USART1, "MPU6050 Error\n");
17
18
    /* Infinite loop */
19
    while (1);
20
  }
21
22
  while (1) {
23
    sprintf(str,"Test");
24
    TM_USART_Puts(USART1, str);
25
    for(int i=0;i<8000000;i++); //delay
26
27
    TM_MPU6050_ReadAll(&MPU6050_Data);
28
    int i=MPU6050_Data.Accelerometer_X;
29
    sprintf(str, "Acceleration X: %d",5);
30
31
    TM_USART_Puts(USART1, str);
32
33
    for(int i=0;i<8000000;i++); //delay
34
  }
35
}

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Welcher Compiler, welche C-Library? Falls GCC&newlib, wie _sbrk_r 
implementiert?

von Sebastian T. (sebastian_tsch)


Lesenswert?

Ich verwende OpenSTM32, ich glaube das verwendet den GCC Compiler.

Dr. Sommer schrieb:
> _sbrk_r

Da bin ich überfragt.

von Dr. Sommer (Gast)


Lesenswert?

Sebastian T. schrieb:
> Da bin ich überfragt.

Dann such doch mal in deinem Projekt danach, in den von der IDE 
angelegten Dateien...

von Sebastian T. (sebastian_tsch)


Lesenswert?

Ich vermute du meinst diese da, wurde in einem Header mit #define als 
_sbrk_r angegeben.
1
caddr_t _sbrk(int incr)
2
{
3
  extern char end asm("end");
4
  static char *heap_end;
5
  char *prev_heap_end;
6
7
  if (heap_end == 0)
8
    heap_end = &end;
9
10
  prev_heap_end = heap_end;
11
  if (heap_end + incr > stack_ptr)
12
  {
13
//    write(1, "Heap and stack collision\n", 25);
14
//    abort();
15
    errno = ENOMEM;
16
    return (caddr_t) -1;
17
  }
18
19
  heap_end += incr;
20
21
  return (caddr_t) prev_heap_end;
22
}

von Dr. Sommer (Gast)


Lesenswert?

Sieht ganz sinnvoll aus. Finde mal heraus, in welcher Funktion es genau 
stehen bleibt.

von Sebastian T. (sebastian_tsch)


Lesenswert?

Naja, ich komme mit dem Debugger gar nicht erst in sprintf(..%d..) 
hinein.

von hp-freund (Gast)


Lesenswert?

Das Problem kann also auch schon eine Zeile drüber liegen?
Kommentiere die mal aus.

Heap/Stack Grösse passen?

von hp-freund (Gast)


Lesenswert?

Die zwei Zeilen drüber meinte ich...

von Sebastian T. (sebastian_tsch)


Lesenswert?

Das habe ich schon probiert, wenn ich in der while(1) Schleife nur z.B 
ein sprintf("..%d..",5) habe, hangt sich der debugger bei sprintf auf.

von hp-freund (Gast)


Lesenswert?

sprintf(str,"Test");

Funktioniert?

von hp-freund (Gast)


Lesenswert?

Nicht das einfach nur deine Delay Zählschleifen wegoptimiert werden.

von Sebastian T. (sebastian_tsch)


Lesenswert?

hp-freund schrieb:
> sprintf(str,"Test");
>
> Funktioniert?

Ja das geht, da kann ich auch die schleife laufen lassen und ich bekomme 
etwa alle halbe Sekunde ein Test im Terminal.

von hp-freund (Gast)


Lesenswert?

Also vielleicht doch Speicherprobleme?
Gib mal deinem Linker ein:

 -specs=nano.specs

von Dr. Sommer (Gast)


Lesenswert?

Sobald das Programm stehen bleibt halte es an, und schaue dir im 
Backtrace an welche Funktion es war...

von Nop (Gast)


Lesenswert?

Ich nehme mal an, itoa wäre zu einfach als Lösung, ne?

Falls nicht vorhanden, geht auch das hier:
https://www.mikrocontroller.net/articles/FAQ#Eigene_Umwandlungsfunktionen

von Stromverdichter (Gast)


Lesenswert?

Hallo Sebastian,
du musst lernen, das Problem auf das Wesentliche zu reduzieren. Isoliere 
dein Problem und analysiere es dann. All die Schleifen die so manchmal 
nicht funktionieren(int ist oft nur 2 Byte lang, dann besser uint32_t 
nutzen, das stimmt immer) verschleiern doch nur die Problemchen. Ist 
deine Senderoutine Interrupt-basierend? Sind die Puffer richtig gesetzt? 
Sende am besten erst mal ein Byte und bastle dir dann den String selbst 
zusammen. Das hilft beim Verständnis ungemein.

Sebastian T. schrieb:
> int i=MPU6050_Data.Accelerometer_X;
>     sprintf(str, "Acceleration X: %d",5)

was soll das bewirken? Das funktioniert doch nicht. wo kommt den da die 
5 her, wofür ist die gut? Wo ist die Variable?

von Johannes S. (Gast)


Lesenswert?

Stromverdichter schrieb:
> Das funktioniert doch nicht. wo kommt den da die 5 her, wofür ist die
> gut? Wo ist die Variable?

Vielleicht geht es um die Reduzierung auf das wesentliche?

Würde auch auf zu kleinen Stack tippen, printf ist da sehr hungrig.

Oder falsches/fehlendes include? Wird alles ohne Warnings übersetzt?

von Vorname N. (felixx)


Lesenswert?

Klingt für mich spontan auch nach einem Stack-Überlauf.
Da die STMF4xx Derivate mehrere KB RAM bereitstellen, einfach mal mit 
"großzügigen" Werten
_Min_Heap_Size = 0x1000;
_Min_Stack_Size = 0x1000;
in der Linker-Steuerdatei testen. Die Datei ist an der Endung .ld 
erkennbar.

von Sebastian T. (sebastian_tsch)


Lesenswert?

Stromverdichter schrieb:
> was soll das bewirken? Das funktioniert doch nicht. wo kommt den da die
> 5 her, wofür ist die gut?

Das war nur zum testen, ich habe das Programm nun mal auf das 
wesentliche reduziert, das Versenden von Integer Variablen.

Ich habe die _Min_Heap_Size auf 0x1000 gesetzt, doch leider ohne Erfolg.

Nop schrieb:
> Ich nehme mal an, itoa wäre zu einfach als Lösung, ne?

itoa funktioniert, es wird nur ein bisschen mühsamer alle Sensordaten zu 
senden. Mich laust es aber, warum das mit sprintf nicht geht.
1
#include "stm32f4xx.h"
2
#include "stm32f4_discovery.h"
3
#include "tm_stm32f4_usart.h"
4
#include <stdio.h>
5
#include <stdlib.h>
6
7
int main(void)
8
{
9
  SystemInit();
10
11
  char str[120];
12
13
  TM_USART_Init(USART1, TM_USART_PinsPack_2, 57600);
14
15
  while (1) {
16
17
    sprintf(str,"Start");
18
    TM_USART_Puts(USART1, str);
19
    for(int i=0;i<8000000;i++);
20
21
    sprintf(str, "Test Number: %d",5);
22
    TM_USART_Puts(USART1, str);
23
    for(int i=0;i<8000000;i++);
24
  }
25
}

: Bearbeitet durch User
von Jannyboy (Gast)


Lesenswert?

Sebastian T. schrieb:
> sprintf(str, "Test Number: %d",5);

So kann das nicht funktionieren 5 ist keine Integer Variable.

So sollte es gehen:
1
int var = 5;
2
sprintf(str, "Test Number: %d",var);

von Christian D. (burning_legend)


Lesenswert?

Gab es bei dem STM32 mit GCC nicht Alignment Probleme im Demo-Code? Ich 
hab es jetzt nicht genau im Kopf, aber die linker files hatten afair 
eine falsche Stack-Adresse drin stehen. Welches Linker Script benutzt 
du?

von hp-freund (Gast)


Lesenswert?

Moin,
was ist mit

-specs=nano.specs

?

von Nop (Gast)


Lesenswert?

Jannyboy schrieb:
> Sebastian T. schrieb:
>> sprintf(str, "Test Number: %d",5);
>
> So kann das nicht funktionieren 5 ist keine Integer Variable.

Unsinn, natürlich funktioniert das (gerade getestet). Es muß ein Integer 
übergeben werden, und selbstverständlich kann das auch eine Zahl sein.

von Johannes S. (Gast)


Lesenswert?

vielleicht mal das map file posten?

von Stromverdichter (Gast)


Lesenswert?

Zum testen könntest du mal
char str[16];
kleiner machen und alternativ das array außerhalb der main global 
deklarieren, dann sollte es doch nicht auf dem Stack liegen.
Hoffentlich findest du bald den Fehler, ich bin echt gespannt, wo er 
liegt. Den Stack kannst du dir nicht einfach mal mit dem Debugger 
anschauen?

von A. S. (Gast)


Lesenswert?

Sebastian T. schrieb:
> TM_USART_Puts(USART1, str);

Und Du bist sicher, dass TM_USART_Puts blockierend arbeitet und den 
Inhalt von str nicht vorher umkopiert?

von Sebastian T. (sebastian_tsch)


Angehängte Dateien:

Lesenswert?

Ich habe alles mögliche probiert, leider immer noch kein Erfolg. Ich 
kann auch nicht mit dem Debugger in sprintf rein um zu sehen, was genau 
passiert. Auf den Mikrocontrollern ist ja meist eine gekürzte Version 
von printf drauf, doch wo kann ich die einsehen/ändern? Es liegt ganz 
klar an sprintf und nicht an einer anderen Codezeile, es crasht mir 
sogar wenn ich nur ein sprintf in der Hauptschleife habe, aber eben nur 
wenn ich noch Werte dem String hinzufügen will.
1
sprintf("test"); //geht wunderbar
2
sprintf("test %d",1); //crash

Im Anhang habe ich das Mapfile.

Grüsse Sebastian

: Bearbeitet durch User
von A. S. (Gast)


Lesenswert?

>
>
1
> sprintf("test"); //geht wunderbar
2
> sprintf("test %d",1); //crash
3
>
>

a) Schau Dir an, ob Du printf oder sprintf verwenden wolltest
b) schalte die Warnmeldungen ein. Alle.
c) RTFM für sprintf. Egal wo, die ersten 2 Absätze reichen, notfalls nur 
die Declaration.

wenn nach 2 Minuten noch etwas unklar sein sollte, melde Dich.

von temp (Gast)


Lesenswert?

Sebastian T. schrieb:
> sprintf(str,"Test");

Da wird aber auch kein sprintf aufgerufen. Der gcc ist mittlerweile so 
schlau zu merken, dass dafür ein strcpy(str,"Test"); reicht und sprintf 
hier "mit Kanonen nach Spatzen" wäre.

Ich denke das liegt an _sbrk. Das wird bei "sprintf(str,"Test");" nicht 
aufgerufen, nur bei "sprintf("test %d",1);"

Was heißt crasht? Was passiert denn wenn du im gecrashten Zustand im 
Debugger das Programm unterbrichst? Landest du da im Hardfault oder wo?

Ansonsten die _sbrk mal aus dem Header nehmen und normal mit in das 
c-File packen ohne #define. Dann kannst du auch da mal einen Breakpoint 
setzen.

von Sebastian T. (sebastian_tsch)


Lesenswert?

Achim S. schrieb:
>>
>>
1
>> sprintf("test"); //geht wunderbar
2
>> sprintf("test %d",1); //crash
3
>>
>>
>
> a) Schau Dir an, ob Du printf oder sprintf verwenden wolltest
> b) schalte die Warnmeldungen ein. Alle.
> c) RTFM für sprintf. Egal wo, die ersten 2 Absätze reichen, notfalls nur
> die Declaration.
>
> wenn nach 2 Minuten noch etwas unklar sein sollte, melde Dich.

Ich habe das hier im Forum nur falsch geschrieben, ich meinte natürlich:
1
sprintf(str,"test:"); //geht wunderbar
2
sprintf(str,"test: %d",100); //crash

von temp (Gast)


Lesenswert?

laut deinem mapfile gibt es eine src/syscalls.c. Da stehen normalerweise 
diese Sachen drin die für sprintf noch interessant sind. Poste die doch 
mal.

von Sebastian T. (sebastian_tsch)


Lesenswert?

temp schrieb:
> Was heißt crasht? Was passiert denn wenn du im gecrashten Zustand im
> Debugger das Programm unterbrichst? Landest du da im Hardfault oder wo?

Wenn ich den Debugger verwende und in die Funktion gehen will, passiert 
einfach nichts und es scheint in einer loop zu hängen.

temp schrieb:
> Ansonsten die _sbrk mal aus dem Header nehmen und normal mit in das
> c-File packen ohne #define. Dann kannst du auch da mal einen Breakpoint
> setzen.

Werde ich mal probieren, danke.

von Sebastian T. (sebastian_tsch)


Angehängte Dateien:

Lesenswert?

temp schrieb:
> laut deinem mapfile gibt es eine src/syscalls.c. Da stehen normalerweise
> diese Sachen drin die für sprintf noch interessant sind. Poste die doch
> mal.

Ok, habe das syscalls.c im Anhang. Dort ist ja auch _sbrk definiert.

: Bearbeitet durch User
von temp (Gast)


Lesenswert?

mach doch mal einen Breakpoint da drauf. Da siehst du wenigstens was 
passiert.

von Sebastian T. (sebastian_tsch)


Lesenswert?

temp schrieb:
> mach doch mal einen Breakpoint da drauf. Da siehst du wenigstens was
> passiert.

Das habe ich probiert, doch ich komme gar nie in _sbrk hinein. Auch wenn 
ich "step in" klicke im debugger für sprintf(...), dann passiert nichts. 
Ich komme auch nicht in sprintf(str,"test"); hinein, obwohl dies 
funktioniert.

von temp (Gast)


Lesenswert?

Kannst du denn den Debugger nicht anhalten und dann sehen wo er steht? 
Wenn nicht, dann denk mal über ne vernünftige Entwicklungsumgebung nach.

passt den deine Implementierung der syscall.c zum Linkerscript?

von temp (Gast)


Lesenswert?

Sebastian T. schrieb:
> Ich komme auch nicht in sprintf(str,"test"); hinein, obwohl dies
> funktioniert.

Das habe ich eben schon versucht zu erklären. Da steht zwar sprintf aber 
der Compiler merkt das da keine Parameter übergeben werden und macht ein 
strcpy draus. Deshalb brauchst du da auch nicht weiter forschen.

von temp (Gast)


Lesenswert?

Hier noch ein Auszug aus deinem map-File:

LOAD 
c:/ac6/systemworkbench/plugins/fr.ac6.mcu.externaltools.arm-none.win32_1 
.7.0.201602121829/tools/compiler/bin/../lib/gcc/arm-none-eabi/5.2.1/armv 
7e-m/fpu/crtn.o
                0x20020000                _estack = 0x20020000
                0x00000000                _Min_Heap_Size = 0x0
                0x00000400                _Min_Stack_Size = 0x400

.isr_vector     0x08000000      0x188


ohne Heap wird das halt nichts. Bau mal ein malloc in deinen Code ein. 
Das wird dann auch crashen.

von Sebastian T. (sebastian_tsch)


Lesenswert?

temp schrieb:
> c:/ac6/systemworkbench/plugins/fr.ac6.mcu.externaltools.arm-none.win32_1
> .7.0.201602121829/tools/compiler/bin/../lib/gcc/arm-none-eabi/5.2.1/armv
> 7e-m/fpu/crtn.o
>                 0x20020000                _estack = 0x20020000
>                 0x00000000                _Min_Heap_Size = 0x0
>                 0x00000400                _Min_Stack_Size = 0x400
>
> .isr_vector     0x08000000      0x188
>
> ohne Heap wird das halt nichts. Bau mal ein malloc in deinen Code ein.
> Das wird dann auch crashen.

Ich habe den Heap und Stack auch schon auf 0x1000 getan, leider kein 
Erfolg.

von temp (Gast)


Lesenswert?

Sorry, aber das passt alles nicht zusammen. Wenn du in deiner IDE was an 
den Einstellungen drehst muss sich das auch im map-File wieder finden. 
Auch die Symbole im Code müssen zum Linkerscript passen. Ich vermute mal 
das wurde alles irgendwie zusammen kopiert ohne zu wissen wie es 
zusammenhängt. Deshalb nochmal die Frage: Wer hat dir den die syscalls.c 
ins src Verzeichnis gezaubert und wie passt die zum Linkerscript? Poste 
das Linkerscript oder ein mini-Projekt mal komplett. Im Moment stocherst 
du nur im trüben und bist meilenweit von einer systematischen 
Fehlersuche entfernt.

von temp (Gast)


Lesenswert?

nimm die syscalls.c mal raus aus deinem Projekt und berichte die 
Linkerfehler. Vielleicht hat dir die IDE, das unbekannte Wesen, schon 
alles richtig zusammengebaut und du versuchst krampfhaft deine eigenen 
Versionen zu linken und gewinnst.

von Dr. Sommer (Gast)


Lesenswert?

Sebastian T. schrieb:
> temp schrieb:
>> mach doch mal einen Breakpoint da drauf. Da siehst du wenigstens was
>> passiert.
>
> Das habe ich probiert, doch ich komme gar nie in _sbrk hinein. Auch wenn
> ich "step in" klicke im debugger für sprintf(...), dann passiert nichts.
> Ich komme auch nicht in sprintf(str,"test"); hinein, obwohl dies
> funktioniert.
Bei derart hartnäckigen Problemen hilft Assembler-Level Debugging. 
Benutze "stepi" im GDB um jede Instruktion einzeln auszuführen. 
Irgendwann wird es dann ja abstürzen/stehen bleiben/Im Fault Handler 
landen. Dann siehst du woran es gelegen hat.

von temp (Gast)


Lesenswert?

Ich tippe mal auf eine andere Baustelle. Fpu benutzt und nicht 
initialisiert.


Schreib das mal an den Anfang deines Codes:

volatile float f=1.123f;
f/=3.567f;

Wenn es dann schon abschmiert hast du die Ursache.

von temp (Gast)


Lesenswert?

in OpenSTM32 muss da wenn ich das richtig sehe

__FPU_USED=1

definiert sein.
Hier ein Auszug aus der system_stm32f4xx.c

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
  /* Reset the RCC clock configuration to the default reset state ------------*/
8
  /* Set HSION bit */
9
  RCC->CR |= (uint32_t)0x00000001;
10
11
  /* Reset CFGR register */
12
  RCC->CFGR = 0x00000000;
13
14
  /* Reset HSEON, CSSON and PLLON bits */
15
  RCC->CR &= (uint32_t)0xFEF6FFFF;
16
17
  /* Reset PLLCFGR register */
18
  RCC->PLLCFGR = 0x24003010;
19
20
  /* Reset HSEBYP bit */
21
  RCC->CR &= (uint32_t)0xFFFBFFFF;
22
23
  /* Disable all interrupts */
24
  RCC->CIR = 0x00000000;
25
26
#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
27
  SystemInit_ExtMemCtl(); 
28
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
29
30
  /* Configure the Vector Table location add offset address ------------------*/
31
#ifdef VECT_TAB_SRAM
32
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
33
#else
34
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
35
#endif
36
}



__FPU_PRESENT wird an anderer Stelle automatisch gesetzt wenn 
__FPU_USED=1 definiert ist.

Oder kommentier das #if und #endif vor und nach

    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 
Full Access */

aus. Bin mir zu 95% sicher dass das dein Problem ist!

von Sebastian T. (sebastian_tsch)


Lesenswert?

temp schrieb:
> Bin mir zu 95% sicher dass das dein Problem ist!

Wow, vielen Dank, genau das war das Problem. Ich verwende Openstm32 und 
die syscalls.c sowie die system_stm32f4xx.c wurden automatisch erzeugt. 
In SystemInit() hat SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); 
komplett gefehlt.

Grüsse und Danke
Sebastian

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.