Forum: Mikrocontroller und Digitale Elektronik Keil und Startup-Code


von Jürgen G. (Gast)


Lesenswert?

Hallo,
bisher hatte ich mit einer Testversion von Rowley gearbeitet, um Code 
für meine NXP LPC2000 Mikrocontroller zu erstellen. Rowley funktionierte 
einigermassen, was mich störte war der Debugger, der nicht wirklich toll 
ist. Nun ja, wie auch immer. Ich habe da mühsam meinen eigenen 
Startup-Code zusammen gestellt, da ich einige spezielle Dinge im Startup 
noch erledigen will, bevor main() beginnt.
So, also meinen Startupcode habe ich. Nun bin ich nicht zufrieden mit 
Rowley und habe mir mal eine Testversion vom Keil MDK besorgt. Das sieht 
schon besser aus, vor allem der Debugger! Aber leider kann ich da meinen 
Rowley-Startupcode nicht benutzen. Meine Frage hierzu ist:

- wo kann ich beim Keil definieren, wo der Stack liegt?
- wo bzw. wie wird beim Keil Startup-Code das RAM initialisiert? beim 
Rowley gabs da die .bss-Section, welche mit Nullen gefüllt werden 
musste; beim Keil Startup ist nichts derartiges vorhanden. Auch eine 
memory-Copy Funktion gibt es nicht, die initialisierte Variablen ins RAM 
kopiert. Frage: wie wird das bei Keil denn gelöst?

Ich hoffe ihr könnt mir weiterhelfen, vielen Dank schon mal.

von Hugo B. (stinkywinky)


Lesenswert?

Bei der Keil-IDE sind Beispiel-Projekte für einige Boards dabei, auch 
für NXP. Dort solltest Du fündig werden.

Bei meinem Luminary-Projekt heisst das File "Startup.s".

von Jürgen G. (Gast)


Lesenswert?

