Forum: Mikrocontroller und Digitale Elektronik Mal eine Frage für die Fortgelaufenen


von TheMason (Gast)


Lesenswert?

Hallo an alle,

ich habe mal eine Frage an die Fortgeschrittenen C-Programmierer unter
euch.
Ich hab schon seit längerem eine Idee und würde diese gerne mal
test-mässig umsetzen. Ich möchte ein Mechanismus programmieren, mit dem
ich in den freien Flash-Speicher meines Mikrocontrollers Programme
nachladen / "nachflashen" kann.
Ich denke mir das folgendermassen :
Ich habe ein Grundstock an Systemfunktionen in einem Speicherbereich A
liegen. Variablen (RAM) liegen ebenfalls in einem fest definierten
Speicherbereich.
Nun möchte ich in einem Speicherbereich B Programm-Code ablegen und von
meinem Grundsystem aus starten.
Speichermässig würde das ganze so aussehen (RAM wie Flash) :

|---------------- .. ------ .. ----------------- .. ---------|
|     A         | .. | AX | .. |       B       | .. |   BX   |
|---------------- .. ------ .. ----------------- .. ---------|

AX bzw. BX sollen Bereiche sein, die für den Austausch von
Daten/Adressem von Funktionen zuständig sind.

RAM mässig müsste es genauso aussehen (also 4 Bereiche).
Nun müsste man einiges an restriktionen machen (z.b. Feste Startadresse
der Bereiche (RAM/Flash), damit das Programm B immer auf gültige Daten
zugreift, vor allem für A müssen diese Bereiche immer fest sein).

Wenn der RAM Bereich für beide Programm-Teile getrennt definiert ist,
müsste es eigentlich doch auch keine probleme mit dem Stack geben (da
ja beide programme, wegen getrennter speicherbereiche, einen eigenen
Stack haben).
Ich hab mir das ganze so vorgestellt das ich mit einem Grundsystem
mehrere Applikationen (von mir aus von SD/MMC) "laden" und ausführen
kann.
Meine Frage ist nun :

Würde das so funktionieren ? Wie würde ich ein Interface schreiben mit
dem ich im Programm B ernittele WO meine Funktionen von A liegen,
welche ich nutzen möchte ?
Was muß ich bei der Initialisierung beachten (außer das ich mir den
Reset-Vektor nicht plattbügel ...) ? Kann ich den Startup-Code von B so
einfach aufrufen ?

Ich habe bewusst keinen Prozessor-Typ genannt (ich verwende einen
MSP430), da ich das ganze universell definieren möchte, da man dieses
Prinzip (wenn es denn so funktioniert) auf alle Controller anwenden
könnte welche in der Lage sind ihren eigenen Programm-Speicher zu
flashen.

Bin mal gespannt auf eure Kommentare und Vorschläge ...

Gruß
Rene

von Karl heinz B. (kbucheg)


Lesenswert?

Du suchst nach einem 'Bootloader'
Viele AVR-Typen unterstützen so was.

Siehe zb.
 http://www.mikrocontroller.net/articles/Bootloader
 http://www.mikrocontroller.net/forum/read-4-53146.html

von TheMason (Gast)


Lesenswert?

in dem sinne ist "bootloader" richtig, aber eben nicht nur auf den
boot vorgang beschriänkt, sondern während des laufenenden betriebs
sagen kann : lade mir nun die andere applikation.
außderdem sollen ja die funktionen von meinem System A mit genutzt
werden können, ohne das diese extra in B nochmal definiert werden
müssen.
quasi ein "dll"-mechanismus für mikrocontroller und weniger einen
bootloader.

von Maddin (Gast)


Lesenswert?

Hallo,

habe auch schon an soetwas gedacht, ich benötige diese sache um einen
font nachträglich auf eine grafiksteuerung zu laden ohne das
eigentliche Programm auf dem Controller erneut zu flaschen.

also eine funktion die verweise auf speicherbereiche aktiviert und den
font an der stelle ablegt, so das man ihn sozusagen selbst entwickeln
kann, ohne ahnung vom controller haben zu müssen.

ein bootloader funktioniert ja im grunde genaus so, es wäre dann ein
fontloader.

maddin

von TheMason (Gast)


Lesenswert?

@maddin,

also daten nachzuladen ist denke ich ist nicht das problem. ich habe
eher bedenken wenn es um die ausführung eines nachgeladenen programms
geht. Wie kann ich denn denn von A aus den startup-code von B aufrufen
und nachher wieder zu A zurückzukehren.
Unmittelbar nach dem Startup Code wird ja die int main (void)
aufgerufen. wenn die main von B ausgeführt wird kann ich dann sicher
sein das mir der Prozessor zu meinem aufrufpunkt (der ja in A liegt)
wieder zurückkehrt ?

