Forum: Compiler & IDEs gcc-arm-embedded Startup-Code


von David L. (david_l)


Lesenswert?

Hi,

Ich bin gerade dabei, meinen Einstieg in die ARM Cortex-M uCs zu finden. 
Und masochistisch veranlagt wie ich nunmal bin, habe ich mir statt eines 
Demoboards einfach einen STM32F103 geholt und mir einen dazu passenden 
Adapter auf Buchsenleisten gebastelt, und zudem gänzlich auf eine IDE 
zur Programmierung verzichtet, sondern stattdessen die 
"gcc-arm-embedded" Toolchain auf der Konsole benutzt. Nach stundenlangem 
Durchackern von Manuals zu Linkerskripten und den Startup-Scripts aus 
der Standard Peripheral Library von STM hab ich es nun auch hinbekommen, 
ein paar LEDs blinken zu lassen.
Aus den paar wenigen Tutorials, die ich zu Cortex-M3 gefunden habe und 
die nicht von einer IDE ausgehen, habe ich die GCC-Option -nostartfiles 
entnommen, und nachdem ich ein bisschen eigenen Startup-Code geschrieben 
habe, scheint das auch irgendwie zu funktionieren. Nun frage ich mich 
aber, wie lange das wohl noch so bleibt, denn in meinem Startup-Code 
mache ich nichts anderes, als .data aus dem ROM ins RAM zu laden und 
.bss mit Nullen zu füllen, danach rufe ich die SystemInit-Funktion der 
StdPeriphLib und schließlich main() auf. Was da vollkommen fehlt ist die 
Initialisierung der libc.

Deshalb meine Frage: Ist es sinnvoll, überhaupt -nostartfiles zu 
benutzen? Wenn ja, was muss ich in meinem Startup-Code dann noch tun, um 
eine funktionierende libc zu haben? Und wenn nicht: Sorgt GCC dann für 
den kompletten Startup-Code, oder muss ich trotzdem noch Teile selbst 
schreiben?


Danke im Voraus!

von W.S. (Gast)


Lesenswert?

Es kommt alles ein bissel auf deinen Programmierstil an. Wenn du drauf 
pochst, vorinitialisierte statische Variablen haben zu wollen, dann mußt 
du selbige eben vom ROM in den RAM laden, ansonsten kannst du dir diesen 
Zirkus schenken. Ich benutze sowas grundsätzlich nicht und gehe immer 
davon aus, daß eben alle Variablen vor Benutzung irrelevante Daten 
enthalten.

Allenfalls wäre da noch das generelle Ablöschen des verwendeten RAM's 
mit null, weil einige grandiose Programmierer (z.B. Chan mit seinem 
Fat-Filesystem) das einfach voraussetzen. Rechthaberische Schlampen 
eben.

Ich schreib mir meinen Startupcode eigentlich immer selber, weil mir 
die Startupcodes von diversen Toolherstellern zu blöde sind.

Kleines Beispiel: unaufgelöste Interrupts und Exceptions landen bei den 
meisten Leuten schlicht auf einem "B ." und das ist m.E. das 
Allerblödeste was man tun kann. Im Fehlerfalle friert der ganze µC 
einfach ein ohne noch irgendwie reagieren zu können. Ich mach es anders, 
ich lade ne Fehlerzelle mit einem entsprechenden Fehlercode und löse nen 
Warmstart aus. Dann kann main immer noch nachschauen, ob es ne Exception 
gegeben hat, selbiges auf irgendeinem Kanal melden (UART oder so), alles 
wieder initialisieren und dann weitermachen. So bleibt der µC 
arbeitsbereit auch dann, wenn man irgendwas ihn aus der Bahn geworfen 
hat.

W.S.

von Lutz M. (themroc)


Lesenswert?

David L. schrieb:
> Und masochistisch veranlagt wie ich nunmal bin, habe ich mir statt eines
> Demoboards einfach einen STM32F103 geholt und mir einen dazu passenden
> Adapter auf Buchsenleisten gebastelt, und zudem gänzlich auf eine IDE
> zur Programmierung verzichtet, sondern stattdessen die
> "gcc-arm-embedded" Toolchain auf der Konsole benutzt.