Hi Hugo,
das Problem ist aber, dass ich auch bei den Beispielprojekten noch nicht 
wirklich ganz durch blicke, wie und wo der Stack definiert wird.
Wie sage ich dem Compiler z.B., dass er den Stack bitteschön an Adresse 
0x40002000 machen soll und dass der Stack 1k gross ist?
Und dann der Heap: wo lege ich den fest?
Ausserdem: wie wird das bei Keil gehandhabt mit nicht initialisierten 
Variablen (die ja dann im BSS liegen und mit 0 überschrieben werden)? 
Und müssen bei initialisierten Variablen nicht noch die 
Initialisierungswerte vom ROM ins RAM kopiert werden?
Ich finde den Part nicht, der das erledigt!
:-(

von Peter (Gast)


Lesenswert?

>- wo kann ich beim Keil definieren, wo der Stack liegt?
>- wo bzw. wie wird beim Keil Startup-Code das RAM initialisiert?

Also solche Dinge solltest Du nun wirklich dem Compiler überlassen und 
nicht selber was damit herumwursteln...!!!!!

von Jürgen G. (Gast)


Lesenswert?

> Also solche Dinge solltest Du nun wirklich dem Compiler überlassen und
> nicht selber was damit herumwursteln...!!!!!

Nöö, ich will selber festlegen können, wo der Stack liegt. Da ich ihn 
z.B. gerne ins externe SRAM legen würde. Das ist grösser. Ausserdem: 
wenn der Compiler den Stack selber bestimmt, dann macht er ihn irgendwie 
400 Bytes gross oder so. Das ist doch Murks! Wenn ich schon 1 MByte RAM 
zur Verfügung habe, soll er das gefälligst auch gescheit nutzen.
Dasselbe gilt natürlich für den Heap. Da ich mittels selber 
geschriebenem Memory Manager dynamischen Speicher alloziiere, brauche 
ich auch einen ordentlichen Heap. Mit diesen Standard-Dingern, die ein 
paar 100 Bytes gross sind, kann ja keiner was anfangen!

von Martin T. (mthomas) (Moderator) Benutzerseite


Lesenswert?

Vom Nutzer wird eine Funktion __user_initial_stackheap bereitgestellt. 
Diese wird von __main (einer library Funktion) aufgerufen und setzt 
R0-R4 auf die Adressen für head und stack. __main kümmmert sich auch um 
data-copy, bss-init und ruft schliesslich main. Im eigenen startup ruft 
man __main (ARM library-code) statt main (eigenem C-Code). (Ist aber 
nichts, was nicht auch in der Dokumentation beschrieben wäre).

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

Jürgen G. schrieb:
> Da ich ihn z.B. gerne ins externe SRAM legen würde. Das ist
> grösser. Ausserdem: wenn der Compiler den Stack selber bestimmt,
> dann macht er ihn irgendwie 400 Bytes gross oder so. Das ist doch
> Murks! Wenn ich schon 1 MByte RAM zur Verfügung habe, soll er das
> gefälligst auch gescheit nutzen.

Denk daran, dass auf den Stack sehr häufig zugegriffen wird. Ich würde
wahrscheinlich eher das ganze interne RAM für den Stack reservieren,
bevor ich auf externen Speicher ausweiche. Vorausgesetzt natürlich
Dein Stack passt überhaupt in den internen Speicher. Bei einer CPU
ohne Cache würde ich mir jedenfalls sehr genau überlegen, wo bestimmte
Bereiche im Speicher angelegt werden. Womit wir wieder bei der
eigentlichen Frage wären:

Keil verwendet ein etwas umständliches Verfahren, um Stack und Heap zu
definieren. Letztlich sind das Konstanten im Startup.s, die aber über
den "Configuration Wizard" dieser Datei einfach konfiguriert werden
können.

Keil nutzt hier leider nicht die Möglichkeit, das über spezielle
Linker Regionen (ARM_LIB_STACK, ARM_LIB_HEAP) im Scatter file zu
definieren. RealView Tools seit Version 3.0 unterstützen das. Das hat
man halt davon wenn man IDEs verwendet :-)

Gruß
Marcus
http://www.doulos.com/arm

von Jürgen G. (Gast)


Lesenswert?

Hi,
danke für eure Posts, Martin und Marcus.

@Martin:
Wo finde ich das mit dem __main? Ich habe sehr wohl in der Onlinehilfe 
gesucht, aber vielleicht nicht nach dem richtigen Begriff.
Kann man sich irgendwo anschauen, was die Funktion __main denn macht? 
Ich will meinen eigenen Startupcode benutzen, nicht irgend einen anderen 
der beim Keil dabei ist. Bei Crossworks ging das, dort konnte man alle 
Dinge, die eigentlich Fest im Projekt eingestellt wurden, trotzdem 
irgendwie aushebeln und selber schreiben. Und genau DAS will ich machen! 
Ein Argument, was sehr für Rowley spricht. Der Debugger da ist einfach 
schlecht und funktioniert nicht zufrieden stellend mit dem J-Link 
zusammen.
Kann ich beim Keil auch irgendwie selber einen Startup-Code integrieren? 
bzw. dieses __main durch mein eigenes ersetzen.

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

Jürgen G. schrieb:
> Wo finde ich das mit dem __main? Ich habe sehr wohl in der Onlinehilfe
> gesucht, aber vielleicht nicht nach dem richtigen Begriff.

Ähh, __main im Suchfenster eingegeben? ;-)

http://infocenter.arm.com/help/topic/com.arm.doc.dui0203i/index.html

Hilfreich ist auch das hier
http://infocenter.arm.com/help/topic/com.arm.doc.dui0349b/index.html

Diese Links beyiehen sich genaugenommen auf die "große" ARM tool chain
(RVDS), die Compiler Tools sind aber weitestgehend identisch. Die
entsprechende Keil Doku findest Du etwas weiter unten. Die ist aber je
nach verwendeter MDK Version nicht ganz aktuell. Außerdem gibt's bei
Keil den Developer Guide nicht, in dem das alles erklärt wird.

