Forum: Mikrocontroller und Digitale Elektronik STM32F4 Linker Scripte: Ich will es jetzt kapieren!


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Christian J. (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

sorry für die provokative Überschrift aber einmal muss man es ja mal 
checken :-)

Ich habe intuitiv rumgefrickelt, reiner Blindflug weil ich von der 
Syntax nichts verstehe und nur ahnen kann und mein Problem mit den Lib 
Funktionen rand, printf, malloc usw gelöst.

Es fehlte das im Script, irgendwoher abgeguckt

    /* Pointers to end of data for dynamic memory management */
    PROVIDE (end = _ebss);
    PROVIDE (_end = _ebss);

(Das Original EmBlocks Script läuft jedenfalls so nichtm, zumindest 
nicht mit dem GCC den ich habe)

Ist dieses Script jetzt soweit ok? Fehlt da noch was? Interrupts ok? 
Heap ok?
Es gibt nämlich noch andere Varianten, zb bei Atollic Studio: Da sieht 
der Anfang so aus. Übernehme ich .isr_vector kommt auch kein Fehler, 
lasse ich es weg passiert auch nichts.

Was dieses NOLOAD besagt weiss ich nicht, auch hier ändert sich 
scheinbar nichts am Ablauf eines Programmes.

Aber so völlig munter drauflos kann es ja nun nicht gehen, es muss da ja 
schon sowas wie eine "richtige Konfiguration" geben.

Kann da mal jemand drüberschauen? Anlage ist Startupcode in C.

Anfang des Atolic Scriptes:

 /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(4);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(4);
  } >FLASH

  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(4);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH



Mein aktuelles Script für FlashDebug
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")

/* Internal Memory Map*/
MEMORY
{
   rom (rx)    : ORIGIN = 0x08000000, LENGTH = 0x00100000  /* 2MB */
   ram (rwx)   : ORIGIN = 0x20000000, LENGTH = 0x00020000  /* 128 kb*/
   ccram (rwx) : ORIGIN = 0x10000000, LENGTH = 0x00010000  /* 64kb */
   sdram (rwx) : ORIGIN = 0xD0100000, LENGTH = 0x00700000  /* 7 MB */
}

/* Section Definitions */
SECTIONS
{
     .text :
     {
       KEEP(*(.isr_vector .isr_vector.*))
       *(.text .text.* .gnu.linkonce.t.*)
       *(.glue_7t) *(.glue_7)
       *(.rodata .rodata* .gnu.linkonce.r.*)
     } > rom

    .ARM.extab :
    {
        *(.ARM.extab* .gnu.linkonce.armextab.*)
    } > rom

    .ARM.exidx :
    {
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    } > rom

    . = ALIGN(4);
    _etext = .;
    _sidata = .;

    .data : AT (_etext)
    {
        _sdata = .;
        *(.data .data.*)
        . = ALIGN(4);
        _edata = . ;
    } > ram

    /* .bss section which is used for uninitialized data */
    .bss (NOLOAD) :
    {
        _sbss = . ;
        __bss_start__ = _sbss; /* define a global symbol at bss start */
        *(.bss .bss.*)
        *(COMMON)
        . = ALIGN(4);
        _ebss = .;         /* define a global symbol at bss end */
        __bss_end__ = _ebss;
    } > ram

    /* User_heap_stack section */

    ._user_heap_stack :
    {
      . = ALIGN(4);
      PROVIDE ( end = . );
      PROVIDE ( _end = . );
      . = ALIGN(4);
    } >ram

    /* stack section */
    .co_stack (NOLOAD):
    {
        . = ALIGN(8);
        *(.co_stack .co_stack.*)
    } > ram

    /* ----- User defined areas ------ */

    /* 64kb CC RAM */
    .ccram (NOLOAD):
    {
        . = ALIGN(4);
        *(.ccram)
    } > ccram

    /* 8MB externes SDRAM */
      .sdram (NOLOAD):
    {
        . = ALIGN(4);
        *(.sdram)
    } > sdram

    . = ALIGN(4);
    _end = . ;

    /* Pointers to end of data for dynamic memory management */
    PROVIDE (end = _ebss);
    PROVIDE (_end = _ebss);

    /* Remove debugging from standard libraries */
    /DISCARD/ :
    {
        libc.a (*)
        libm.a (*)
        libgcc.a (*)
    }
 }

