Forum: Compiler & IDEs Seltsame Initialisierungen und Abstürze.


von Thomas Bartzick (Gast)


Lesenswert?

Hallo zusammen!

Ich habe folgendes getan:

1.) Bestehendes Keil-Projekt (zuvor erstellt mit ARMCC & Co.) mit 
Änderungen in Startups versehen und mittels Gcc compiliert (im Visual 
Studio).
Das lief dann auch nach einigen Verrenkungen recht gut. Die Option 
"-ggdb" liefert mir auch schönen Debug-Code, wie's scheint.

2.) Das Gebinde: Mittels diverser Linker-Skript-Vorlagen und der 
ausführlichen Beschreibung des "ld" habe ich mir ein STM32-Linker-Skript 
gebastelt, was meiner Ansicht nach funktionieren müsste. Kann ich auch 
auf Anfrage gerne mal posten.

Das Linken funktoiniert dann auch ohne Warnung und Fehler.
Ich lade das Programm mittels ULINK2 auf mein MCBSTM32E (bestückelt mit 
STM32F103ZE) und gehe in den Debugger (und ja, der Debugger akzeptiert 
das anscheinend, zu meiner größten Überraschung).

Das Programm läuft in meine liebliche main()-Routine und ich steppe 
frohen Mutes durch die ersten Funktoinen (RCC_Init, GPIO_Init...). Und 
jedoch: Just im UART_Init passiert es dann in einer der Unterfunktionen, 
die den UART einstellen: Die Baudrate hat total krude Werte.

Ich hatte im Laufe meiner Versuche das Vergnügen, irgendeine 
Konstellation im Linker-Skript (denn nur dort habe ich dann noch 
Änderungen vorgenommen) zu haben, die mir eine gültige 
UART-Konfiguration ermöglichten. Später dann, mit der endgültigen 
Fassung aber nicht mehr. Ich muss also etwas "verschlimmbessert" haben, 
und weiß nicht was.

Ich konnte die fehlerhafte Baudraten-Konfiguration auf ein 
Variablen-Feld im Modul für die UART-Konfiguration (keine Lib, 
Bestandteil des bestehenden Projekts, also quasi selsbtgetrickt und mit 
ARMCC voll funktionsfähig) zurückführen. Dort stehen definitiv bei jedem 
Run mittels Gcc-Umgebung eben falsche Werte drin.

Das verhält sich ungefähr so: Modul UART.c:
static aucWichtigWerte[] = {0, 1, 2, ..., n}.

{
   blah;
   blubb;
   Baudrate = {Rechnerei, mittsl aucWichtigWerte};
]
... Ende des Moduls.
Nur, dass da statt 0, 1, 2,... 13, 76, 7, usw. drin steht, wenn ich mit 
dem Debugger das Modul betrete.

Meine Schlussfolgerung: Aufgrund eines Fehlers im Linker-Skript geht die 
Variablen-Initialisierung schief!
Ich poste das Skript auch gerne mal, habe es nur gerade nicht greifbar. 
Grundsätzlich muss ich aber doch folgendes tun:

.text-Sektion
.data-Sektion
.bss-Sektion

festlegen; sowie evtl. zu exporierender Symbole... Oder ist da bereits 
ein Denkfehler?
Müssen evtl. noch weitere Sektionen definiert werden? Oder muss ich in 
der Daten-Sektion mittels "KEEP" festlegen, dass mir auch nicht explizit 
referenzierte Variablen erhalten bleiben; wobei ich diese Option, 
ehrlich gesagt, noch nicht ganz verstanden habe.

Naja, vielleicht hat ja jemand eine Idee. Vielen Dank im voraus!

Thomas.

von Fabian O. (xfr)


Lesenswert?

Stammen die in der Berechnung verwendeten Variablen aus einer anderen 
C-Datei? Dann ist vermutlich dieses Problem:
https://isocpp.org/wiki/faq/ctors#static-init-order

von Thomas Bartzick (Gast)


Angehängte Dateien:

Lesenswert?

Hi Fabian,

nein, das ist es nicht.

Die Datei heisst stm32f10x_rcc.c und definiert dort das Feld:

static __I uint8_t APBAHBPrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 
3, 4, 6, 7, 8, 9};

Diese Initialisierung stimmt schon nicht, wie ich auch im Debugger sehen 
kann. Da stehen dann Werte 68,... usw. Irgendwie scheint der Linker 
nicht die korrekten Init-Werte zu übernehmen.

Ich hänge die Linker-Datei und das MAP-File einmal an. Seltsam ist, dass 
das Variablenfeld sich die Lade-Addresse mit anderen zu teilen 
scheint...
Aber vielleicht täuscht das auch. Ich gebe zu, die Tiefen des 
Gcc-Linkers sind Neuland für mich.

Gruß,

Thomas.

von Stephan (Gast)


Lesenswert?

Hi,
stimmen denn die Werte im Flash?
was steht im Hex-File?(ELF) oder vorher ins List-File schauen.
So sieht es doch IO aus. oder wo meinst du liegt der Fehler genau?
Die anderen Symbole haben aber eine Länge von 0 Byte.

von Thomas Bartzick (Gast)


Angehängte Dateien:

Lesenswert?

Stephan schrieb:
> Hi,
> stimmen denn die Werte im Flash?
> was steht im Hex-File?(ELF) oder vorher ins List-File schauen.
> So sieht es doch IO aus. oder wo meinst du liegt der Fehler genau?
> Die anderen Symbole haben aber eine Länge von 0 Byte.

