Hi,
ich habe absichtlich nicht Bootloader in den Titel geschrieben, denn ich
moechte nur "fast" einen Bootloader bauen. Der Hintergrund ist der
folgende:
Ich habe ein gut funktionierendes Funkprotokoll (CRC, ACK, encr) laufen.
Das Funknetzwerk hat einzelne Nodes. Jede Node hat einen grossen Teil
Code, der identisch ist (naemlich das Protokoll, usw.).
Es gibt auch einen Server, der mit dem PC verbunden ist.
Der Teil, der ab und zu ein Update braucht ist nur, wie auf Kommandos
reagiert werden soll. Das heisst im Wesentlichen eine einzelne Funktion
(und ausschliesslich von ihr benutzte daten) zB:
react(uint8_t *, uint8_t len);
Dabei benutzt der Funkcode externe ISRs und Timer. Die Reaktion auf ein
Datenpacket braucht normalerweise keine ISRs oder aehnliches. Der
"Bootloader" soll auch nicht beim Neustart sondern immer laufen, ein
Kommando triggert dann nur das beschreiben des Flash.
Das recyclen der Funktionen aus dem Bootloader und dann springen in den
App Code ueber jump tables. o.Ae. scheint ein bisschen zu viel.
Naiv wuerde ich erwarten, dass ich einfach nur eine Funktion zum Flash
ab einer bestimmten Stelle schreiben einbauen muss und dann dem
"Bootloader" (der eigentlich das Hauptprogramm ist) mitteilen muss, dass
er in der Hauptschleife einmal die Funktion aufrufen an der Stelle
aufrufen und der zwei Variablen uebergeben muss: react.
Und der Flashteil, wo die sitzt ist halt ueberschreibbar.
Vielleicht ist die Idee naiv - ich habe mich mit Bootloadern noch nicht
tuefgehend beschaeftigt. Ich wuerde mich ueber Kommentare freuen.
Gruss
Ich hab den Eindruck, Du hältst ein software-update für gleichwertig zur
Aufnahme irgendwelcher Daten zur Verarbeitung in einem Programm.
Das updaten ist m.E. aber wesentlich heikler und auch zeitraubender als
eine normale Datenübergabe in ein RAM.
Die übliche Programmausführung wird beim bootloaden behindert oder gar
gesperrt.
Als Reaktion auf ankommende Daten häufig ein update zu machen dürfte ein
ziemlich riskanter Weg sein, was die Zeitabläufe angeht.
Auch wenn die EEPROMs schon eine hohe Zubverlässigkeit haben, stellt
meiner Meinung nach häufige Umprogrammierung auch noch immer einen
Verkürzungsfaktor für die Datenhaltigkeit dar.
Ist es nicht einfacher, jedem Node den absolut identischen Code zu
verpassen und mit einem Switch-Case anhand eines Flags im EEPROM oä. zu
entscheiden, was gemacht werden soll? Oder ist es notwendig, dieses
Stückchen Code ständig und überall ändern zu können?
Peter R. schrieb:> Ich hab den Eindruck, Du hältst ein software-update für gleichwertig zur> Aufnahme irgendwelcher Daten zur Verarbeitung in einem Programm.>
Nein.
---
@ Georg:
Das hatte ich auch schon ueberlegt. Es ist aber ein bisschen komplexer
als es nur mit ein paar Flags zu machen waere. Man muesste dann schon
fast einen Parser basteln, und das sprengt wohl auch wieder den Umfang.
Jedenfalls sprengt es den EEprom der Controller, die ich momentan
einsetze.
Daher meine Idee, diese eine Funktion im Flash auf eine bestimmte Stelle
zu schreiben und ein Update (ein ueberschreiben) der Funktionalitaet
(wie auf uebergebene Daten aus dem RAM reagiert wird) zuzulassen.
Natuerlich nur, wenn ein Firmware update durchgefuehrt wird und nicht
bei jedem Eintreffen neuer Daten.
Jan K. schrieb:> ich habe absichtlich nicht Bootloader in den Titel geschrieben, denn ich> moechte nur "fast" einen Bootloader bauen. Der Hintergrund ist der> folgende:
Usw.
Vorab, der Begriff Bootloader wird im Zusammenhang mit Microcontrollern
m.E. oft ungenau oder falsch gebraucht. Im allgemeinen bezeichnet
bootstrap loader ein beim Start eines Computers bereits vorhandenes und
initial ausgeführtes Programm, das einfach als Loader fungiert, also
weitere Programmstücke in den volatilen Speicher (aka RAM) laden und
dann ausführen kann, ggfs. auch mehrstufig. Die Möglichkeit, diese
nachgeladene Programm in einen weiteren nichtvolatilen Speicher zu
übertragen und ggfs. bei nachfolgenden Einschaltvorgängen ohne bootstrap
direkt auszuführen, oder sogar in einem weiteren Schritt den initialen
Bootloader auszutauschen, ist damit nicht zwingend verbunden oder
gleichzusetzen. Es scheint aber so, daß genau dieses (quasi ein
Bootloader, der sich wie ein Brennprogramm verhält, das ihm übergebene
Programm also nicht abschließend ausführt, sondern in nichtvolatilem
Programmspeicher aka Flash ablegt) in diesem Umfeld der typische
Sprachgebrauch geworden ist.
So einen Bootloader brauchst Du in der Tat nicht. Allerdings
unterscheidet sich das, was Du tun möchtest, m.E. nur bezüglich des
Codeumfangs davon, insofern liegst Du mit "fast" schon ganz richtig.
Der hauptsächliche Unterschied ist, daß Dein "Bootloader" groß und der
nachzuladende Teil klein ist. Etwas mehr als der "Bootloader" mußt Du
allerdings insofern tun, als der mit dem Ablegen des Programms im Flash
seine Arbeit erledigt hat, während Du Dir ggfs. auch noch einen
Mechanismus für das Binden (das, was man früher einen Linker nannte -
http://de.wikipedia.org/wiki/Linker_%28Computerprogramm%29) - ausdenken
musst.
> Naiv wuerde ich erwarten, dass ich einfach nur eine Funktion zum Flash> ab einer bestimmten Stelle schreiben einbauen muss und dann dem> "Bootloader" (der eigentlich das Hauptprogramm ist) mitteilen muss, dass> er in der Hauptschleife einmal die Funktion aufrufen an der Stelle> aufrufen und der zwei Variablen uebergeben muss: react.
Genau. Bzw. umgekehrt, Du reservierst ein Stück Programmspeicher für
die nachzuladende Funktion (wenn es nur eine ist, entfällt das Linken,
dann fängt die einzige Funktion einfach am Anfang an) und die dort
abgelegte Funktion wird schlicht dort aufgerufen. Natürlich mußt Du Dir
Gedanken über Anfangsbedingungen machen (was steht da anfänglich drin,
eine Dummyfunktion, oder eine Defaultfunktion?) und darüber, daß sich
die allgemeine Programmausführung und das zeitraubende Überschreiben der
nachzuladenden Funktion nicht in die Quere kommen. Es kann auch nicht
schaden, das Verfahren so robust wie möglich auszulegen, also den
übertragenen Codeblock mit einer Prüfsumme abzusichern etc.
HTH
Und danach kommen die speziellen Eigenschaften deines Controllers ins
Spiel.
* Unter welchen Umständen kann das Flash programmiert werden?
- Im allgemeinen können im betroffenen Flashbereich keine Lesezugriffe
vorgenommen werden, während das Flash gelöscht oder geschrieben wird.
Also keine Programmausführung, keine ISRs, keine konstanten Daten lesen
in diesem Bereich zu dieser Zeit.
* Wie ist die Architektur des uC?
- Havard: keine Programmausführung im RAM Bereich. Denkbar ist das
Einblenden von RAM in den Codebereich. Beim ATmega kann der Bootblock
das restliche Flash löschen/schreiben.
- von Neumann: Programm kann im RAM ausgeführt werden. Dazu wird der
Flash Code ins RAM kopiert und dort ausgeführt. Er muss natürlich
entsprechend lokatiert sein.
* Wie ist die Segmentierung des Flashs?
- Was ist die kleinste Segementgröße die gelöscht werden kann?
- Wie groß ist der Code der geschrieben werden soll?
- Ist genug RAM vorhanden um den neuen Code zu puffern und in einem
Rutsch zu schreiben? Oder muss das in Häppchen unterteilt werden?
Wenn wir jetzt wüssten, um welche(n) Controller es sich handelt, hagelt
es bestimmt lauter gut gemeinte Ratschläge. Aber so ist das alles noch
zu akademisch.
Gruß,
Bernd
Danke fuer eure Antworten, Bernd, Wolfgang.
Ja, ich habe voellig vergessen, welche Controller ich verwende - das
steht aber sogar schon fest, weil die Hardware schon existiert:
Ich verwende AVRs, genaugenommen Attiny841. Da bin ich auch (selbst wenn
die Hardware nicht existierte) festgelegt, weil ich die beiden 16bit
Timer, HardwareSPI usw. brauche.
Der hat keine separate Boot-Section im Flash, nicht genug RAM um den
gesamten zu schreibenden Code zu puffern. Allerdings existieren kleine
Bootloader dafuer bereits, und self-programming kann der laut Datenblatt
auch.
Man muss immer 4 pages auf einmal loeschen, das macht 4*8 words. Das
kann ich gut im RAM puffern. Waehrend der erase/write Zeiten muss ich
halt aufpassen, dass das Timing stimmt. Wenn dort ISRs oder das
restliche Programm aussetzen bedeutet das nur, dass der Sender des Codes
eben warten muss und keine Antwort bekommt. Das macht das Funkprotokoll
sowieso. Nur der timeout muss ggf. angepasst werden. Auch Pruefsumme
etc. ist schon im Protokoll implementiert, sollten es mehrere Packete
werden gibts eben eine eben noch eine obendrauf.
Gruesse
Jan K. schrieb:> Ich verwende AVRs, genaugenommen Attiny841. [...]> Man muss immer 4 pages auf einmal loeschen, das macht 4*8 words.
Da nehmen sich die Controller von Atmel und Microchips offenbar nichts.
Der 12F1840 z.B. erlaubt ebenfalls erase/write in Blöcken/rows/pages von
32 words.
Bedenke, daß der Program-Flash nur eine Endurance von 10.000 solcher
Zyklen hat, statt der 100.000 des EEPROM. Je nach Updatefrequenz sind
die ziemlich schnell aufgebraucht.