Forum: Compiler & IDEs Aus dem AVR-Programm auf Funktionen im Bootloader zugreifen


von Sepp O. (Gast)


Lesenswert?

Ich habe eine Frage an euch.

Ist es möglich, bei einem AVR vom eignetlichen Programm heraus auf 
Funktionen im Bootloader zuzugreifen?

Ich möchte eine Art Ablaufsteuerung verwirklichen, bei der sich die 
eignetlichen Funktionen im Bootloader befinden und nur die 
Hauptprogrammschleife und zusätzliche Funktionen nachgeladen werden.

Ist soetwas möglich?

von Imon (Gast)


Lesenswert?

Sepp O. schrieb:
> Ich habe eine Frage an euch.
>
> Ist es möglich, bei einem AVR vom eignetlichen Programm heraus auf
> Funktionen im Bootloader zuzugreifen?

Ja ist es Mario Grafe hat gerade dazu eine Anleitung in die Artikel 
Sammlung gestellt. und diese Anleitung hier auch Diskutiert

siehe mal unter

AVR Bootloader in C - eine einfache Anleitung: Die Test-Anwendung

von Peter D. (peda)


Lesenswert?

Sepp O. schrieb:
> Ist es möglich, bei einem AVR vom eignetlichen Programm heraus auf
> Funktionen im Bootloader zuzugreifen?

Generell erstmal nein und prinzipiell jain.

In Assembler sind alle Schweinereien erlaubt. Obs aber auch praktikabel 
ist, steht auf einem anderen Blatt.

In C oder Basic mußt Du mal Dein entsprechendes Manual befragen, ob 
sowas unterstützt wird. Ich vermute mal, nein.

Es müßte quasi eine Art OS mit nem API implementiert werden.
Und der Compiler müßte entsprechende Schnittstellen und 
Speicherverwaltung bereitstellen, damit sich die 2 Programme überhaupt 
erstmal verstehen und auch nicht gegenseitig ihre Daten und den Stack 
zerstören.


Peter

von StinkyWinky (Gast)


Lesenswert?

@Peter
Deinen Einwand verstehe ich nicht. Wenn man aus dem Hauptprogramm 
lediglich eine Funktion des Bootloaders aufrufen will, so findet dies ja 
im selben Kontext statt. Das einzige Problem ist doch, dass ich die 
Adresse der Funktion wissen muss?

von Sepp O. (Gast)


Lesenswert?

Gibt es eventuell eine Lösung die ähnlich ist wie bei der 
PC-Programmierung bei DLL's, Plug in's,...?
Da gibt es ja auch dass Problem, dass man dem Programm mitteilen muss an 
welcher Adresse sich die Funktion befindet.

von Peter D. (peda)


Lesenswert?

StinkyWinky schrieb:
> Das einzige Problem ist doch, dass ich die
> Adresse der Funktion wissen muss?

Nicht nur das.
Du weißt nicht, wo sie steht.
Du weißt nicht, welche Argumente sie wo und wie haben will.
Du weißt nicht, wo und wieviel RAM sie belegt.
Du weißt nicht, welche Ressourcen (Ports, Interrupts) sie belegt.

Und was noch viel schlimmer ist, der Linker weiß es ja auch nicht.


Peter

von Sepp O. (Gast)


Lesenswert?

Da ich den Boot-Loader schreiben werde dürften die Punkte mit mehr oder 
nochmehr Aufwand zu lösen sein.

Was mir von Anfang an Kopfzerbrechen macht, ist wie ich das Ganze dem 
Linker beibringe.
Gibt es da keine Möglichkeit etwas über Schnittstellen / Headerdateien 
zu trixen?

von Εrnst B. (ernst)


Lesenswert?

Sepp O. schrieb:
> Gibt es da keine Möglichkeit etwas über Schnittstellen / Headerdateien
> zu trixen?

Du erzeugtst den Bootloader als normale Library. Mittels change-section 
usw. an die richtige Stelle verschieben.

Lib linken mit minimalprogram, dessen main mit "weak"-attribut versehen, 
damit der Linker nicht meckert.
Lässt sich dann so brennen, als reiner Bootloader.

Jetzt die Applikation ebenfalls gegen exakt diese library linken. 
Bootloader-Funktionen sind dann ganz normal verfügbar.

Das daraus resultierende HEX-File enthält jetzt aber bootload UND 
Applikation. Den Bootloader-Teil vorm Upload rausschneiden, der 
Bootloader kann sich nicht selbst updaten. Alternativ kann der 
bootloader einfach ungültige Adressen in seiner Eingabe ignorieren.

von Karl H. (kbuchegg)


Lesenswert?

Sepp O. schrieb:
> Da ich den Boot-Loader schreiben werde dürften die Punkte mit mehr oder
> nochmehr Aufwand zu lösen sein.
>
> Was mir von Anfang an Kopfzerbrechen macht, ist wie ich das Ganze dem
> Linker beibringe.

Gar nicht.

> Gibt es da keine Möglichkeit etwas über Schnittstellen / Headerdateien
> zu trixen?

