Hallo Community,
ich habe ein großes Problem beim kombinieren von meinen beiden
Projekten.
Ich habe den Silabs C8051F120 als MCU + vorhandene Elektronik mit
kompletter Peripherie, d.h. ich kann den Prozessor nicht mehr wechseln!
Ich arbeite mit µVision 3.30a (incl. PK51).
Ich habe ein Bootloader-Projekt und ein Frimware-Projekt. Ich muss nun
auf Codebanking umsteigen, weil der Firmware-Code mittlerweile die 64k
Grenze übersteigt und noch nicht alle gewünschte Funktionalität
implementiert ist. Deshalb habe ich bei beiden Projekten auf Codebanking
umgestellt. Wenn ich die Projekte für sich kompiliere und aufspiele,
gibt es keine Probleme.
Ich habe nur ein Problem mit dem Firmware-Projekt, weil ich dort dem
Linker(LX51) aus welchem Grund auch immer nicht mitteilen kann, dass die
Firmware in der Ersten Bank die ersten 8191 Bytes nicht verwenden soll,
weil diese ja schon vom Bootloader verwendet wurden.
Die Konfiguration ist zur Zeit so:
Bankarea(C:0x8000 - C:0xFFFF)
Der Bootloader-Code beginnt bei 0x8000 und endet bei 0x9FFF.
Die Firmware soll bei 0xA000 beginnen, das funktioniert aber nur
teilweise, weil ich kann zwar dem Linker sagen, dass erst bei einem
Offset von 0xA000 begonnen werden soll, aber er linkt trotzdem
irgendwelche Funktionen in den Bereich davor.
Kann mir da irgendjemand einen guten Tipp geben, was ich ggf. falsch
mache?
Ich bedanke mich schon im Vorraus für zahlreiche Antworten.
Viele Grüße, Daniel
> aber er linkt trotzdem irgendwelche Funktionen in den Bereich davor.
Ich tippe mal spontan, dass IRGENDWELCHE Funktionen die
Interrupt-Vektoren sind...
> Kann mir da irgendjemand einen guten Tipp geben, was ich ggf. falsch mache?
SiLabs hat ne AppNote für einen USB-Bootloader, evtl. findest du da
schon mal Infos. Für Code-Banking-Applikationen müsste auch was da sein.
Ansonsten gäb's noch die Keil Knowledge-Base als Anlaufpunkt.
Ralf
Hallo Ralf,
danke für deine Antwort, aber die Interrupt-Vektoren sind es nicht, die
habe ich schon per Linker-Befehl fix in den Common-Bereich geschoben. Da
rutschen immer irgendwelche Funktionsfragmente anderer Funktionen rein.
Es kann ja aber nicht das Ziel sein, dass ich jedes einzelne Segment
separat addressieren muss - nur damit alles hintereinander kommt - oder?
Die Knowledge-Base und alles mögliche von Keil zu diesem Thema habe ich
schon durchforstet, habe dazu auch einiges gefunden. Ich bleibe aber
immer wieder am selben Problem hängen. Es gibt im Linker irgendwie nur
die Möglichkeit bestimmte Segmente direkt zu adressieren.
Die AppNote zu dem USB-Bootloader werde ich mir gleich mal ansehen,
vielleicht find ich da noch was brauchbares und meld mich dann wieder.
Daniel
Bei den unseren AVR machen wir das so, dass wir auf einen Master-AVR den
Bootloader aufspielen, dann über den Bootloader die Applikation
nachladen und anschließend ein Hexdump ziehen; das dann als Vorlage für
alle weiteren Controller dient.
Ich arbeite zwar mit SDCC, aber das sollte da analog funktionieren.
Per Bank-geswitchtes Modul musst Du für alle globalen Variablen/Daten
und Funktionen normalerweise per pragma-Direktive einen Segmentnamen
angeben.
Im Linker-Script weist Du dann jedem Segment eine 20-Bit-Adresse zu. Wie
das bei Keil genau geht, weiss ich nicht mehr, der flog zugunsten von
SDCC in die Ecke.
Vielleicht kannst Du dir von diesem SDK
http://openschemes.com/2011/08/23/our-turn-with-the-ax206-digital-photo-frames/2/
was abgucken.
Gruss,
- Strubi
> Es kann ja aber nicht das Ziel sein, dass ich jedes einzelne Segment> separat addressieren muss - nur damit alles hintereinander kommt - oder?
Das nicht, doch ich glaube, du musst es für jedes Modul machen, bzw. für
jede Gruppe von Modulen.
Wobei es eigentlich reichen sollte, dem Linker zu sagen, dass der
Code-Bereich für's komplette Projekt an einer anderen Stelle beginnt.
Das ist im Memory-Dialog, wenn man den Haken bei "use memory layout from
target dialog" rausnimmt, dann sollte man es selbst einstellen können.
Hast du dir mal das MAP-File angeschaut, welche Funktionen im
"verbotenen" Bereich landen?
Ralf
Hallo zusammen,
vielen Dank für die vielen Tipps.
@Ralf: das USB-Bootloader Projekt habe ich mir angesehen, das beschreibt
im Prinzip genau den Status meines Programms bevor ich mit Codebanking
angefangen habe, es ist genau so aufgebaut.
@Stefan: genau das iss ja mein Problem, den Bootloader aufspielen kann
ich nur ich bekomm ja nichtmal nen lauffähiges Firmware-Executable aus
dem Compiler raus, was ich dann aufspielen könnte.
@Strubi: Bei Keil werden Funktionen automatisch zu Segmenten, die man
speziefisch adressieren kann.
@Ralf: Der Codebereich fürs komplette Projekt kann nur einmal deklariert
werden, das stimmt soweit. Nur habe ich bei diesem Controller das
Problem, dass ich so ne Einstellung für jede Bank seperat machen müsste,
da es folgende Einschränkungen gibt:
1. Der Bootloader fängt bei Bank1:0x8000 an und hört bei B1:0x9FFF
inclusive Reserve auf. Das würde bedeuten, wenn ich den Codebereich im
Firmware-Projekt von 0xA000 - 0xFFFF definiere, gilt das dann auch für
die anderen Bänke und damit würde ich dann 2x 0x2000 Bytes einbüßen.
2. Laut Datenblatt vom Controller darf ich den Bereich Bank3:0xC000 -
0xFFFF nicht mehr beschreiben, da dort die lese/schreib - Schutz Bytes
sind. Wenn ich dort was reinschreibe, dann wird der ganze Controller
lese/schreib geschützt, so dass ich über den JTAG nichts mehr machen
kann (ist alles im Zuge der Problemlösung passiert, die letzten Tage).
Das MAP-File ist ständig offen bei mir, daher weis ich ja, dass der
Linker da irgendwie mist gebaut hat.
Nun habe ich dann nach intensievem Suchen endlich das erlösende
Schlüsselwort RESERVE für den Linker gefunden. Damit kann man spezielle
Bereiche als Reserviert deklarieren und somit weis der Linker, dass er
nichts in diese Bereiche legen soll.
Nachdem ich das nun nochmal Compiliert hab, habe ich nun aber das
Problem, dass unzählige IMPROPER FIXUP's kommen und ich nicht weis, wie
ich die alle beheben soll. Weil in der Hilfe zu diesem Problem steht nur
im Groben, dass dieser fehler auftritt, wenn ein Jump gemacht werden
soll, der zu weit weg ist. Wie soll man das jetzt verstehen, muss ich
jetzt die Funktionen(FYI: es sind über 95!) doch einzeln adressieren und
auch noch solange die Reihenfolge tauschen, bis kein Fehler mehr
auftritt?
Vielleicht kann mir ja dazu noch jemand einen guten Tipp geben.
Viele Grüße, Daniel
Normaler Weise plaziert man den Bootloader nicht irgendwo mittendrin,
sondern ganz ans Ende.
Die Applikation fängt dann ganz normal bei 0x0000 an, sie weiß garnichts
davon, daß überhaupt ein Bootloader existiert.
Kann dieser MC überhaupt den Resetvektor verschieben, damit er auf den
Bootloader zeigt?
Peter
Hallo Peter,
klar kann man den Resetvektor verschieben, das habe ich auch gemacht.
Und bei Codebanking mit diesem Controller fängt nun mal alles bei 0x8000
an, weil der Bereich davor 0x0000-0x7FFF ist die Common-Area.
Nun gut, ich könnte jetzt den Bootloader auch nach hinten schieben, das
löst aber mein Problem nicht.
Vielen Dank trotzdem.
Hier noch ein Nachtrag zum vorigen Beitrag:
Es besteht ausserdem das Problem, dass der Linker aus unerklärlichen
Gründen große *Gap*'s zwischen die Funktionen macht. Woran liegt das und
kann man das irgendwie verhindern? Nur mal ein Beispiel: Er hat in einer
Bank einen Gap von 0x29FB, was 10747 Bytes sind, produziert.
Gruß, Daniel
Ich hab bisher nie so extrem große Programme gehabt, daher habe ich
Banking noch nie benutzt.
Benutzt Du keine Optimierung?
Benutzt Du das Large-Modell?
Man erreicht deutlich kompakteren Code, wenn man das Small-Modell
benutzt und nur große Arrays als xdata definiert.
Beim Banking muß natürlich Code auch unter 0x8000 plaziert werden, z.B.
Interrupthandler. Das sollte eigentlich der Linker selbst entscheiden
können. Deshalb auch den Bootloader ans Ende, damit der Linker ihn nicht
überschreibt.
Peter
Daniel schrieb:> 1. Der Bootloader fängt bei Bank1:0x8000 an und hört bei B1:0x9FFF> inclusive Reserve auf. Das würde bedeuten, wenn ich den Codebereich im> Firmware-Projekt von 0xA000 - 0xFFFF definiere, gilt das dann auch für> die anderen Bänke und damit würde ich dann 2x 0x2000 Bytes einbüßen.
Hallo,
warum definierst du nicht einfach eine (leere) Datentabelle an dieser
absoluten Adresse oder eine Folge von 8192 NOPs? Das frisst doch auch
der dümmste Linker.
Gruss Reinhard
Hallo Peter,
ja ich habe die höchste Optimierungsstufe (11) eigestellt und ja im
Moment benutz ich das Large-Memory-Modell. Ich habe aber auf deinen
Hinweis hin mal auf Small umgestellt, ohne Erfolg. Die Fehler bleiben
die gleichen. Das da auch im Common was rein muss, weis ich natürlich,
aber da ich zur Zeit nur 3 Interrupt-Handler habe, ist das auch
überschaubar. Ich habe diese natürlich manuell direkt dahin adressiert.
@Reinhard: Wie kann man das im C-Code machen?
Grüße, Daniel
Daniel schrieb:> Ich habe aber auf deinen> Hinweis hin mal auf Small umgestellt, ohne Erfolg.
Small hat doch keinen Einfluß auf das Banking.
Es soll nur die Codegröße verringern, daß vielleicht kein Banking nötig
ist.
Peter
Hallo Peter,
das hat aber leider nicht dafür gereicht. Ich habe ja noch vor, was dazu
zu nehmen, aber im moment bekomm ich ja nichtmal das vorhandene
lauffähig.
Vielen Dank für die Informationen.
Grüße, Daniel
> 1. Der Bootloader fängt bei Bank1:0x8000 an und hört bei B1:0x9FFF> inclusive Reserve auf. Das würde bedeuten, wenn ich den Codebereich im> Firmware-Projekt von 0xA000 - 0xFFFF definiere, gilt das dann auch für> die anderen Bänke und damit würde ich dann 2x 0x2000 Bytes einbüßen.
Bist du sicher? Ich meine, man kann für die Bänke separate
Adressbereiche angeben (komme leider grad nicht dazu, nachzuschauen).
> 2. Laut Datenblatt vom Controller darf ich den Bereich Bank3:0xC000 -> 0xFFFF nicht mehr beschreiben, da dort die lese/schreib - Schutz Bytes> sind. Wenn ich dort was reinschreibe, dann wird der ganze Controller> lese/schreib geschützt, so dass ich über den JTAG nichts mehr machen> kann (ist alles im Zuge der Problemlösung passiert, die letzten Tage).
Nicht ganz richtig, du darfst da sehr wohl reinschreiben, nur an die
Adressen der entsprechenden Security-Bytes darfst du nix schreiben, wenn
ich mich recht entsinne.
> habe ich nun aber das Problem, dass unzählige IMPROPER FIXUP's kommen> und ich nicht weis, wie ich die alle beheben soll.> Weil in der Hilfe zu diesem Problem steht nur im Groben, dass dieser> fehler auftritt, wenn ein Jump gemacht werden soll, der zu weit weg ist.
P.Danneger hat's schon angedeutet, aber ums klar zu machen:
Du kannst beim Banking keinen Code zwischen den Bänken aufrufen. Das
heisst im Klartext: Eine Funktion, welche in der oberen Hälfte
beispielsweise in Bank 1 liegt, kann keine Funktion aus Bank 2 aufrufen.
Deswegen sollte der Hauptteil der Applikation immer in Bank 0 sein, und
Funktionen, die andere Funktionen aufrufen müssen entsprechend in der
gleichen Bank sein.
Könnte das evtl. dein Problem mit den FixUps sein?
Ralf
Hallo Ralf,
> Bist du sicher? Ich meine, man kann für die Bänke separate> Adressbereiche angeben (komme leider grad nicht dazu, nachzuschauen).
Ja, das geht nur bei Segmenten, wo man es so schreiben kann: B1:0x8000 -
B1:0xFFFF
> Nicht ganz richtig, du darfst da sehr wohl reinschreiben, nur an die> Adressen der entsprechenden Security-Bytes darfst du nix schreiben, wenn> ich mich recht entsinne.
Das stimmt schon, aber irgendwas steht da noch, dass code der in dieser
Region ausgeführt wird nix in Regionen weiter unten schreiben kann oder
so ähnlich.
> P.Danneger hat's schon angedeutet, aber ums klar zu machen:> Du kannst beim Banking keinen Code zwischen den Bänken aufrufen. Das> heisst im Klartext: Eine Funktion, welche in der oberen Hälfte> beispielsweise in Bank 1 liegt, kann keine Funktion aus Bank 2 aufrufen.> Deswegen sollte der Hauptteil der Applikation immer in Bank 0 sein, und> Funktionen, die andere Funktionen aufrufen müssen entsprechend in der> gleichen Bank sein.> Könnte das evtl. dein Problem mit den FixUps sein?
Möglicherweise ja, ich kann es zumindest nicht ausschließen. Ich habe
nun halt alle Funktionen (ca. 100) geschnappt und diese entsprechend
ihrer Codegröße in die drei Banken eingeteilt.
Es gibt keinen richtigen Haupt und Nebenteil, da es sich um ein
Messgerät handelt und immer zyklisch alles gebraucht wird, was da ist.
Wenn ich das eher nach dem Call-Tree einsortieren muss, werd ich
bestimmt ein mega großes Problem haben, weil es sind zwei drei
Funktionen dabei, die alleine ca. 4kB groß sind und auch noch alle
möglichen Funktionen aufrufen.
Daniel