> Kann man sich irgendwo anschauen, was die Funktion __main denn macht?
> Ich will meinen eigenen Startupcode benutzen, nicht irgend einen anderen
> der beim Keil dabei ist.

Warum? Was ist an Deinem Projekt so speziell? Was genau meinst Du
eigentlich mit Startup code -- den von Keil implementierten Reset
Handler, oder das C library startup?

> Bei Crossworks ging das, dort konnte man alle Dinge, die eigentlich
> Fest im Projekt eingestellt wurden, trotzdem irgendwie aushebeln und
> selber schreiben. Und genau DAS will ich machen!

Normalerweise endet der Reset Handler in einem Sprung nach __main. Du
kannst stattdessen einfach eine andere Funktion aufrufen.

> Kann ich beim Keil auch irgendwie selber einen Startup-Code integrieren?
> bzw. dieses __main durch mein eigenes ersetzen.

s.o.

Gruß
Marcus
http://www.doulos.com/arm/

von Jürgen G. (Gast)


Lesenswert?

Hi Marcus,
dass der Startupcode normalerweise beim __main-Call endet ist mir klar. 
Was ich machen will: ich habe meinen eigenen Startupcode geschrieben. 
Der hat z.B. auch einen Dispatcher für alle Interrupts, erlaubt die 
Verwendung von SWI's mittels eines Dispatchers und hat noch ein paar 
andere lustige Spielereien drin, die ich einfach haben will. Deshalb 
will ich diesen Startupcode verwenden und nicht den von Keil.
Aber mein Problem ist jetzt, dass der Startupcode ja auch das bss-Memory 
mit 0 initialisieren soll und dass er bestimmte Daten vom ROM ins RAM 
kopieren soll. Und beim Keil weiss ich nicht, wo welche Daten kopiert 
werden müssen oder wo das .bss liegt.

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

Jürgen G. schrieb:
> Was ich machen will: ich habe meinen eigenen Startupcode geschrieben.
> Der hat z.B. auch einen Dispatcher für alle Interrupts, erlaubt die
> Verwendung von SWI's mittels eines Dispatchers und hat noch ein paar
> andere lustige Spielereien drin, die ich einfach haben will. Deshalb
> will ich diesen Startupcode verwenden und nicht den von Keil.

Und das brauchst Du alles vor main()? Kannst Du nicht aus main() als
erstes noch Deinen Code aufrufen? Welche Aufgaben sind so wichtig,
dass sie nicht die paar Mikrosekunden warten können?

> Aber mein Problem ist jetzt, dass der Startupcode ja auch das bss-Memory
> mit 0 initialisieren soll und dass er bestimmte Daten vom ROM ins RAM
> kopieren soll. Und beim Keil weiss ich nicht, wo welche Daten kopiert
> werden müssen oder wo das .bss liegt.

Das .bss heißt bei ARM ZI (Zero Initialize, uninitialisierte
Variablen) und schließt normalerweise an die RW (initialisierte
Variablen) Region an. Der ARM Compiler optimiert hier aber, so dass
nicht unbedingt ein ZI erzeugt wird.

Meine Frage wurde ja noch nicht beantwortet:
>> Was genau meinst Du eigentlich mit Startup code -- den von Keil
>> implementierten Reset Handler, oder das C library startup?

Also eigentlich willst Du den Reset Handler neu implementieren, oder?
Da sich Teile des neuen Codes auf korrekt kopierte Daten/Code
verlassen, muss der neue Reset Handler auch das Scatter Loading
enthalten, da er nicht warten kannst bis der entsprechende Code (aus
der C library) sowieso ausgeführt wird. Ist dieses Problem nicht
rekursiv?

Gruß
Marcus
http://www.doulos.com/arm/

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.