Hallo, ich arbeite gerade das AVR Tutorial durch und dabei geht mir
diese eine Frage nicht aus dem Kopf.
Im FLASH ROM befindet sich das fertige Programm und weitere Daten.
Was aber, wenn ich während des Ausführens das Programm erweitern lassen
möchte?
Ich kann ja nicht einfach in den FLASH schreiben oder den Programmzähler
in den DRAM springen lassen wo das geschriebene Programm steht (und es
als Instruktionen ausführen lassen).
Wie aber könnte ich so etwas mit einem AVR realisieren?
Bei Unklarheiten einfach fragen.
(Mit einem Laptop geht das ja auch dass ich mittels einer IDE Assembler
Code schreibe und ausführen lasse, liegt aber wahrscheinlich an den
Eigenschaften einer HDD/SDD)
Es gibt verschiedene Forth Systeme für AVRs.
Diese können das.
int 21h schrieb:> (Mit einem Laptop geht das ja auch dass ich mittels einer IDE Assembler> Code schreibe und ausführen lasse, liegt aber wahrscheinlich an den> Eigenschaften einer HDD/SDD)
Der Läpptop dürfte eher eine "Von Neumann Maschine" sein.
Dein AVR ist eher eine Harward Architektur
Theoretisch kann man sowas machen. Du musst zum Beispiel ein Interface
definieren worüber du festlegst wie du Daten mit dem teile des Programms
austauscht was neu hereinkommt. Dann musst du einen Funktionpointer auf
NULL setzten. Den rufst du nicht auf solange der auf NULL zeit. Dann
guckst du ob du im Flash eine erweiterung reinprogramiert hast. Wenn ja
dann setzt du diese Funktionspointer und rufst die erweiterung auf.
1. Erweiterung programmieren: dazu musst du irgendwie den Flash so
aufteilen dass du da etwas relativ easy einfalshen kannst.
2. Funktionspointer: Interface ist ja vorgegeben. Die addresse selbst
musst du auch irgendwo so definieren dass es irgendwie aus dem
heruntergeladene daten auslesbar ist oder immer fest ist. Prinzipiell
wenn es immer fest ist dann musst du gucken ob du da 0xFFFF hast oder
etwas anderes, und dann deine Funktion aufrufen.
3. Funktion selbst: Erstmal würde ich mit ein paar ASM befehlen
speielen. Dann könnte man versuuchne den C kompiler dazu bewegen
einzelne funktionen zu übersetzten und als library verpacken, damit es
auch flashbar wird. Irgendwie.
Ja kann man machen. Ob das aber auf einen 8 bit controller sinn macht?
Ich glaube nicht. Genauso nicht wie aus einem SD Karte eine Executable
zu laden und laufen zu lassen. Da macht schon ein 32bit kontroller mehr
Sinn. Siehe beispiel bei Olimex den Retro BSD. Der kann dynamisch
programme aus der SD Karte laden. Prinzipiell willst du sowas ähnliches.
int 21h schrieb:> Ich kann ja nicht einfach in den FLASH schreiben
Doch, die meisten AVR Modelle können das.
> oder den Programmzähler in den DRAM springen lassen
Auch das geht. Am einfachsten in C, wenn die nachinstallierten
Funktionen den gleichen Rückgabe-typ und die gleichen Parameter haben,
wie eine Funktion, die schon zum Compilierzeitpuntk existierte.
Stichwort: Function-Pointer. Google mal danach.
Gehen tut das, indem die festen Funktionen über Sprungtabellen im RAM
aufgerufen werden (z.B. Funktionspointer). Wenn Du nun eine alternative
Funktion DoThis() irgendwo anders hast, legst Du als letzten Schritt den
Funktionspointer um.
Ist in C aber in der Regel sinnlos, und gute Debugger schaffen sowas
alternativ mit ganz kurzen Turnaround-Zeiten (indem z.b. nur wirklich
geänderter Code neu geflashed wird).
Arduino Fanboy D. schrieb:> Der Läpptop dürfte eher eine "Von Neumann Maschine" sein.> Dein AVR ist eher eine Harward Architektur
Habs jetzt verstanden.
Realisieren lässt sich das ganze dann nur über Sprungtabellen im FLASH
und Daten im EEPROM die als Instruktionen simuliert werden.
wirrer Pseudocode Beispiel
________________________
EEPROM
'ldi r18 0x04' 'sub r18, 0x04' 'breq 0x07' 'rjmp 0xff'
________________________
FLASH
switch(instruction){
case 'ldi':
ldi temp1, temp2
...
}
So würde das ganze doch gehen wenn man es geschickt macht oder?
Dann braucht man aber sicher das 10 fache an Zyklen für nur einen Befehl
:/
Stefanus F. schrieb:> Auch das geht. Am einfachsten in C, wenn die nachinstallierten> Funktionen den gleichen Rückgabe-typ und die gleichen Parameter haben,> wie eine Funktion, die schon zum Compilierzeitpuntk existierte.
Leider habe ich nicht genügend Ahnung von C.
Wie würde ich das mit AVR Assembler hinbekommen?
int 21h schrieb:> Hallo, ich arbeite gerade das AVR Tutorial durch und dabei geht mir> diese eine Frage nicht aus dem Kopf.>> Im FLASH ROM befindet sich das fertige Programm und weitere Daten.> Was aber, wenn ich während des Ausführens das Programm erweitern lassen> möchte?> Ich kann ja nicht einfach in den FLASH schreiben [...]
Das kannst Du durchaus; unter kontrollierten Bedingungen. Schau mal ins
Datenblatt und in die Liste der Assemblerbefehle. Damit fängt es an.
Dann gibt es natürlich noch Organisationsstrukturen mit denen das
"erweitern" eines Programmes möglich ist. Teilweise mit und teilweise
ohne den Flash-Speicher zu beschreiben.
Das Ganze ist ein umfangreiches Thema mit einer Reihe sehr
unterschiedlicher Ansätze.
Aber fang einfach mal mit der CPU an und schau ins Datenblatt. Daraus
ergeben sich erst einmal ganz einfache Ansätze, auf die Du teilweise
auch mit Anfängerwissen kommen kannst.
Das Assembler-Mnemonic heisst SPM - Store Programm Memory.
Viele AVRs haben den Befehl, nicht alle. Damit kannst du beliebige Daten
in den Flash schreiben. Vorsicht, du darfst dir das Programm, das den
neuen Code speichert, nicht ueberschreiben, sonst kann der Befehlsfluss
durcheinanderkommen.
Bootloader verwenden uebrigens den SPM-Befehl. Der Bootloader empfaengt
das zu speichernde Programm als Daten, z.B. ueber die serielle
Schnittstelle und speichert es im Flash. Beim Starten des Controllers
wird zunaechst der Bootloader angesprungen, dieser entsvheidet dann, ob
er den Befehlszeiger auf das Programm weiterreicht, oder ein Upload
ansteht.
int 21h schrieb:> Stefanus F. schrieb:>> Auch das geht. Am einfachsten in C, wenn die nachinstallierten>> Funktionen den gleichen Rückgabe-typ und die gleichen Parameter haben,>> wie eine Funktion, die schon zum Compilierzeitpuntk existierte.>> Leider habe ich nicht genügend Ahnung von C.> Wie würde ich das mit AVR Assembler hinbekommen?
Leider habe ich nicht genügend Ahnung von Assembler :-(
Aber nur der Bootloader kann in das Programmmemory schreiben. Nicht das
ausfuehrende Program.
Und der Mega 8 ist etwas auf der kleinen Seite. Was soll der Mega8 ? 3
cents sparen ? Was spricht gegen einen 644 oder so ?
Jetzt ist G. schrieb:> Aber nur der Bootloader kann in das Programmmemory schreiben. Nicht das> ausfuehrende Program.
Doch, auch das laufende Programm kann ins Flash-ROM schreiben; es gibt
beim AVR keine hardwareseitige Unterscheidung zwischen Bootlader und
anderen Programmen.
Natürlich (aber das hat "Mach" auch schon geschrieben) darf auch Dein
laufendes Programm sich nicht selbst überschreiben bzw. erwarten, daß es
danach noch weiterläuft ...
Rufus Τ. F. schrieb:> Doch, auch das laufende Programm kann ins Flash-ROM schreiben; es gibt> beim AVR keine hardwareseitige Unterscheidung zwischen Bootlader und> anderen Programmen.
Schau dir doch einfach mal an, wie ein Bootloader programmiert ist.
Natürlich in Assembler...da wird einiges klar und man kann auch sofort
mit eigenem Testcode loslegen. Ist keine Hexerei.
Gruß Rainer
Jetzt ist G. schrieb:> Aber nur der Bootloader kann in das Programmmemory schreiben. Nicht das> ausfuehrende Program.
Nein. Es gibt hart nur eine einzige Restriktion: die SPM-Instruktion
selber muss im "Bootloader-Bereich" liegen, um tatsächlich schreiben zu
können, sonst wirkt sie wie ein NOP, macht also garnix.
ABer: Neben der Tatsache, dass sich der "Bootloader-Bereich" bei Tinys
sowieso über den gesamten Flash erstreckt (wenn SPM halt überhaupt per
fuse erlaubt ist), ist auch die Einschränkung bei Megas mit getrenntem
Bootloaderbereich kein Problem, denn es genügt ja, eine (sehr kleine)
Routine in diesem Bereich zu etablieren, die die entscheidende
SPM-Instruktion (und praktischerweise noch ein wenig Beiwerk,
insbesondere eine RET-Instruktion) enthält. Diese Routine kann dann von
überall aus dem Flash aufgerufen werden.
Natürlich gibt es dabei ein Haufen Zeug zu beachten, insbesondere, wenn
auch noch Interrupts im Spiel sind, aber grundsätzlich geht das. Es ist
nur nicht ganz einfach zu programmieren. Und der Teufel soll mich holen,
wenn ich jemals versuchen sollte, sowas in C zu realisieren. In
Assembler ist das schon anstrengend und fehlerträchtig genug...
int 21h schrieb:> Ich kann ja nicht einfach in den FLASH schreiben oder den Programmzähler> in den DRAM springen lassen wo das geschriebene Programm steht (und es> als Instruktionen ausführen lassen).
Das wird in der Tat schwierig, eigentlich aus zwei Gründen:
1. Der Programmzähler kann beim ATmega8 nur auf den Programmspeicher
zeigen und das ist der FLASH
2. Der ATmega8 besitzt gar kein DRAM
int 21h schrieb:> Was aber, wenn ich während des Ausführens das Programm erweitern lassen> möchte?
Das geht bei keinem System, auch nicht auf Deinem PC. Ein Programm muß
beendet werden, ehe man ein neues Programm laden kann.
Bei AVR kann z.B. die Applikation in den Bootloader springen, dieser
lädt dann ein neues Programm in den Flash und startet es.
Siehe auch
https://en.wikipedia.org/wiki/Self-modifying_code
War in der Anfangszeit der Programmierung ein gültiges Verfahren.
In moderner SW Entwicklung die absolute Ausnahme, da extrem
fehleranfällig.
Bei manchen Architekturen wird es auch von der Hardware unterbunden.
Z.B. wenn der Programmspeicher nur lesbar ist.
Wird auch in Viren verwendet und soviel ich weiss erzeugt Ltspice auch
einige Optimierungsroutinen im Betrieb.
int 21h schrieb:> (Mit einem Laptop geht das ja auch dass ich mittels einer IDE Assembler> Code schreibe und ausführen lasse, liegt aber wahrscheinlich an den> Eigenschaften einer HDD/SDD)
Damit hat das überhaupt nichts zu tun. Wenn du ein Programm (z.B. .exe
Datei) startest, lädt das Betriebssystem, d.h. der Kernel, den Code aus
dieser Datei in den RAM (unter Beachtung von zusätzlichen Informationen
wie Headern). Der Scheduler des Kernels wird dann an eben diese Stelle
im RAM springen, um diesen Code auszuführen. Das BIOS beispielsweise
lädt seinen Programmcode aus einem Flash/EEPROM vom Mainboard in den RAM
und führt diesen aus. Dieser Code kann dann z.B. ein Betriebssystem über
ein Netzwerk, USB-Stick, CD, oder eben auch eine Festplatte laden. Es
muss keine Festplatte involviert sein, das ist nur bei
PC-Betriebssystemen der Normalfall.
Der AVR kann nur leider keinen Code aus dem RAM ausführen, nur aus dem
Flash. Wie bereits gesagt wurde kannst du Code in den Flash schreiben
und dann ausführen, hast aber das Problem dass das Schreiben langsam und
nur begrenzt oft möglich ist.
Andere Controller wie ARM (z.B. STM32) oder MSP430 können Code direkt
aus dem RAM ausführen. Dort ist so etwas problemlos möglich. Tatsächlich
macht ein "normales" Betriebssystem wie Linux oder Windows RT, welches
auf einem ARM läuft, nichts anderes.
Mini-Beispiel:
1
.syntax unified
2
.thumb
3
.cpu cortex-m3
4
5
add r0, r0, r1
6
bx lr
Assembler-Code für eine Addition und Rückkehr auf Cortex-M3. Diesen
lässt man sich assemblisieren, und erhält:
1
00000000 <.text>:
2
0: 4408 add r0, r1
3
2: 4770 bx lr
Da Cortex-M3 Instruktionen Little Endian sind, muss man also die Bytes
0x08 0x44 0x70 0x47 in den Speicher schreiben. Dies kann man überprüfen
indem man das Kompilat binär ausgeben lässt:
1
Contents of section .text:
2
0000 08447047
Diese vier Bytes könnte man sich jetzt in ein C-Array schreiben:
um diese nun aufzurufen, muss man die Adresse des Arrays "or 1" rechnen,
um dem Sprung mitzuteilen, dass hier Thumb-Code vorliegt. In C ist das
eigentlich nicht möglich, aber mit etwas hässlicher Zeiger-Arithmetik
geht es. Dazu definiert man sich einen Funktionspointer auf den
Speicher. Als kleines Gimmick definieren wir 2 Funktionsparameter,
welche entsprechend dem AAPCS-ABI als r0 und r1 übergeben werden, und
einen Rückgabewert, welcher in r0 steht.
Ruft man den Funktionszeiger auf, wird hier also die in Assembler
kodierte Addition aufgerufen und dabei 3 und 4 übergeben. Der
Rückgabewert kann dann direkt an printf gegeben werden, Natürlich kann
man sich auch C-Code kompilieren und so aufrufen, aber bei Assembler ist
etwas leichter sichtbar was passiert.
Wenn man eine MMU/MPU nutzt, muss man natürlich noch dafür sorgen dass
der Code ausgeführt werden darf (XN-Bit auf 0). Manche RAM-Blöcke
mancher Controller können gar nicht für Code genutzt werden, wie z.B.
die CCM-Blöcke beim STM32F4. Das muss man vorher prüfen. Manche
Controller wie die STM32F7 haben aber dedizierte RAM-Blöcke extra für
Code, der extra schnell von dort ausgeführt werden kann (ITCM).
Peter D. schrieb:> Das geht bei keinem System, auch nicht auf Deinem PC. Ein Programm muß> beendet werden, ehe man ein neues Programm laden kann.
Doch geht schon(bedingt). Dafür sind mal Dynamic Link Library (DLL) bzw
shared library erfunden worden. Das eigentliche Hauptprogramm muss das
natürlich unterstützen und wenn man das mal aktualisieren muss gilt
natürlich das was du geschrieben hast.
Was dann unter ziemlich jedem ARM-Prozessor ab ARMv4T, z.B. ARM7TDMI
funktionieren sollte. Kann ja mal jemand z.B. auf einem Raspberry
ausprobieren... :-)
>Wie aber könnte ich so etwas mit einem AVR realisieren?
Du könntest beispielsweise einen BASIC-Interpreter schreiben, der ein im
SRAM als Textdatei abgelegtes BASIC-Programm ausführt. Das kannst Du
dann während der Controller läuft, jederzeit nach Belieben starten,
stoppen, unterbrechen, fortsetzen oder durch ein anderes ersetzen. Die
"großen" AVR-Controller hätten übrigens genug Leistungsreserven (Flash,
SRAM, Speed), um das tatsächlich zu realisieren.
Rainer V. schrieb:> Schau dir doch einfach mal an, wie ein Bootloader programmiert ist.> Natürlich in Assembler...da wird einiges klar und man kann auch sofort> mit eigenem Testcode loslegen. Ist keine Hexerei.
Ich wiederhole mich wirklich ungern, aber es stellen sich mir 2 Fragen:
warum geht es nicht aus deinem Kopf...und warum willst du sowas
machen???
Fast immer geht es heute ohne "sowas"!!
Punkt...Schluss!!!
Gruß Rainer
>Mit einem Laptop geht das ja auch dass ich mittels einer IDE Assembler>Code schreibe und ausführen lasse
Ja, aber ein Laptop ist auch einfach eine konzeptionell andere Maschine
als ein µC. Bei einem Laptop oder allgemein PC sorgt ein Betriebssystem
(nebst viel anderem) dafür, dass der Benutzer jederzeit nach seinen
Wünschen Programme starten und wieder beenden kann, ganz verschiedene
und auch mehrere gleichzeitig. Programme für PCs werden auf PCs
entwickelt (aber Proramme für µCs nicht auf µCs, sondern auch auf PCs).
Auf einem µC läuft dagegen immer nur ein einziges Programm mit einer
speziellen Aufgabe. Eingriffe am Code durch den Benutzer sind weder
nötig noch vorgesehen. Weil es - von Ausnahmen wie etwa einem
gelegentlichen Update abgesehen - also als unveränderlich betrachtet
wird, spricht man auch von "Firmware". Es ist zwar richtig, dass man
diese Schranke theoretisch durchbrechen kann, d. h. es ist möglich,
einen (genügend leistungsstarken) µC so zu programmieren, dass man am
Ende damit ungefähr dasselbe machen kann wie mit einem (sehr einfachen)
PC, aber sinnvoll wäre das kaum, weil die Architektur von µCs in der
Regel nicht auf diesen Zweck hin optimiert ist.