Natrülich. Du musst in deinem Anwenderprogramm deine Funktion so 
verpacken, dass sie als konstanter Funktionspointer bekannt ist. 
Zusammen mit dem richtigen Protoypen kannst du dann den Aufruf machen.

Die Schwierigkeit: Die Adressen der Funktionen feststellen.

Bei CP/M hat das zb so funktioniert:
An einer bekannten Stelle im Speicher gibt es ein Array mit 
Funktionspointern (oder waren dort schon die Calls. Ich bin mir nicht 
sicher, aber ich glaube dort waren schon die Calls), welche zu den 
eigentlichen Funktionen führen. Das BDOS hat dieses Array aufgebaut und 
seine eigenen Funktionsstartadressen dort eingetragen. Will ein 
Anwenderprogramm eine BDOS Funktion aufrufen zb Konsolen-Ausgabe, dann 
geht es über dieses Array, deren Lage im Speicher es kennt und deren 
Reihenfolge der Funktionen fix ist.

Im Grunde/Prinzip nichts anderes als das was bei den Interrupt Vektoren 
auch gemacht wird.

von Hc Z. (mizch)


Lesenswert?

Du deklarierst die Funktionen in Deinem Programm wie üblich:
1
int externeFunktion(char *s, int i);
damit der Compiler weiß, wie sie anzusprechen ist.


Der Linker-Kommandozeile fügst Du dann zu:
1
avr-ld ... --defsym externeFunktion=0xfa2 ...

oder, wenn der Linker vom Compiler aufgerufen wird (was der übliche Fall 
ist):
1
avr-gcc ... -Wl,--defsym,externeFunktion=0xfa2 ...

So sollte es gehen.  (Als Compiler habe ich den [avr-]gcc 
vorausgesetzt.)

von Karl H. (kbuchegg)


Lesenswert?

Hc Zimmerer schrieb:

> Der Linker-Kommandozeile fügst Du dann zu:
>
1
> avr-ld ... --defsym externeFunktion=0xfa2 ...
2
>

Ich zieh mein

[Zitat]
>> Was mir von Anfang an Kopfzerbrechen macht, ist wie ich das Ganze dem
>> Linker beibringe.
>
> Gar nicht.
[/Zitat]

hiermit zurück :-)

von StinkyWinky (Gast)


Lesenswert?

Ich gehe davon aus, dass ich den Bootloader selber geschrieben habe, 
also weiss ich:
- welche Argumente sie wo und wie haben will.
- wo und wieviel RAM sie belegt.
- welche Ressourcen (Ports, Interrupts) sie belegt.

Ferner weiss ich, an welcher Adresse mein Bootloader und mein 
Hauptprogramm liegen. Als Bastel-Lösung kann ich die Adresse meiner 
gewünschten BL-Funktion aus dem Map-File lesen und in meiner Applikation 
verwenden.

Sollte ich aber den Bootloader ändern, muss ich natürlich die Adresse 
der BL-Funktion im Hauptprogramm anpassen.

von Sepp O. (Gast)


Lesenswert?

StinkyWinky schrieb:
> Ich gehe davon aus, dass ich den Bootloader selber geschrieben habe,
> also weiss ich:
> - welche Argumente sie wo und wie haben will.
> - wo und wieviel RAM sie belegt.
> - welche Ressourcen (Ports, Interrupts) sie belegt.
Ich werden den Bootloader nicht vollkommen selbst schreiben, sondern nur 
an meine Bedürfnisse anpassen.
Ich will ja das Rad nicht umbedingt komplet neu erfinden.

StinkyWinky schrieb:
> Sollte ich aber den Bootloader ändern, muss ich natürlich die Adresse
> der BL-Funktion im Hauptprogramm anpassen.
Dass ist aber im PC-Bereich beim Verwenden von Schnittstellen / Plugins 
auch nicht anders.

@Hc Zimmerer
Dass ist ja genau das was ich suche.
Weist du wo ich detailierte Informationen darüber finde?

Hc Zimmerer schrieb:
> (Als Compiler habe ich den [avr-]gcc vorausgesetzt.)
Ja, ich verwende AVR gcc. Genauer gesagt das aktuelle Win-AVR Paket.

von Hc Z. (mizch)


Lesenswert?

Sepp O. schrieb:
> @Hc Zimmerer
> Dass ist ja genau das was ich suche.

Das dachte ich mir :).

> Weist du wo ich detailierte Informationen darüber finde?

In den Gnu Info Pages zu gcc und ld (->binutils), zu finden in der 
Paketverwaltung jedes Linux-Systems oder online unter 
http://www.gnu.org/manual/manual.html, Abschnitt „Software Development“.

von Tom M. (tomm) Benutzerseite


Lesenswert?

StinkyWinky schrieb:

> Ferner weiss ich, an welcher Adresse mein Bootloader und mein
> Hauptprogramm liegen. Als Bastel-Lösung kann ich die Adresse meiner
> gewünschten BL-Funktion aus dem Map-File lesen und in meiner Applikation
> verwenden.

