Hallo,
ich verwende einen MSP430-1232 mit MSP430-gcc und -ld,
ich implementiere einen eigenen Bootloader für den MSP und Teile mein
Programm in unterschiedliche Sektionen ein wobei die .text section den
Benutzercode enthält der überschreibbar ist.
Mein Problem ist nun das Variablen (zurzeit nur bei Globalen Variablen
aufgefallen) in der von mir neu definierten section ein komisches
verhalten an den Tag legen.
Beispielcode mit dem ich das Verhalten getestet habe:
1
staticunsignedcharstate=0;
2
3
voidtest()
4
{
5
state++;
6
if(state>=2)
7
{
8
*dosomething*
9
}
10
}
11
12
voidmain()
13
{
14
while(1)test();
15
}
Das Verhalten ist Folgendes:
obwohl state immer erhöht wird, wird do something nicht aufgerufen,
wenn ich state bei der deklaration auf 1 setze wird do something
aufgerufen
daher denke ich wird state in der Funktion test wie eine lokale Variable
verwendet und zu beginn immer mit dem Wert aus der deklaration
initiiert.
dieses Verhalten tritt nur bei meinem geänderten Linker-File auf, was
das Problem warscheinlich auf dieses einschränkt, nur weiß ich leider
nicht wie ich das Linker-File umschreiben muss damit auch die Variablen
richtig Verlinkt werden.
Ein weiteres Problem hatte ich mit den debug Informationen die meine
Sektionen zum Überlaufen veranlassen, weshalb ich die
Debug-Informationen vom MSP430-gcc nicht generieren lasse.
kann mir jemand beim Umschreiben des Linker Files helfen, wo die
Variablen und Debug-Informationen wie in der .text Sektion
berücksichtigt werden.
Mein geändertes Linker-File habe ich in den Anhang gegeben.
mfg Benedikt
Variablen werden doch im .data und.bss abgelegt, die dürften sich nicht
in die Quere kommen. AUch Debug-Infos kommen nicht in die .txt sections.
Sehr komisch. Ich hab auch für meinen F1611 einen Funk-Bootloader
geschrieben in einer eigenen Section, das klappt bestens. Allerdings
benutze ich im Bootloader keine globalen Variablen aus dem "user
programm".
Im Anhang mal das geänderte Linker-File.
Das Problem ist, dass ich die Sektion nicht in den Files stehen haben
möchte sondern alles was in dem bootloader.c und bootloader.h File zu
bootloader.o umgewandelt wird in meine eigene .bootloader section
stelle, so wie es aussieht musst du bei deinen Funktionen davor noch
überall den sektionsnamen angeben, dort wo er nicht steht werden bei dir
die original sektionen verwendet. Deswegen wirst du auch keine Probleme
mit den Varablen haben denk ich mir mal. Gibt es eine Möglichkeit, dass
der Linker Variablen und Debug-Informationen automatisch wie er es im
originalfile auch tut in die dafür vorgesehenen Sektionen ladet?
Mir fällt gerade ein weiteres Problem ein aber vielleicht is das ja eh
keines, kenn mich bei dem msp430 Linker zu wenigaus:
Der Programmspeicher ist ja durch die Sektionen geschützt aber der
Variablenspeicher ist bei der Verwendung wieder gemischt wie kann ich es
schaffen das die Variablen immer an den gleichten Platz gebunden werden
und nicht automatisch in den gemeinsamen Bereich verlinkt werden.
Denke mir das es da dann ein Problem geen könnte wenn die bereits von
anderen Programmteilen verwendet werden nachdem der neue Code mittels
eigenem Bootloader einspielt wird kann ja die Anordnung variieren
wodurch die zugriffe auf die Variablen anders ausfallen oder kann das eh
nicht passieren.
mfg Benedikt
Achso, hm, da kann ich dir leider nicht helfen. Ich hab die in einem
"geschützen" Flash-Bereich stehen. Da müsstest du dich mal an die MSPGCC
Profis in den Mailinglisten oder so wenden....Chris Lichti oder Steve
Underwood.
Ich habe leider im Moment keine Zeit mich durch dein Linker-file zu
graben (kann aber gerne heute abend mal einen Blick rein werfen wenn das
Problem dann immernoch besteht), hätte aber dennoch einen Tipp für dich:
Ich persönlich würde Bootloader und Anwendung immer als zwei getrennte
Projekte übersetzen. Beide bekommen bezüglich RAM die selben (bzw. die
jeweils passenden) Linkereinstellungen, allerdings getrennte Bereiche im
Flash.
Nachteil:
- Du hast zweimal den Startup-Code enthalten. (Halte ich bei den paar
Byte für unkritisch.)
Vorteile:
- Variablen werden garantiert richtig initialisiert bzw. getrennt
verwendet.
- Du verschwendest in der eigentlichen Applikation keinen RAM für den
Bootloader, weder auf dem Stack noch für globale Variable.
Grüße,
odic
Verstehe nicht ganz wie du das meinst, vielleicht kannst du mir das
heute abend genauer erklären bzw vielleicht findest du ja den Fehler den
ich im Linkerfile gemacht hab denk mir mal, dass da noch einige Einträge
in den neuen Sektionen hinzugefügt werden müssen so wie es in der .text
section gemacht wird nur wie die genau heißen oder wo das zu schreiben
ist dazu kenn ich mich leider zu wenig in den Linker-File Syntax und in
den Eintellungen aus. Weil wenn man das original Linker-File verwendet
müssen ja auch keine eigenen Angaben zu den Variablen oder Sektionen im
Code gemacht werden.
zum Besseren Verständnis habe ich mal einen kurzen Überblick über den
Aufbau meines Programms, welches auf eigenen Speicherbereichen aufgebaut
ist zusammengestellt:
(fixer Bereich nicht änderbar, Bootloader und Interne Funktionen)
*[ Bootloader Bereich ]*****************
Einstiegspunkt Main
Interrupt Routinen
Bootloader Routinen
Überprüfungs Routinen
Interne Routinen
...
****************************************
++++++++++++++++++++++++++++++++++++++++
(fixe Einsprungadressen, weiterspringen durch User änderbar)
*[ Eigene Funktionsvektoren ]***********
User Main Einsprungspunkt
User Interrupt Einsprungspunkte
User Main deaktivieren
...
****************************************
(eigener Bereich komplett durch User änderbar)
*[ User Bereich ]***********************
****************************************
++++++++++++++++++++++++++++++++++++++++
der gesammte Bereich der zwischen +++ gekennzeichnet ist soll danach
mittels eigenem Bootloader umgeändert werden können.
Der Bereich mit den Eigenen Funktionsvektoren ist so aufgebaut das jede
Funktion die im Bootlaoer aufgerufen wird in einer 0x10 Sektion abgelegt
wird in der im Prinzip mittels extern auf die user funktionen verlinkt
wird, nach dem Beispiel:
im Bootloader Bereich:
1
externvoiduser_main_vector();
2
voidmain()
3
{
4
user_main_vector();
5
}
im eigene Funktionsvektoren Bereich:
1
externvoiduser_main();
2
voiduser_main_vector();
3
voiduser_main_vector()
4
{
5
user_main();
6
}
im User Bereich:
1
voiduser_main();
2
voiduser_main()
3
{
4
*codefromtheuserexecutedasMain*
5
}
Hoffe es wird so ca. klar was ich machen will,
Danke schonmal im Voraus,
mfg Benedikt
Ok, mein Post war vielleicht etwas knapp gehalten...
Also: ein Bootloader hat ja die Eigenschaft daß er im µC verbleibt,
wohingegen die Anwendung die du damit laden möchtest, ausgewechselt
wird. Wenn es sich bei deiner Anwendung nicht lediglich um
Parametrierung handelt, hast du zum jetzigen Zeitpunkt ein Problem: du
weißt nicht wieviel RAM deine Anwendung künftig brauchen wird und wo
Compiler bzw. Linker dann versuchen werden, diesen zu allozieren. Daher
hast du jetzt zwei Möglichkeiten:
1.) Entweder du reservierst Anwendung und Bootloader zwei getrennte
Adressbereiche im RAM und linkst die jeweiligen Module entsprechend.
Dann kannst du beide Softwareteile in einem einzigen Compiler- bzw.
Linkerlauf in einem einzigen Projekt übersetzen. Somit ist aber der
Adressbereich des Bootloaders für die Applikation gestorben, obwohl der
Bootloader im Normalfall überhaupt nicht läuft.
2.) Bei der zweiten Variante übersetzt du Bootloader und Anwendung in
zwei getrennten Projekten. Somit haben beide Softwareteile den vollen
RAM zur Verfügung und du hast auch sonst keine Abhängigkeiten zwischen
Bootloader und Anwendung. Zwar mußt du gewisse Softwareschichten doppelt
vorhalten (Startup Code, ggf. Kommunikationsfunktionen,
Transportprotokolle oder Flashfunktionen) was aber häufig insbesondere
bei kleinen Prozessoren besser zu verschmerzen sein dürfte als wenn
einem 100 Byte im RAM fehlen.
Da es bei dir ja um mehr geht als einen reinen Bootloader (es scheint
keinen Zeitpunkt zu geben, zu dem du voll von einer Welt in die andere
springst) hast du dich für Variante eins entschieden. Richtig?
Jetzt hast du allerdings ein anderes Problem: Du kannst problemlos
text-segment, Konstanten und Initialisierungswerte für vorinitialisierte
Variable in zwei unterschiedliche Flashbereiche legen, je nachdem ob sie
aus Bootloader oder Anwendung stammen. Was du allerdings so einfach
nicht hinbekommst, ist die Aufteilung im RAM. Selbst wenn du im
Linkerfile getrennte Speicherbereiche einrichtest hast du ein Problem:
der Startup-Code in deinem Bootloader weiß nicht, wieviele Daten der
Anwendung er wo im Flash holen bzw. wohin ins RAM kopieren soll. D.h.
hierfür müßtest du dir wieder selbst eine Routine schreiben. Was du da
möchtest ist zwar machbar, aber nicht ganz trivial. Mit dem reinen
Anpassen des Linkerfiles ist es jedenfalls nicht getan.
Ohne deine Anwendung jetzt im Detail zu kennen würde ich mir eine andere
Frage stellen: Ist die momentan gewählte Aufteilung wirklich notwendig
bzw. sinnvoll? Würde nicht auch ein einfacher und kleiner Bootloader
nach Schema zwei deine Anforderungen ebenfalls abdecken? (Ok, waren zwei
Fragen. ;-) )
Ich hoffe das war jetzt verständlicher....
Grüße,
odic
Ich habe vor das Programm wie bereits beschrieben im ROM zu trennen im
RAM sollen später rein aus Platztechnischen gründen Überlappende
Bereiche existieren. Ich habe mich deswegen für eine Mischung aus
Variante eins und zwei entschieden damit sollte es mir möglich sein
Informationen von einem Teil in den anderen zu bringen und
nichtverwendete Bereiche des einen Teils im anderen Teil zu verwenden.
Ich habe mich deswegen für diese umständliche Variante entschieden da
ich später noch einen dritten Bereich einführen will der eine weiter
Quelle für den Botloader bildet aber dann nicht geflashed werden darf so
zu sagen:
Bootloaderbereich, Interner Sicherheitsbereich, Userbereich
Nur muss ich wie gesagt einige Informationen von einem in den anderen
Bereich bekommen und das InfoMEM habe ich vor bereits für andere Dinge
zu verwenden also das fällt leider auch flach.
Wie du bereits bemerkt hast ist zur Zeit alles noch auf Variante eins
eingestellt, weil ich noch kein Speicherproblem habe, und noch am Testen
bin, aber wenn das Variablenproblem gelöst ist werde ich da auch noch
zum umstellen beginnen,
Ich denke das es sich bei den Problem wirklich um ein Linker Problem
handelt dass die Variablen die ich in meiner Bootloader sektion verwende
durch das Linker File irgendwie in diese Sektion geschrieben werden da
dies aber nicht möglich ist können diese nicht erhöht werden und sind
solange sie in verwendung sind in den registern und werden auch brav
erhöht und am schluss wird versucht den wert des Registers wieder
zurückzuschreiben aber das geht nicht da der speicherbereich nicht
beschrieben werden kann und beim nächsten Aufruf werden die
unveränderten Werte wieder aus dem Speicher ins Register geholt und das
Spiel beginnt von vorne.
hoffe du verstehst, trotz meiner wirren Gedankengängen was ich denke was
das Problem ist
mfg Benedikt
Irgendwie reden wir aneinander vorbei:
Zu deinem aktuellen Problem:
Hast du ein MAP-file zu deinem Code?
Zu meinen Anmerkungen:
Hast du verstanden was dein Problem sein wird, wenn du versuchst,
verschiedene Anwendungen mit deinem Bootloader zu laden?
Grüße,
odic
Ich glaub ich versteh schon wie du das meinst,´
ich hoffe das es so zu lösen geht wie ich es vorhabe,
indem ich entweder ein globales Variablenfile erstelle und das mit
Unions und Structs so aufteile das die Bereiche überschnitten werden und
in den einzelnen files nur mit Variablen arbeite die als extern
deklariert werden
oder
,und diese Möglichkeit hoffe ich umsetzen zu können,
in den jeweiligen Files Structs erzeugen die mit Linkeranweisungen an
den bestimmten Speicherpunkt gerückt werden, da ich nicht gleichzeitig
auf alle Bereiche zugreifen muss, Variablen auf die ich zugreifen muss
die im anderen Bereich liegen würde ich über getter und setter
Funktionen die im Funktionsvektorenbereich verlinkt werden zugreifen
somit muss der eine Teil nicht wissen wo Variablen des anderen Teils
wirklich liegen.
Hoffe das du das so gemeint hast wenn nicht hab ich noch immer was
falsch verstanden und werd ein noch größeres Problem bekommen wenn mir
der Speicher ausgehen sollte :/
Anbei das Map file von meinem Projekt, hoffe du siehst dich da raus, die
sektionen werden brav aufgeteilt nur wie das genau mit den Variablen
passiert ist mir ein rätsel :)
mfg Benedikt
Naja, spätestens wenn mein bss auch im Flash liegt würde mich das schon
stutzig machen.... ;-)
Zur Erklärung:
Du legst alle Segmente deines bootloader.o in eine einzige Section. Das
dürfte nicht ganz das sein was du möchtest. Du willst lediglich das
.text-Sement in diese Section legen. Probiers mal mit einem Attribut für
deine Funktion ala __attribute__((section (".section_bootloader")))
Das müßte funktionieren. Kannst auch mal googeln wie sich das auf
Dateiebene bewerkstelligen läßt. Geht mit Sicherheit auch, bin ich aus
dem Kopf raus aber momentan überfragt. Nach dem gleichen Prinzip kannst
du auch mit .bss bzw. .data vorgehen, wobei ich dir jetzt schon sagen
kann daß dein Standard Startup-Code damit ziemlich sicher überfordert
sein dürfte.... aber das Thema hatten wir schon mehrfach....
Grüße,
odic
PS: Ein Tipp noch: überleg dir mal eine durchgängige Nomenklatur für
dein LinkerCommand-file. Teilweise heißen die Sections wie die Segmente,
die darin abgelegt werden, teilweise heißen sie wie die
Speicherbereiche, in denen sie liegen.... etwas unübersichtlich.
:) (ich habe angenommen das genau sowas der Fehler ist),
Das ist genau das worauf ich hinaus wollte, das alles in bootloader.o in
eine section geschrieben wird genau das möchte ich ja ändern so wie es
im original Linker-File umgesetzt wird wo die Variablen ohne direktiven
in eine andere sektion als der programmcode kommen und die
debug-informationen nochmals anders behandelt werden.
gibt es da eine Möglichkeit ohne direktiven im Sourcecode die Bereiche
die normalerweise in .text verschoen werden, sobald sie aus einer
gewissen *.o datei kommen in einen eigenen bereich zu setzen und die
anderen sektionen aber zu übernehmen?
mfg Benedikt
hallo, und danke,
ich hab das Linker File umgestellt und es wird nurnoch die text section
dort eingetrage, ich kann jetzt auch wieder die debuginformation beim
compilen aktivieren ohne den speicher zu überfüllen.
Weiters habe ich alle globalen Variablen in ein gemeinsames File
gestellt,
das keine eigene behandlung im Linker erfährt und somit in .bss und
.data gelinkt wird.
Habe noch 2 Funktionen (initvars_bootloader und initvars_user)
eingeführt mit denen beim wechsel zwischen den bereichen die variablen
initiiert werden.
trotz allem kämpfe ich mit dem compiler der teilweise einfache
statements oder vergleiche unterschiedlich verarbeitet . . . ist
warscheinlich tageszeit abhängig . . . :)
denke mir aber das da ein kleines stack problem auftritt . . .
wie gesagt danke nochmal für deine Hilfe
mfg Benedikt