gruß
rene

von Karl heinz B. (kbucheg)


Lesenswert?

> wenn die main von B ausgeführt wird kann ich dann sicher
> sein das mir der Prozessor zu meinem aufrufpunkt (der ja in A liegt)
> wieder zurückkehrt ?

Darauf würde ich nicht bauen.
AFAIK fügt zb. der AVR-gcc in seine Startup-Sequenz
nach dem Return von main() eine Endlosschleife ein.
Wenn main() tatsächlich zurückkommt, muss ja normalerweise
irgendwas geschehen und wenn es nur eine Endlosschleife ist.

Ich denke das du so nicht weiterkommen wirst. In C ist
ein Programm eine abgeschlossene Einheit und was ausserhalb
dieser Einheit liegt ist alles undefiniert.

von TheMason (Gast)


Lesenswert?

und wenn ich nun hingehen würde und meinen eigenen startup-code (der ja
nichts weiter als die initialisierung der variablen machen muß) in
einer funktion des programms B lege um dann zu gewährleisten dass nach
aufruf der initialisierung mein programm a wieder zum zuge kommt ?
ich denke mir das es doch irgendwie möglich sein muß, zumal wenn ich
getrennte speicherbereiche (für stack/heap/variablen bezgen auf ram,
und code/const bezogen auf flash) pro programm habe ?
scheitert das ganze nur am startup-code ?

gruß
rene

von Ronny (Gast)


Lesenswert?

Wie wär es den,den Startup-Code,den Loader und den Einsprung in die
Hauptanwendung als dein Programm zu laden?Dann könnte man z.B nach
einem Reset eine Anfrage für ein neues Programm an eine serielle
Schnittstelle schicken.Wenn innerhalb von z.B. 100ms eine Antwort kommt
lädt der Loader das Programm von der Schnittstelle,andernfalls springt
er in das vorhandene Programm (was dann natürlich auch irgendwann mal
vom Loader geladen wurden sein musste).

Das main()-problem ist dagegen nicht so einfach zu lösen.Wenn man kein
stdio und co verwendet kann man VIELLEICHT auf das C-Startup Zeug
verzichten.Dann würde es reichen die definierten Funktionen und Daten
zu übernehmen.Aber eine Garantie das man nicht irgendwas vom Compiler
generiertes ausversehen weglässt hat man dann nie.

Alternativ könnte man die main() vielleicht in Assembler schreiben und
eine in C programmierte Lib mit der eigentlichen Anwendung
dazulinken.Die Lib wär dann nur eine Ansammlung von Funktionen und
Daten ohne main() die dann als extern definiert sein muss.

von mh789 (Gast)


Lesenswert?

Was Du suchst ist ein "Loader" mit "Relocation". Vielleicht noch ein
"Operating System" als Suchbegriff dazu und Du solltest fündig werden
(Theorie, keine fertigen Code-Schnipsel).

Da Dein Linker Dir die Codestücke nur für einen bestimmten
Speicherbereich erstellen kann, musst Du durch eine "Relocation" beim
Laden Deines Codes alle absoluten Sprünge im Code und alle absoluten
RAM-Adressen so verschieben, dass sie in ihrem zugewiesenen
Speicherbereich bleiben. Da alles notwendige, aber nichs falsches
anzufassen, ist ohne Zusatzinformationen fast unmöglich. Solche
Informationen kann man aber vielleicht aus dem Linker herauskitzeln.

von Ronny (Gast)


Lesenswert?

Naja,man kann mit den richtigen Linkereinstellungen schon dafür
sorgen,das alle Funktionen und Variablen in den richtigen
Adressbereichen liegen.Da braucht man dann auch nix mehr von Hand oder
mit irgendwelchen Tools zu sortieren.

Und wenn man einmal (ohne ein Betriebssystem was das für einen
übernimmt) mit relozieren anfängt,wird es recht schnell sehr
ungemütlich wenn´s an die Fehlersuche geht.

von Stefan (Gast)


Lesenswert?

Grundsätzlich sehe ich keine Probleme mit deinem Ansatz.

Dein Programm A ist quasi ein Betriebssystem und die Programme B1...Bx
sind die Anwenderprogramme.