Wieso definierst du nicht eine schöne kleine Sprungtabelle im 
Bootloader-Bereich? Damit hast du weniger Abhängigkeiten zwischen BL und 
dem "normalen" Programm. Musst dich bloss einmal drauf einigen, wo die 
Sprungtabelle im BL-Bereich liegt. Würd ich wohl ganz am Anfang machen. 
Der erste Befehl als Jump in die BL main, dann weitere Jumps in die 
exportierten functions. Kommt mal eine function hinzu, wird die Tabelle 
einfach n bisschen grösser und der Code dahinter verschiebt sich um 
einige Bytes.

von Peter D. (peda)


Lesenswert?

Man kann es auch wie früher beim DOS-Interrupt machen.
Du hast eine Einsprungadresse, z.B. Flashend und in einem Register wird 
die Funktionsnummer übergeben.

Interessant ist auch, ob der Bootloader Interrupts behandelt oder ob 
auch die Applikation Interrupts enthalten darf.


Peter

von ThomasH (Gast)


Lesenswert?

ich hab so etwas für ein Projekt gemacht. Man benötigt natürlich 
Funktionen die nur am Stack arbeiten, also nichts globales angreifen. 
Bei mir waren das alles Verschlüsselungs- und Hashfunktionen, was es 
noch einfacher macht, weil auch keine Hardwareabhängigkeiten bestanden.

Ich hab im Bootloader ein Array mit den Adressen der gewünschten 
Funktionen an eine Bekannten Stelle abgelegt, damit ich sich mögliche 
Änderungen im BL nicht auf die App durschlagen, angelegt. Und in der 
Applikation verwenden ich dann diese Sprungtabelle für meine 
Funktionsaufrufe. Funktioniert alles problemlos und man muss nicht mit 
Linker herumtricksen.

von Sepp O. (Gast)


Lesenswert?

Dass hört sich vielversprechend an.

Kann ich (und eventuell auch andere) ein Beispiel bekommen?
Denn dieses Thema dürfte sicher auch für andere Interessant sein.

von Peter D. (peda)


Lesenswert?

Wäre es nicht einfacher, Deine geheimen Funktionen zu ner Lib zu 
compilieren?

Im Bootloader sind sie ja auch nicht gegen Auslesen geschützt.


Peter

von Sepp O. (Gast)


Lesenswert?

Falls du mich meinst.

Bei mir hat es nichts mit Geheim zu tun.
Ich will nur so viele Funktionen wie möglich in den Prozessor 
verfracchten, damit nur mehr das Steuerungsprogramm selbst nachgeladen 
werden muss.

von Peter D. (peda)


Lesenswert?

Sepp O. schrieb:
> Ich will nur so viele Funktionen wie möglich in den Prozessor
> verfracchten, damit nur mehr das Steuerungsprogramm selbst nachgeladen
> werden muss.

Dann wird das aber mit dem Bootsektor nichts, der ist ja nur sehr klein.


Peter

von ThomasH (Gast)


Lesenswert?

stimmt die Bootloader Section im AVR ist ja auch nicht so groß, bei mir 
war das ganze auf ARM7 bzw M3 Cortex.

Eine Frage hätte ich noch, warum willst du gewisse Teile deines 
Programmes fix nicht updatebar machen, wenn du sie im Bootloader nicht 
verwendest, damit kannst du mögliche Fehler mit Firmware Updates ja 
nicht mehr beheben? Oder ist die oberste Prämisse die neue Firmware 
möglichst klein zu halten?

Also nochmal mein Senf dazu, weiß jetzt leider nicht auswendig, ob das 
alles im AVR so geht:
Bootloader mit allen anderen fixen, nicht updatebaren Funktionen an den 
Beginn vom Flash -> das ganze Zeug muss natürlich auch gelinkt werden 
und im ELF bzw HEX file da sein für später. Hier muss der Bootloader 
natürlich jedes mal selbst in die Hauptapplikation springen.

1) Quick and dirty Variante um zu sehen ob es so funktioniert:
Hauptapplikation ist ein separates Projekt und bindet die Header Dateien 
von den gewünschten Funktionen ein, aber die dazugehörigen Files werden 
nicht kompiliert. Beim Linken sagst du dem Linker mit:
--just-symbols=filename
dass er sich die Symbole für die Adressen der Bootloader Funktionen aus 
dem ELF File vom Bootloader holen soll. Somit kannst du deine App 
kompilieren und Linken.
Nachteil: Änderungen am Bootloader schlagen sich direkt auf die APP 
durch

2) BL und APP unabhängiger gestalten:
dazu im Bootloader entweder gleich zu Beginn oder am Ende seiner Section 
ein Array mit den Adressen der Funktionen anlegen. In der Applikation 
musst du dann aber jeden Funktionsaufruf, oder die Funktion selbst, 
umschreiben und mit Funktionspointern arbeiten. Damit braucht die APP 
nur mehr den Beginn des Arrays und die Reihenfolge der Funktionen 
wissen.

von Sepp O. (Gast)


Lesenswert?

Ich glaube, ich werde es erst einmal mit einer Lib versuchen.

Aber um zu sehen ob und wie es funktioniert, werde ich die Boot-Loader 
Geschichte einmal ausprobieren.

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.