Forum: Mikrocontroller und Digitale Elektronik Codebanking: Kombinieren von 2 Projekten (Bootloader & Firmware)


von Daniel (Gast)


Lesenswert?

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

von Ralf (Gast)


Lesenswert?

> 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

von Daniel (Gast)


Lesenswert?

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

von Stefan . (xin)


Lesenswert?

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.

von Strubi (Gast)


Lesenswert?

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

von Ralf (Gast)


Lesenswert?

> 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

von Daniel (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von Daniel (Gast)


Lesenswert?

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.

von Daniel (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von Reinhard Kern (Gast)


Lesenswert?

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

von Daniel (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von Daniel (Gast)


Lesenswert?

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

von Ralf (Gast)


Lesenswert?

> 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

von Ralf (Gast)


Lesenswert?


von Daniel (Gast)


Lesenswert?

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

von Ralf (Gast)


Lesenswert?

Hi Daniel,

okay, dann sagste Bescheid, wenn du "umstrukturiert" hast.

Ralf

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.