STM32F4 sprintf Problem

OP #4748817
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
}
OP #4748877
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
}
Gast #4749252
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?
Gast #4749280
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?
#4749335
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.
OP #4749599
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
}
Gast #4749686
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.
Gast #4751759
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?
OP #4771908
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
Angehängte Dateien:
Gast #4771920
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.
Gast #4771932
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.
OP #4771935
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
OP #4771938
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.
Gast #4771996
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?
Gast #4771997
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.
Gast #4772014
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.
OP #4772021
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.
Gast #4772068
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.
Gast #4772087
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.
Gast #4772096
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.
Gast #4772198
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.
Gast #4772262
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!

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