Hallo Stephan,

ja, im List-File zu stm32f10x_rcc stehen die richtigen Initialwerte 
drin.
Das ELF müsste ich dahingehend mal mit einem Hex-Editor anschauen. Die 
Länge von 0 der übrigen Symbole macht mich ebenfalls nachdenklich...

Jedenfalls müsste das Array ADCPrescTable eben tatsächlich die Werte des 
List-Files haben (hänge ich an!): 0, 0, 0, 0, 1, 2, 3, 4, usw.

Es stehen dann aber Werte wie 58, 40, usw. dort, sobald ich das Modul im 
Debugger betrete.

Im Simulations-Modus des µVision funktioniert das ganz prächtig, falls 
ich dann auch im Linker-File die Anweisung weglasse, dass die 
Initialisierungswerte im ROM (APP) zu finden sind. Dann scheint sich der 
Debugger die Werte anderweitig zusammenzuklauben. Natürlich taugt das 
für das Laden ins reale Flash nicht.

Ein weiteres Phänomen ist, dass ich zwar im Einzelschritt-Betrieb in die 
einzelnen Funktionen hereinkomme, im Aufruf ("F10") jedoch in eine 
Exception gesprungen wird. Wahrscheinlich stimmen da auch weitere Sachen 
noch nicht. (Gilt nur für Betrieb mit realem STM32-Board!)


Gruß,

Thomas.

von Stephan (Gast)


Lesenswert?

Hi,
also so sieht es doch gut aus.
Kann es am Startup code liegen?
- die Daten werden ja vom Flash in den RAM kopiert (von 0x08005904 nach 
0x20000010)

Thomas Bartzick schrieb:
> Im Simulations-Modus des µVision funktioniert das ganz prächtig, falls
> ich dann auch im Linker-File die Anweisung weglasse, dass die
> Initialisierungswerte im ROM (APP) zu finden sind. Dann scheint sich der
> Debugger die Werte anderweitig zusammenzuklauben.

Das verstehe ich nicht!?!

von Oliver S. (oliverso)


Lesenswert?

>static aucWichtigWerte[] = {0, 1, 2, ..., n}.

Wenn das schiefgeht, fehlt in deinem Startupcode die Initialisierung des 
entsprechenden Speichersegments.

Oliver

von Thomas Bartzick (Gast)


Lesenswert?

Hallo Oliver & alle anderen,

es verhält sich wirklich so: Der Initialisierungscode, der angesprungen 
wird, ist anscheinend nur für Simulationsbetrieb bestimmt ("__cs3_start" 
und folgende Routinen).

Nach einem Hinweis aus dem Netz habe ich mir nun meine eigene 
Initialisierungsroutine in C-Code geschrieben, die das Problem löst.

Des Weiteren ergab sich noch das Problem, dass die 
Interrupt-Vektor-Tabelle, die ich aus einem Beispiel-Projekt übernommen 
habe nicht mit entsprechendem Code "unterfüttert ist". Wird dann ein 
Interrupt (z.B. SysTick) ausgelöst, springt der ins Leere. Dies erklärt 
auch, warum ich zwar im Einzelschritt-Betrieb debuggen konnte (auf 
realem Board), aber im Falle eines Freilaufs ins Nirvana gesprungen bin. 
Auf die schnelle habe ich daraufhin nach der Takt- IVEC und 
Timer-Initialisierung alle Interrupts verboten (da ich diese im 
Augenblick nicht benötige).

Zusammen mit besagter Initialisierungs-Routine läuft nun alles 
einwandfrei.

Gruß & Danke,

Thomas.

P.S.:
Code-Schnippsel, falls das mal jemand nachvollziehen möchte:

In der main.c:
---
//! Some linker imports.
extern  t_uint32_t                            _etext;
extern  t_uint32_t                            __cs3_region_start_ram;
extern  t_uint32_t                            __cs3_region_end_ram;

extern  t_uint32_t                            __cs3_region_start_bss;
extern  t_uint32_t                            _end;
---
Dies sind Symbole aus meinem Linker-File, die hier extern geholt werden.

Es folgt der Initialisierungs-Code:
---
int main(void)
{
    //! Configuration of the system.
    /* Configure the system clocks */
    RCC_Configuration();

    /* NVIC Configuration */
    NVIC_Configuration();

    GPIO_Configuration();
    TIMER_Configuration();

    //! Disable interrupts, therefore not used here.
  __ASM volatile ("cpsid i" : : : "memory");

    USART_Configuration();

    uprintf("\n\r");
    ...
} // main()

void Init(void) // Hier werden die Initialisierungswerte ins RAM 
kopiert. Die Regionen entsprechen dem mit *(.data)-Bereich aus dem 
Linker-File.
{
  unsigned long *src, *dst;
  /* copy the data segment into ram */
  src = &_etext;
  dst = &__cs3_region_start_ram;
  if (src != dst)
    while(dst < &__cs3_region_end_ram)
      *(dst++) = *(src++);

  /* zero the bss segment */
  dst = &__cs3_region_start_bss;
  while(dst < &_end)
    *(dst++) = 0;
}

void __cs3_start_c(void) // Hier wird auf die vom Linker erwartete 
Startup-Routine für C-Code Bezug genommen.
{
  Init();
  main();
}
--- (Mit Dank an den Autor der Vorlage aus dem Netz!)

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.