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!
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.
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
cat? Programmieren auf Dateisystemebene? Also ich benutz als Editor immer dd, da hast du eigentlich am meisten Freiheiten...
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.