Hallo.
Ich habe hier ein C++ Projekt auf einem Mikrocontroller!
Dieser hat externen ram und der Heap ist dorthin ausgelagert.
Nun ist das Problem:
Entweder ich nutze den C-Startupcode, den ich als ASM habe - dort kann
ich editieren, dass zuerst mein Speicher initilaisiert wird, bevor der
Heap (.bss und .data) initialisiert wird. Nachteil ist, dass nun die
Konstruktoren der statischen Variablen nicht mehr aufgerufen werden.
Ich würde gerne C++ dazu bringen direkt nach dem Reset aber VOR der
Initialisierung von .bss und .data einige
Hardweareinitialisierungs-Funktionen aufzurufen.
Ich hab nen AVR32 AP7000 (GCC)
Es MUSS irgendwie gehen.
MFG
Haben die Linkerscripts beim AVR32 denn keine .initN-Sections?
(N = Zahl von 1 bis 9) In diesen werden solche Initialisierungs-
aufgaben normalerweise erledigt, die C++-Konstruktoren belegen
auch eine davon. Du müsstest also im Linkerscript mal nachsehen,
welche sie belegen und dann deinen Initialisierungs-Code in einer
Section davor platzieren. Aber Vorsicht, da ist u. U. der Stack
noch nicht initialisiert, normalerweise baut man dort nur ,,flache''
Codestücke ein, keine Funktionen mit CALL/RET. In C kann man
derartige Funktionen mit dem Attribut `naked' erzeugen, was aber
gelegentlich auch Fallstricke mit der Optimierung bringen kann,
siehe Beitrag "GCC Startet nicht main() auf Mega168"
(wichtig ist das KEEP bei .init0, sonst wird die Funktion
weggeschmissen.. die ruft ja niemand auf.)
Dann hab ich einen Code geschreiben, der während einer normalen
C-initilaisierung genommen würde:
Dieser Code wird jetzt sofrot am Anfang eingefügt. Der Stackpointer ist
initlaisiert - das erlaubt zumindest Funktionsaufrufe. Hier der Fall
<InitGPIOs> und <InitRam>. Prinzipiell kann man dann dort alles
reinschreiben was man will, wie es scheint. Der normale .reste-Code wird
dann einfach hinten rangehängt.
Geht alle sproblemlos bis jetzt. :-)
Danke, war eine Hilfe, auch wenn ichs zum schluss selbst geschafft habe.
Die Nummer mit den Init-Sections wie in der avr-libc geht wie wie
mittlerweile wissen schon bei den AVRs u.U. in die Hose, weil Funktionen
nicht zwingend dort aufhören wo man es gerne hätte. Drum ist ist mir
diese Methode im Startup von beispielsweise ARMs auch noch nicht
begegnet. Kann ich nicht wirklich empfehlen.
Man kann aber jederzeit in den Startup-Code generell einen bestimmten
Funktionsaufruf (z.B. __initHardware) einfügen. Will man diese Funktion
nicht immer verwenden, dann definiert man weiter unten in Startup eine
"weak" Funktion dieses Namens die nur aus einem Return besteht. Die
greift, wenn sich sonst niemand gleichen Namens findet.
Naja das problem: wie fügt man denn einen bestimmten Funktoinsaufruf so
ein, dass er nicht u.U in die Hose geht??
Man bemerke: der Startupcode liegt also lib vor. Also im Code
rumschreiben is nicht.
Ich bin eigentlich ganz zu frieden damit, muss ich sagen.. ich wüsste
jetzt keinen Grund warum das jemals nicht funktionieren sollte, in
meiner Konfiguration
:-)
MFG
DerAlbi schrieb:
> Man bemerke: der Startupcode liegt also lib vor.
Ok, das war mit so nicht bekannt, oben hast du geschrieben, er läge als
ASM vor, das las ich als Assembler-Quelltext.
> Ich bin eigentlich ganz zu frieden damit, muss ich sagen.. ich wüsste> jetzt keinen Grund warum das jemals nicht funktionieren sollte,
In der von dir benutzten Variante wird das wohl funktionieren, also mit
bekanntem Assembler-Code, der seinerseits nur Funktionen aufruft. Die
Initialisierungsfunktionen dort direkt rein zu pinnen, wie Jörg das im
Sinn hatte, ist jedoch hoch riskant.
Auf manchen ARM Plattformen, darunter m.W. auch denen von Atmel, können
sich aber Nebenwirklungen in Bezug auf das Debugging per JTAG ergeben.
Ob bei AVR32 ähnlich wir bei vielen ARMs der Debugger einen ab Reset
ungebremst loslaufenden Core erst einfangen muss ist mir aber nicht
bekannt.
>Ok, das war mit so nicht bekannt, oben hast du geschrieben, er läge als>ASM vor, das las ich als Assembler-Quelltext.
Sry, Ich hab den C-StartupCode als ASM vor mir.. aber C++ StartupCode
als Lib.
Deswegen hab ich erst den C-StartupCode genommen. Nun war ich aber mit
der Einschränkung unzufrieden, dass der die Konstruktoren der statischen
variablen nicht aufruft.
Deswegen war ich nun auf der Suche nach einer richtigen C++Vairante.
MFG
Komische Methode, zwischen C und C++ Startup zu unterscheiden. Steckt da
irgendwie Geld drin, nach dem Schema: wer mehr will muss ordentlich Geld
rausrücken?
Klingt abschreckend. Startup von sowas will ich als Quellcode, sonst
droht Ablage P.
Vielleicht gibts den auch ;-) Aber ich hab davon ehrlichgesagt eher
weniger Ahnung. Naja.. ich sag mal so: für C++ ist halt auch recht wenig
Support..
Da steckt sicher kein Geld dahinter und abschreckend sollte es nicht
sein...
passt schon. Hab ja auch sonderanforderungen. Normalerweise läuft auf
dem AP7000 ein Linux. Da braucht man soetwas nicht. Und wenn überhaupt
scheinen die meißten leute - warum auch immer - C zu bevorzugen... also
braucht man das noch viel weniger ;-)
MFG
A. K. schrieb:
> Die Nummer mit den Init-Sections wie in der avr-libc geht wie wie> mittlerweile wissen schon bei den AVRs u.U. in die Hose, weil Funktionen> nicht zwingend dort aufhören wo man es gerne hätte.
Das stimmt so nicht. Das stimmt nur für in C geschriebene und als
"naked" deklarierte Funktionen. Die Methode funktioniert trotzdem
noch einwandfrei für reine Assembler-Schnipsel, und das Stückchen
da oben hätte ich selbst wohl auch als Assemblerdatei dazu gelinkt,
statt mich mit dem Inline-Assembler zu verrenken. Der inline-
Assembler ist in der hier gezeigten Form aber auch kein Kandidat
für irgendwelche Code-Umstellungen durch den Compiler, insofern auch
sicher.
Das ist richtig, aber wenn man sowas zukunftsträchtig einrichten will,
dann sind "naked" Funktionen in einer Init-Section nun einmal
problematisch. Wenn man das auf Assembler-Stücke beschränkt, dann wird
das funktionieren, ist aber nicht jedermanns Sache.
Eine sicherere Variante scheint mir darin zu bestehen, analog zu den
Konstruktur-Aufrufen eine oder mehrere Sektionen zu schaffen, die nicht
aus dem nackten Code selbst bestehen, egal ob Assembler oder C, sondern
aus Zeigern auf den Code. Das kommt ohne Assembler aus, die Funktionen
benötigen keinen speziellen Frame und nur die Vektoren werden der
Sektion zugeordnet.
Statische Instanzen in C++ ist keine gute Idee, da man praktisch keine
Kontrolle ueber die Initialisierungsreihenfolge hat. Das ist oft nur am
Anfang eines Projekts eine coole Idee und raecht sich spaeter bitter.
Korrekt. Man kann sie sehr wohl verwenden, muss dabei unbedingt daran
denken, ausschliesslich die eigenen Resourcen, d.h. den eigenen Inhalt,
zu initialisieren. Abhängigkeiten von anderen solchen Daten oder vom
Zustand der Hardware sind sehr problematisch.
Andersum neige ich dazu, bei vollintegrierten Controllern dynamische
Allokation zu vermeiden, egal ob C oder C++, weil bei rein statischer
Allokation und restriktiver Allokation von Daten auf dem Stack der
Speicherbedarf weit besser übersehbar ist.
A. K. schrieb:
> Andersum neige ich dazu, bei vollintegrierten Controllern dynamische> Allokation zu vermeiden, egal ob C oder C++, weil bei rein statischer> Allokation und restriktiver Allokation von Daten auf dem Stack der> Speicherbedarf weit besser übersehbar ist.
Deswegen habe ich eine Main-Klasse als einzige statische Instanz oder
als lokale Instanz innnerhalb von main() und alles andere, was global
gebraucht wird, ist Member von Main. Alle Initialisierung, die ueber
einfaches Aufsetzen von Membern geht, machen die Klassen in einer extra
Methode, die von Main in definierter Reihenfolge aufgerufen wird. Das
erspart einem uebrigens auch sonst vielen lustigen Aerger bei
Klassenhierarchien, weil man dann im Konstruktor nicht auf einem halb
initialisierten Objekt rumwerkelt...
Peter Stegemann schrieb:
> Deswegen habe ich eine Main-Klasse als einzige statische Instanz oder> als lokale Instanz innnerhalb von main() und alles andere, was global> gebraucht wird, ist Member von Main.
Das alloziert allerdings den Speicher auf dem Stack, was die Sache
sehr unübersichtlich macht. Controller-Benutzer sind Freunde voll
statischer Allokation, weil man diese prima zur Compilezeit bereits
sieht und die Unwägbarkeit eines Stacküberlaufs unwahrscheinlicher
wird.
Jörg Wunsch schrieb:
> Peter Stegemann schrieb:>>> Deswegen habe ich eine Main-Klasse als einzige statische Instanz oder>> als lokale Instanz innnerhalb von main() und alles andere, was global>> gebraucht wird, ist Member von Main.> Das alloziert allerdings den Speicher auf dem Stack,
Nur beim "oder..."-Fall.
> was die Sache> sehr unübersichtlich macht. Controller-Benutzer sind Freunde voll> statischer Allokation, weil man diese prima zur Compilezeit bereits> sieht und die Unwägbarkeit eines Stacküberlaufs unwahrscheinlicher> wird.
Bezueglich des Stackueberlaufs sehe ich da keinen grossen Unterschied.
Der Gesamtverbrauch ist nur um einen statischen Umfang groesser, dafuer
der Restspeicherverbrauch um den gleichen Umfang kleiner.
Peter Stegemann schrieb:
> Der Gesamtverbrauch ist nur um einen statischen Umfang groesser, dafuer> der Restspeicherverbrauch um den gleichen Umfang kleiner.
Yep, aber den einen Verbrauch sehe ich direkt, den anderen nicht.
> Alle Initialisierung, die ueber einfaches Aufsetzen von Membern> geht, machen die Klassen in einer extra Methode, die von Main in> definierter Reihenfolge aufgerufen wird.
Ebenso. Nur eben auf statischer Basis.