Generationen von Programmierern haben sich überlegt, wie man ein
Betriebsystem implementiert und wie man die Hooks
(Betriebssystemfunktionen) sinnvoll ablegt. Oft wird eine Sprungtabelle
am Programmanfang benutzt. Das sollte nachlesbar sein.

Technisch am anspruchvollsten finde ich die Nachflasherei, weil du
dabei an dem Baum Äste ummodelst, auf denen du sprichwörtlich mit
deinem Betriebssystem sitzt.

Ich habe schon Datenblätter von Flash-Bausteinen gelesen, bei denen
eine Sektorierung des Flash beschrieben war. Gewisse Sektoren konnte
man dort gegen überschreiben sichern (nützlich fürs Betriebssystem),
wenn man andere neu beschrieben hat.

Allerdings durfte dort in der Zeit des Neubeschreibens nicht lesend auf
das restliche Flash zugegriffen werden, d.h. die eigentliche
Flash-Rewrite-Routine musste zuvor ins SRAM verlagert werden und von
dort aus gestartet werden.

von mh789 (Gast)


Lesenswert?

> Naja,man kann mit den richtigen Linkereinstellungen schon dafür
> sorgen,das alle Funktionen und Variablen in den richtigen
> Adressbereichen liegen.

Nur, wenn Du jeweils nur ein Programm zu einer Zeit an einer
Stelle laufen lässt.

Das könnte hier vielleicht sogar so sein. "mehrere Applikationen (von
mir aus von SD/MMC) 'laden' und ausführen" - halt nur nie
gleichzeitig.

von Ronny (Gast)


Lesenswert?

Jap,dann läuft immer nur ein Programm.Welches würde dann beim Reset
(oder einem vom Loader überwachten Event) entschieden werden.Der quasi
fliegende Wechsel ("Multitasking") ist dann natürlich nicht
möglich.Wenn genug Platz im Flash ist,kann man natürlich mehrere
Bereiche für Anwendersoftware definieren,aber dann wird es wieder ´ne
ganze Ecke komplizierter (Stichwort Task switchin,Task Context sichern
usw),von erhöhten RAM bedarf und Rechenleistung mal ganz abgesehen.

Den Bootloader ins RAM zu kopieren ist die meist verwendete Variante.
Theoretisch könnte man auch externen Flash für die Anwendung(en)
anknüpfen und den Loader ins interne Flash packen.

von TheMason (Gast)


Lesenswert?

@all

hups .. jetzt habe ich die ganze diskussion verpasst :-(

@m789

mit dem relokatiblen code ist insofern egal, als das ich dem linker
einfach nur sage das das programm in einem bereich gebracht wird der
nicht vom betriebssystem benutzt wird.

und ich hatte kein multitasking vor :-) und wenn dann nur kooperatives

@ronny

ich hatte mir gedacht das ich über einen geeigneten mechanismus die
funktionen des programms A dem programm B zur verfügung stelle und
umgekehrt (deswegen auch die bereiche AX und BX, jeweils für RAM und
Flash)

@stefan

also bei meinem "betriebssystem" was quasi mein programm A ist weiß
ich einfach in welchem speicherbereich es steht (linkerfile).
und wenn dann sollte eh nur ein einziges programm nachgeladen werden.
mit der sprungtabelle hatte ich mir auch überlegt (wie gesagt
speicherbereich AX und BX)


mal was behind the scenes :

mir ist die idee gekommen weil ich an einem "mini-betriebssystem"
(funktionsansammlung welche prozesse, software-timer, fifos, message
queues, devices und später auch statemachines und einen parser bietet)
programmiere welches mit relativ wenig aufwand auf mehrere prozessoren
portierbar und vor allem wiederverwendbar ist. weiterhin ist dieses
system in weiten grenzen konfigurierbar und ist als kooperatives
betriebssystem ausgelegt. evtl. werd ich hier mal vor-/ reinstellen
...

der gedanke mit dem "nachflashen" ist mir gekommen um z.b.
benchmark-programme/profiling-programme oder software updates für
applikationen laufen zu lassen die man von sd-karte laden kann.
ausgangsformat wäre dann ein hex-file (da kann man dann auch gucken ob
das programm in dem richtigen speicherbereich liegt). das man die
betriebssystem funktionen dabei nutzen kann (muß) ist schon fast
"zwangsläufig".

das einzige was ich noch rausfinden muß ist, wie man am besten so ein
interface (datenaustausch der programme) aufbaut, und was der
startup-code schlimmstenfalls machen kann (sprich : was der außer
initialisierung der variablen noch machen kann, was ich nachbilden
muß)

für vorschläge immer offen ...

gruß
rene

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.