von W.S. (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Wenn ich deinen "Startup"-C-Code sehe, wird mir schlecht.

Also, erstmal:
Du benutzt vermutlich den GCC, ja?
Für den brauchst du eigentlich GARKEIN Linker-Script, weil der 
zugehörige Linker bereits sowas eingebaut hat. Allerdings MUSST du dazu 
erstmal deinen eigentlichen Startupcode in ASSEMBLER schreiben 
(jajajaja!) und dem dortigen Codesegment einen passenden Namen geben, so 
daß es als allererstes ab 0 gelinkt wird. (den Namen hab ich nicht 
auswendig gelernt, guck dir das Zeugs in der Lernbetty an)

Eigentlich ist das garnicht so schwer, allerdings hatte ich damals mit 
der Lernbetty auch schwer mit diversen schlecht/un-dokumentierten 
Fallstricken beim GCC zu kämpfen. Mit dem Keil geht das wesentlich 
einfacher. Ach lade dir die Lernbetty mal hier aus dem Forum herunter 
und guck dort, wie das Ganze mit dem GCC geht.

Du mußt dann lediglich nen anderen Kern angeben, also nicht ARM7TDMI, 
sondern deinen Cortex und du mußt im Startupcode eben die Vektortabelle 
hinschreiben, dazu die [WEAK] Dummies und fertig.

W.S.

von Dr. Sommer (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ach W.S., vielleicht lernst du es irgendwann mal...

> Für den brauchst du eigentlich GARKEIN Linker-Script, weil der
> zugehörige Linker bereits sowas eingebaut hat.
Nur leider keins für den STM32.

> Allerdings MUSST du dazu
> erstmal deinen eigentlichen Startupcode in ASSEMBLER schreiben
Schwachsinn, das geht wunderbar in C.

> und dem dortigen Codesegment einen passenden Namen geben, so
> daß es als allererstes ab 0 gelinkt wird.
Auch Unsinn, der Startupcode kann sonstwo sein, solange der 
Reser_Handler da richtig drauf zeigt. Ein "Codesegment" gibts nicht im 
GCC/ARM Kontext.

An den OP:
Nimm doch den Startupcode und das Linkerscript von/für Atollic, das hat 
bis jetzt immer wunderbar mit GCC funktioniert. Wenn es das noch 
Probleme macht, sag Bescheid...

von Pit S. (pitschu)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Christian,
die kryptische Syntax der Linker-Scripts ist im entsprechenden GNU 
manual gut dokumentiert (google nach gnu linker manual). Ich verwende 
meistens als Vorlage für z.B. den STM32F429 die Templates aus der 
STM-Cube Sammlung. Z.B. unter 
"STM32Cube_FW_F4_V1.3.0\Projects\STM32F429I-Discovery\Templates\TrueSTUD 
IO"  findet sich ein generisches linker script. Da TrueStudio auch auf 
der gcc-Toolchain aufsetzzt, kann man die eigentlich ohne Änderungen 
verwenden. Für STM32F1 etc. findet man entsprechende Templates in 
anderen ST-Sammlungen.

Passender Startup Code ist auch gleich dabei, allerdings ASM, ich 
bevorzuge da auch lieber C-Versionen.

pitschu

: Bearbeitet durch User
von Christian J. (Gast)


Angehängte Dateien:
  • crt0.s (6,01 KB, 212 Downloads)

Bewertung
0 lesenswert
nicht lesenswert
Peter Schulten schrieb:
> unter
> "STM32Cube_FW_F4_V1.3.0\Projects\STM32F429I-Discovery\Templates\TrueSTUD
> IO"  findet sich ein generisches linker script. Da TrueStudio auch auf
> der gcc-Toolchain aufsetzzt, kann man die eigentlich ohne Änderungen
> verwenden.

Hi,

ich habe mir genau diese beiden Files mal zur Brust genommen und sie 
eingefügt. Das RamDebug entsprechend verändert, so dass kein Flash Code 
mehr erzeugt wird. Und meine Dinge auch eingefügt, da ich SDRAM als 
Section haben möchte und auch das Backup Ram als Section Memory Bereich.

Klappt soweit alles. Ok, gestern lief es auch aber das hier ist mir 
verständlicher und auch "geprüfter".

Hoffe meine Änderung für die Hardware FPU ist richtig. Vorher stand da 
softvfp

 .syntax unified
  .cpu cortex-m4
  .fpu fpv4-sp-d16
  .thumb

Ein Test mit volatile Vars sieht aus als wenn da eine FPU verwendet 
würde.....

20003824  vldr  s14, [r7, #12]
20003828  vldr  s15, [r7, #8]
2000382C  vmul.f32  s15, s14, s15
20003830  vstr  s15, [r7, #4]
20003834  vldr  s15, [r7, #4]
20003838  vcvt.u32.f32  s15, s15


Sorry, dass ich auf WS ncht näher eingehe aber wir leben in einer 
anderen Welt wie ich früher schon merkte. Ich kaufe mir kein Auto, damit 
ich dieses erst fahren kann, nachdem ich einen Werkstatt Kursus besucht 
habe und genau verstanden haben muss, wie der Motor arbeitet. Ich möchte 
auch keine "Lernbetty" weil ich hier das Disco Board habe. Ich möchte 
den Zündschlüssel rumdrehen und losfahren.

@WS: Im Anhang ist auch ein Startup Code von mir, 99% selbst 
geschrieben. Läuift perfekt. Wird dir da auch schlecht?

von Ivolle (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Ich kaufe mir kein Auto, damit
> ich dieses erst fahren kann, nachdem ich einen Werkstatt Kursus besucht
> habe und genau verstanden haben muss, wie der Motor arbeitet.

Dann ist ein Evalboard das falsche Produkt.

von Eric B. (beric)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Ich kaufe mir kein Auto, damit ich dieses erst fahren kann,
> nachdem ich einen Werkstatt Kursus besucht habe und genau
> verstanden haben muss, wie der Motor arbeitet.

Aber das ist doch genau was du in deinem "provokativer" Betreff 
schreibst: du willst jetzt kapieren wie der Motor funktioniert!?

von Christian J. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Eric B. schrieb:

> en haben muss, wie der Motor arbeitet.
>
> Aber das ist doch genau was du in deinem "provokativer" Betreff
> schreibst: du willst jetzt kapieren wie der Motor funktioniert!?

Ok.... sagen wir es mal so: Wirklich kapiert habe ich es nicht aber das 
Map File zeigt mir, dass es funktioniert. Viel macht der Startup ja 
nicht: Stack setzen, Vektortabelle einrichten, Initialisierte Variablen 
umkopieren.

Was mir noch rätselhaft ist wann die Umschaltung passiert, das Flash von 
0x0 auf 0x08 zu mappen. Passiert das vorher oder nach dem Startup?

von Dr. Sommer (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> Was mir noch rätselhaft ist wann die Umschaltung passiert, das Flash von
> 0x0 auf 0x08 zu mappen. Passiert das vorher oder nach dem Startup?
Es ist genau anders rum: Der Flash ist immer bei 0x08000000 
eingeblendet. Falls die BOOT0 und BOOT1 Pins richtig gesetzt sind, 
wird der Flash zusätzlich bei 0x0 eingeblendet; falls nicht wird der RAM 
oder der System Memory (= ROM mit Bootloader drin) bei 0x0 eingeblendet. 
Dann liest der Controller den initialen Stack Pointer von Adresse 0x0 
und setzt ihn (daher muss, anders als zB beim AVR, der Startupcode den 
Stack Pointer nicht setzen), und liest die Adresse des Reset Handlers 
aus Adresse 0x4 und startet diesen.
Alles dokumentiert im Reference manual, Kapitel "Memory and Bus 
architecture" -> "Boot configuration".

von W.S. (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Christian J. schrieb:
> @WS: Im Anhang ist auch ein Startup Code von mir, 99% selbst
> geschrieben. Läuift perfekt. Wird dir da auch schlecht?

Nö - ich hab schon lange keinen Z80 mehr angefaßt. Aber für nen STM32 
dürfte das ne völlig falsche Nummer sein.

Christian J. schrieb:
> Ok.... sagen wir es mal so: Wirklich kapiert habe ich es nicht aber das
> Map File zeigt mir, dass es funktioniert. Viel macht der Startup ja
> nicht: Stack setzen, Vektortabelle einrichten, Initialisierte Variablen
> umkopieren.

Christian J. schrieb:
> Sorry, dass ich auf WS ncht näher eingehe aber wir leben in einer
> anderen Welt wie ich früher schon merkte. Ich kaufe mir kein Auto, damit
> ich dieses erst fahren kann, nachdem ich..


Ah, ja. So langsam kommen wir der Sache näher: "Wirklich kapiert habe 
ich es nicht" muß ich das noch kommentieren?

Du befindest dich übrigens NICHT in der Position des Autokäufers, 
sondern in der Position des Mechanikers in der Entwicklungswerkstatt.

Deine Frau würde sich in der Käufer-Position befinden, wenn sie einen 
von dir entwickelten MP3-Player im Laden kaufen würde.


Weißt du, von Leuten, die derart oberflächlich an die Sache herangehen, 
habe ich eine ausgesprochen schlechte Meinung. Das ist der Wille zum 
Nicht-Verstehen-Wollen.

Stattdessen kann ich deine hier kundgetane Ansicht mal so 
zusammenfassen: "Man mache es mir, daß es geht". Aber auf diese Weise 
wird niemand ein guter Ingenieur oder Entwickler oder Programmierer, 
sondern eben immer nur ein Scharlatan.

Intellekt ist "geistiges Vermögen, durch Denken zu Erkenntnis zu 
kommen." und dazu gehört eben, daß man die Dinge, mit denen man was 
entwickeln will, auch verstehen will. Du tätest gut daran, deinen zu 
befördern, anstatt dich auf den scheinbar leichteren Weg des Copy&Paste 
zu begeben.

So, ich hänge dir mal einen (älteren) Startupcode zur Ansicht hier dran, 
einschließlich dessen, was man beim Keil als so eine Art Entsprechung 
des GCC-Linkerscriptes auffassen könnte. (XCL = eXtended Command Line) 
Jaja, viel mehr braucht man beim Keil-Linker zum Linken nicht.

Der Startupcode war mal für ein Evalboard und enthält übrigens noch nen 
Fehler: beim Restart nach Systemfaults setzt er den SP nicht zurück. Und 
er ist für nen Cortex M3.


W.S.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.