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.
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".
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!
:-(
>- 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...!!!!!
> 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!
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).
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
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.
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/
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.
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/