Wieso "masochistisch veranlagt"? Das ist genau die richtige Methode, so 
machen das eche Männer. Schön das es noch so welche gibt, und wir es 
hier nicht nur noch mit diesen IDE-benutzenden Waschlappen, 
Warnhinweislesern und Sozialdemokraten zu tun haben.

Allerdings brauchen eche Männer auch keine libc.
Oder nen gcc, die tippen nur
1
cat>a.hex

HTH

von Karl (Gast)


Lesenswert?

cat?
Programmieren auf Dateisystemebene?

Also ich benutz als Editor immer dd, da hast du eigentlich am meisten 
Freiheiten...

von Jürgen (jliegner)


Lesenswert?

Damit es hier in Thread mal wieder sinnvoll weiter geht:

Ja, ich tue mir das auch an und schreibe (oder modifiziere) den Startup 
auch selbst. Neben der Vectortabelle und den Irq-Defaulthandlern ist 
eigentlich nur nur das Datensegment und bss zu initialisieren. 
Irgendwelche Initialisierungen der newlib sind meistens nicht nötig. 
Falls du allerdings C++ verwendest müssen auch alle Constructoren von 
globalen Classen vor der main-Funktion abgearbeitet werden. Das macht 
z.B. die Funktion
1
  __libc_init_array();
Die benötigt allerdings ein paar Segmente in der ld mit festen Namen. In 
etwa so:
1
    /* C++ constructors etc */
2
    . = ALIGN(4);
3
    KEEP(*(.init))
4
    
5
    . = ALIGN(4);
6
    __preinit_array_start = .;
7
    KEEP (*(.preinit_array))
8
    __preinit_array_end = .;
9
    
10
    . = ALIGN(4);
11
    __init_array_start = .;
12
    KEEP (*(SORT(.init_array.*)))
13
    KEEP (*(.init_array))
14
    __init_array_end = .;
15
    
16
    KEEP(*(.fini));
17
    
18
    . = ALIGN(0x4);
19
    KEEP (*crtbegin.o(.ctors))
20
    KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
21
    KEEP (*(SORT(.ctors.*)))
22
    KEEP (*crtend.o(.ctors))
23
    
24
    . = ALIGN(0x4);
25
    KEEP (*crtbegin.o(.dtors))
26
    KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
27
    KEEP (*(SORT(.dtors.*)))
28
    KEEP (*crtend.o(.dtors))
29
    /* End C++ */
30
    } > Flash
In der SystemInit wird häufug nur der Takt vom internen rc-Oszillator 
auf Quarz und PLL gestellt und die globale Variable SystemCoreClock 
belegt. Wenn man in die CPU einsteigen will, kann man sich diese Parts 
auch gleich noch anlernen. Dann guckt man später nicht wies's Schwein 
ins Uhrwerk wenn mal ein Takt geändert werden soll...
Ich muss aber dazu sagen, printf pflege ich selbst und auch new und 
delete leite ich auf die Funktionen der heap4.c (FreeRTOS) wenn es 
benötigt wird. So erspare ich mir das Implementieren der Funktionen die 
die newlib sonst erwartet.
Ich verwende CrossWorks zum Debuggen und habe die Projekte in 2 Formen. 
Einmal mit den Libs und dem Projektfile von Crossworks zum anderen als 
makefile mit den gnu-arm-tools. Die Crossworks XML-Projektfiles sind 
leichter zu bearbeiten als ein makefile. Das rumklicken in der IDE hasse 
ich auch wie die Pest. Das gibt mir die Sicherheit nicht von einer IDE 
abhängig zu sein.

Ich würde es begrüßen, wenn sich hier im Forum ein paar Leute 
zusammentun würden, um mal so was wie ein Standard 
Makefile+Startup+Linkerscript für die gängigsten CPUs (STM32,LPC) 
zusammenträgt. Ich wäre sicher dabei.

von Michael F. (mifi)


Lesenswert?

Hallo zusammen,

hier mal meine kleine Sammlung an Beispielen
für verschiedene CPUs. Vielleicht hilft das ja:

http://www.emb4fun.de/arm/examples/index.html

Gruß,
Michael

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.