Hallo, es gibt ja die Möglichkeit ein Firmware-Update mittels Bootloader durchzuführen. Dabei wird aber die Firmware komplett neu (bis auf den Bootloader) in den internen Flash geschrieben. Ist es möglich Firmware auch modular im internen Flash auszutauschen? Ich stelle mir das Ganze so vor: -Hauptmodul (enthält Firmware-Updater) -Tabelle mit Funktionszeigern -Funktionsmodul 1 -Funktionsmodul 2 -Datenmodul 1 -Datenmodul 2 -Bootloader Die Funktions- und Datenmodule liegen mit ausreichend Platz zwischeneinander (für Änderungen der Module) im Flash an festen Adressen. Die Adressen werden im Linkerskript festgelegt. Alle Funktionen in den Funktionsmodulen können mittels Funktionszeigern vom Hauptmodul aufgerufen werden. Funktionsaufrufe innerhalb der Funktionsmodule sollten ohne Funktionszeiger funktionieren. Wenn ein Funktions- oder Datenmodul ausgetauscht werden soll, dann befindet sich das Hauptmodul in der Firmware-Update-Funktion. Diese überschreibt den internen Flash mit dem neuen Modul aus dem externen Flash. Danach wird ein Software-Reset ausgeführt um Inkonsistenzen zu verhindern. Ich habe bisher nirgends ein Konzept für so etwas gefunden. Kann ich also davon ausgehen, dass ein modulares Firmware-Update aufgrund bestimmter Dinge unpraktikabel bzw. unmöglich ist? Antworten die über ein "geht"/ "geht nicht" hinausgehen würde ich toll finden. Ich denke dass eine evtl. angestossene Diskussion auch Anderen ein besseres Verständnis über die Funktionsweise von Mikrocontrollern geben würde.
Geht schon, macht im allgemeinen nur keinen Sinn, einzelne Module auszutauschen. Der Aufwand dafür ist viel höher, als wenn die ganze Software neu geflasht werden soll. Warum baust du die einzelnen Module nicht am PC in der benötigten Kombination zusammen und flashst genau diese? ...dann brauchst du auch keinen Freiraum zwischen den Modulen auszusparen, sparst dir die Funktionszeigertabelle, es gibt keine Inkonsistenzen... Damit sind alle deine Nachteile ausgeräumt. :-)
Christian B. wrote: > Antworten die über ein "geht"/ "geht nicht" hinausgehen würde ich toll > finden. Ich hätte erstmal ne Frage: was soll das überhaupt bringen? Außer nem Haufen Nachteilen sehe ich keinerlei Vorteile. Funktionen können nicht mehr direkt aufgerufen werden, sondern über einen Dispatcher. Variablen können nicht mehr direkt angelegt werden, sondern nur über malloc (mit der Möglichkeit des Fehlschlags!). Es kostet also mehr SRAM, Flash und CPU-Zeit. Von den Huddeleien mit dem Linker ganz zu schweigen. Peter
@Peter: Peter Dannegger wrote: > Ich hätte erstmal ne Frage: was soll das überhaupt bringen? > Außer nem Haufen Nachteilen sehe ich keinerlei Vorteile. Vorteile aus meiner Sicht: -die Zeit bis das System wieder normal reagieren kann wird verkürzt -ich hätte immer ein funktionierendes System, wenn ich das alte Funktionsmodul vor dem Kopiervorgang irgendwo temporär speichere -die Menge der zu übertragenenen Daten wird reduziert, was einen schon evtl. stark belasteten Bus entlastet, -wenn beispielsweise das Update über GPRS (packetorientiert) für viele tausend Geräte gemacht wird kann das auch ein paar Taler sparen und die Server-Seite entlasten (ca. 1 cent/ 1 kB, anstelle von 200 kB nur 20 kB Code übertragen macht eine Einsparung von 1,80 EUR/ Update) > Funktionen können nicht mehr direkt aufgerufen werden, sondern über > einen Dispatcher. Ich schätze mal, dass Du Deine Funktion "u8 execute(u8 func_no)" aus dem Thread "Absolute Funktionsadressen in Tabelle ablegen" (Nr. 66866, Posting am 11.04.2007) als Dispatcher bezeichnest. Das es pro Funktionsmodul so eine "Dispatcher"- Funktion geben muß leuchtet mir ein. Wenn ich aus dem Hauptmodul eine Funktion in einem Funktionsmodul aufrufen möchte, dann rufe ich die azugehörige "Dispatcher"-Funktion mit dem Argument "Index von Funktions-Adress-Array's" auf, welches beispielsweise die Funktion Read_XYZ im Funktionsmodul adressiert. D.h. der Dispatcher hat ein Array in dem die Adressen der Funktionen stehen die von außerhalb aufgerufen werden sollen. Richtig so? > Variablen können nicht mehr direkt angelegt werden, sondern nur über > malloc (mit der Möglichkeit des Fehlschlags!). Ich stimme auch überein, dass man Variablen nur noch mit malloc() anlegen darf, da bei jedem neuen "Make" die Variablen vermutlich neue Adressen im RAM erhalten. Die alten Module konnen also Speicherkollisionen mit den neuen Modulen haben. > Von den Huddeleien mit dem Linker ganz zu schweigen. Da sehe ich auch Probleme: 1) Kann ich dem Linker beibringen, dass die Dispatcher-Funktion von Modul 1 an Adresse X im Flash liegen soll und die restlichen Funktionen von Modul 1 darauf folgen sollen? Ich weiß nur dass man dem Linker sagen kann wo Code und wo Daten im Flash liegen sollen. 2) Können lokale Funktionen innerhalb eines Funktionsmoduls einander ohne Pointer aufrufen? Da sollte es doch keine Probleme geben oder? @Gast: Gast wrote: > Warum baust du die einzelnen Module nicht am PC in der benötigten > Kombination zusammen und flashst genau diese? Ich müßte doch trotzdem immer noch den kompletten Code neu flashen. Oder habe ich das falsch verstanden? Bitte erschlagt mich nicht, wenn ich etwas übersehen oder falsch verstanden habe ;-) Gruß Christian
Da Du anscheinend C verwenden willst, erzeugt man dadurch nicht für jedes Modul redundanten Overhead?
> Vorteile aus meiner Sicht: > -die Zeit bis das System wieder normal reagieren kann wird verkürzt Um wieviele Bruchteile von Sekunden? > -ich hätte immer ein funktionierendes System, wenn ich das alte > Funktionsmodul vor dem Kopiervorgang irgendwo temporär speichere Nein, wenn du deine Sprungtabelle beim Update aufmischst nützt dir das alte gespeicherte Modul auch nichts mehr. > -die Menge der zu übertragenenen Daten wird reduziert, was einen schon > evtl. stark belasteten Bus entlastet, Wenn du dir eine Unterbrechung durch ein Firmware-Update auf dem System nicht leisten kannst und Auszeiten so kritisch sind, dann denk mal drüber nach das gesamte System doppelt auszulegen. In einer Aktiv/Passiv- oder Aktiv/Aktiv-Konfiguration. Das ist viel Arbeit, aber immer noch besser als im Flash rumzupopeln. > -wenn beispielsweise das Update über GPRS (packetorientiert) für viele > tausend Geräte gemacht wird kann das auch ein paar Taler sparen und die > Server-Seite entlasten > (ca. 1 cent/ 1 kB, anstelle von 200 kB nur 20 kB Code übertragen macht > eine Einsparung von 1,80 EUR/ Update) Bessere Mobilfunk-Konditionen aushandeln. Gibt es für Großkunden. Tausend Geräte a 200kb macht 200 MB. Das ist nicht die Welt.
Vielleicht solltest Du erstmal sagen, um welche CPU und um welche Codegrößen es sich überhaupt handelt. Bei mir geht es z.B. um 8051/AVR mit 2kB..32kB Code. Und da lade ich lieber alles komplett neu. Man muß auch sehen, ob sich der zusätzliche Entwicklungsaufwand und die warscheinlich höhere Fehleranfälligkeit überhaupt rechnet. Je komplexer ein System, umso mehr Fehler kann man ja beim Entwickeln machen. Man sieht es ja sehr schön, wie es bei Windows an allen Ecken und Enden kracht und knirscht, nur weil unterschiedliche Programme unterschiedliche Versionen von irgendwelchen DLLs benötigen. Dieses blöde DLL-Zeugs ist ja quasi so ein modulares Konzept (leider kein gutes). Peter
Norgan wrote: > Nein, wenn du deine Sprungtabelle beim Update aufmischst nützt dir das > alte gespeicherte Modul auch nichts mehr. Ich hab eher daran gedacht, dass jedes Modul eine eigene Sprungtabelle hat und damit die Sprungtabelle vom alten Modul weiterhin stimmt (wenn ich das alte Modul wieder zurückschreibe wenn das neue Modul nicht funktioniert). > Tausend Geräte a 200kb macht 200 MB. Das ist nicht die Welt. Ok, die eine Seite ist dass man das Verhältnis Nutzen/Aufwand abschätzen muß...sehe ich ein. Mich würde aber trotzdem brennend interessieren ob der oben umrissene Update-Mechnismus funktionieren kann. Um eben auch eigene Denkfehler zum Zusammenspiel Hard-/ Software bei uC's zu erkennen. Gruß Christian
Peter Dannegger wrote: > Vielleicht solltest Du erstmal sagen, um welche CPU und um welche > Codegrößen es sich überhaupt handelt. Bei mir handelt es sich um einen Controller mit ARM7-Core, 512k Flash und 32k SRAM (+externer SDRAM und Flash). Bei dem internen Flash wird es langsam knapp, deshalb der externe Flash für Daten. Jetzt kann man sofort sagen, bei soviel externem Flash und SDRAM sollte es Null Probleme geben ein sicheres komplettes Firmware-Update durchzuführen. Anregungen dazu sind auch willkommen. Mich würde aber interessieren ob das o.g. Konzept funktionieren kann bzw. was man noch berücksichtigen muß. Gruß Christian PS: Ich hab schon verstanden, dass es irgendeinen Grund geben muß warum alle nur komplett die Firmware ersetzen, aber was ist der wirkliche Knackpunkt?
Jörg B. wrote: > Da Du anscheinend C verwenden willst, erzeugt man dadurch nicht für > jedes Modul redundanten Overhead? Denkst Du da an die hier in Thread so bezeichnete Dispatcher-Funktion? Oder was meinst Du?
Ich dachte an die in C eingebauten Funktionen zum Rechnen, Anzeigen oder ähnlichen die dann möglicherweise in jedem Modul neu vorhanden sind...
Jörg B. wrote: > Ich dachte an die in C eingebauten Funktionen zum Rechnen, Anzeigen oder > ähnlichen die dann möglicherweise in jedem Modul neu vorhanden sind... Da ist was dran *grins. Also darf nicht nur das Hauptmodul auf Funktionen in Modulen zugreifen, sondern es muß auch Funktionen des einen Moduls gestattet sein auf Funktionen in anderen Modulen zuzugreifen (mit den gleichen Mechanismen)?
>> Nein, wenn du deine Sprungtabelle beim Update aufmischst nützt dir das >> alte gespeicherte Modul auch nichts mehr. > > Ich hab eher daran gedacht, dass jedes Modul eine eigene Sprungtabelle > hat und damit die Sprungtabelle vom alten Modul weiterhin stimmt (wenn > ich das alte Modul wieder zurückschreibe wenn das neue Modul nicht > funktioniert). Du musst an einem Punkt die Sprungtabelle, welche die anderen Module benutzen um in das zu ändernde bzw. geänderte Modul einspringen zu können, neu schreiben. Stromausfall mitten drin: Eine Hälfte zeigt schon in das neue Module, die andere noch in das alte Modul. Viel Spass. Programmierfehler mitten drin? Viel Spass. Inkompatible Module (neues Modul erwartet, dass bereits andere neue Module da sind, die sind es aber nicht, geänderte Sprungtabelle). Viel Spass. Ja, auch das kann man mit mehr und trickreicherem Code regeln, z.B. ein Transaktions-Log im EEPROM mitschreiben, nur ist das nichts, was man mal so aus Jux macht weil es so cool ist. Zu sowas greift man nicht ohne Not.
Vorschlag: Bau dein Programm in etwa wie eingangs beschrieben auf, einzelne Funktionen auf Flash-Blöcke alligned, mit Zwischenraum. Keine Funktionspointertabellen ö.ä. nötig. Für ein Update kompilierst du alles neu, und machst ein diff zw. altem und neuem Hex. Die Funktionen sollten dabei großteils an den selben Stellen bleiben, d.h. Funktionsaufrufe etc. bleiben gleich. Jetzt musst du nur noch die geänderten Flash-Blöcke übertragen und flashen, hast aber trotzem ein 100%aktuelles Zielsystem. Ohne die Zwischenräume + alignment verschiebt dir natürlich eine Änderung allen nachfolgenden Code... Und wenns unabhängig von der Zielsystem-Softwareversion gehen soll, muss der Bootloader dort halt CRCs der vorhandenen Blöcke generieren und die mit dem Upload-Program austauschen...
@Norgan: Ich sehe mich schon mit meinen 2 Hardware-Breakpoints verzeifeln *grins. Durch das ständige Haareraufen eine Glatze bekommend...
Ernst Bachmann wrote: > Für ein Update kompilierst du alles neu, und machst ein diff zw. altem > und neuem Hex. Das würde folgendes Bedeuten: Ich ändere eine Funktion in Funktionsmodul_1, damit verschieben sich die Adressen der folgenden Funktionen in diesem Modul. Deshalb wird sich auch in allen Modulen, die irgendwelche Funktionen in Modul_1 aufrufen der Code ändern (da sich ja die Adressen geändert haben). Kann ich dann davon ausgehen, dass ich fast den kompletten Code neu flashen muß?
Hallo, keine Ahnung, wie das in C handhabbar gehen könnte... Am Anfang jedes Moduls ist eine Tabelle mit Sprüngen zu den im Modul befindlichen Funktionen. Jeder Funktionsaufruf kennt nur den Beginn dieser Tabelle (Startadresse des Moduls) und den Offset. Dann kann sich innerhalb eines Moduls ändern, was will. Wenn man Reserve bei der Tabelle einplant, kann mach auch Funktionen hinzufügen, die dann natürlich nur von neuen Modulen benutzt werden können, die die Bedeutung der neuen Offstes kennen. Das ging schon beim C64 so, war allerdings ASN... ;-) Gruß aus Berlin Michael
>Funktionsaufruf kennt nur den Beginn
Es sollte allerdings auch ein "Ende der Sprungtabelle" markiert sein, zB
durch einen Nullpointer.
Weiterhin wäre es sinnvoll, wenn jedes Modul eine Art Versionsnummer
hat, um sagen zu können, ob alle Funktionen unterstützt werden
Hallo, kann man da doch einbauen. Anzahl der Funktionen an den Anfang, Version danach, dann die Liste. Das mitzutesten macht doch wenig Aufwand, allerdings bleibt bei einem µC-Konzept wohl sinnvoll nur, das bei Systemstart zu prüfen und dann gleich mit einem DeadEnd abzubrechen, wenn was nicht stimmt. Wenn die Module noch FallBack-Lösungen enthalten sollen, ist wohl ein RealTime-OS, daß den Kram zur Laufzeit nachlädt, die bessere Wahl. Gruß aus Berlin Michael
Michael U. wrote: > Am Anfang jedes Moduls ist eine Tabelle mit Sprüngen zu den im Modul > befindlichen Funktionen. Ja. > Jeder Funktionsaufruf kennt nur den Beginn dieser Tabelle (Startadresse > des Moduls) ... Ja. >> ... und den Offset. Meinst Du mit Offset den Abstand zwischen den Sprungadressen in der Tabelle?
Michael U. wrote: > Wenn die Module noch FallBack-Lösungen enthalten sollen, ist wohl ein > RealTime-OS, daß den Kram zur Laufzeit nachlädt, die bessere Wahl. Ein RTOS hätte vermutlich auch den Vorteil Funktionsmodule solange für andere sperren zu können bis sicher ist, dass diese vollständig geflasht wurden und die Sprungtabelle wieder aktuell ist.
Was versprichst du dir von der Diskussion? Natürlich ist eine modulare Firmware realisierbar. Alles ist realisierbar wenn man genug Zit und Geld übrig hat. Die Frage sollte eher lauten: brauchst DU eine modulare Firmware? Falls nein, warum zerbrichst du dir darüber den Kopf?
Gast wrote:
> Was versprichst du dir von der Diskussion?
Hatte ich eig. oben schon erwähnt. Aus 2 Gründen:
1.) Um herauszubekommen ob man eine modulare Software auf diese oder
eine andere Art und Weise realisieren kann.
2.) Um herauszufinden womit ich mich noch beschäftigen sollte, damit ich
das nächste mal nicht so blöde Fragen im Forum stelle ;-)
Hi, @Christian: mal die ungeliebte ;-) Antwort nach Sender Erewan: Im Prinzip ja, aber ... Machbar ist das. Aber zum Schluß bist Du bei einem dynamischen Modul-Loader a la den bekannten Betriebssystemen. Eine Sprungtabelle ist eine Vereinfachung, wird Dir aber vermutlich schnell a) Probleme bereiten und b) nicht mehr Deinen Ansprüchen gerecht. Da ich beruflich mit u.a. wirklich großen Embedded-Systemen zu tun habe, man dort auch daran gedacht hat, dies aber verworfen hat: laß es! Der Verwaltungsaufwand, sei es Code, sei es Sicherstellung, das nicht zum Schluß doch etwas Inkompatibles geladen wird und Dein System in eine Resetschleife gerät, ist schlicht zu hoch. Insbesondere, wenn Du auf die Download-and-Flash-Zeit anspielst! (in der Regel dauert das Flash-Page-Löschen systembedingt am längsten!) Hier könntest Du ev. überlegen, das Du nur eine Differenz zum Vorgänger flasht. Was aber voraussetzt, das Du den Vorgänger kennst, ansonsten hättest Du unnötige Download-Zeit. Alternativ ginge auch ein Mechanismus, der "oben" und "unten" über eine Page eine Checksumme rechnet und nur im Differenzfall überträgt und flasht. Das könnte u.U. mehr sparen und in der Verwaltung des Code weniger aufwendig sein. Schönen Tag noch, Thomas
tom wrote: > Hier könntest Du ev. überlegen, das Du nur eine Differenz zum Vorgänger > flasht. Was aber voraussetzt, das Du den Vorgänger kennst, ansonsten > hättest Du unnötige Download-Zeit. Alternativ ginge auch ein > Mechanismus, der "oben" und "unten" über eine Page eine Checksumme > rechnet und nur im Differenzfall überträgt und flasht. Klingt logisch, wobei die Praxis eventuell zeigt, dass die Übersetzungsmechanismen (Compiler, Linker) an so ein Konzept angepaßt werden müssen (damit sich bei kleineren Änderungen nicht der ganze Code ändert). Oder gibt es solche Optionen schon??? Bei Datenblöcken könnte man es ja so machen: Einzelne Datenblöcke am Ende vom Code. Aber mit ausreichend Platz zueinander. Um Sicherzustellen, dass sich die Adressen im Flash nicht ändern wenn man einen Datenblock verändert. Das würde auch ein modulweises Ersetzen den Datenblöcke ermöglichen bzw. einem Vorgehen nach Deinem Vorschlag noch mehr Wirkung verleihen. Mein Eindruck ist jetzt, das der von Tom vorgeschlagene Weg am praktikabelsten ist. Wenn jetzt noch jemand sagt, das es die oben angesprochene Compiler-Option gibt, dann gebe ich endlich Ruhe ;-) Gruß Christian
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.