Forum: Mikrocontroller und Digitale Elektronik Programm während des Laufens erweitern möglich? (Atmega8)


von int 21h (Gast)


Lesenswert?

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)

von Einer K. (Gast)


Lesenswert?

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

von kyrk.5 (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von A. S. (Gast)


Lesenswert?

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).

von int 21h (Gast)


Lesenswert?

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 
:/

von int 21h (Gast)


Lesenswert?

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?

von Theor (Gast)


Lesenswert?

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.

von Mach (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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 :-(

von Purzel H. (hacky)


Lesenswert?

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 ?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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 ...

von Rainer V. (a_zip)


Lesenswert?

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

von c-hater (Gast)


Lesenswert?

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...

von Wolfgang (Gast)


Lesenswert?

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

von Rainer V. (a_zip)


Lesenswert?

Man o man, zumindest die AVR's können jederzeit ins Flash schreiben! 
AVR-Forth ist ja schon genannt worden. Wo ist das Problem???
Gruß Rainer

von Peter D. (peda)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

Ich denke schon, dass ein Programm zusätzlichen Code in den (freien) 
Flash nachladen kann und dann aufrufen.

von Josef (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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:
1
const uint8_t instructions [4] = { 0x08, 0x44, 0x70, 0x47 };

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.
1
int main () {
2
  uint32_t (*fPtr) (uint32_t, uint32_t) =
3
    (uint32_t (*) (uint32_t, uint32_t)) (((uint32_t) &instructions) | 1);
4
  
5
  printf ("%u", fPtr (3, 4)); // Sollte 7 ausgeben
6
}

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).

von Irgendwer (Gast)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

PS: Wenn man das Beispiel minimal abwandelt:
1
.syntax unified
2
.thumb
3
.cpu arm7tdmi
4
5
adds r0, r0, r1
6
bx lr

Erhält man Thumb1-Code
1
  0:  1840        adds  r0, r0, r1
2
  2:  4770        bx  lr

bzw.
1
static const uint8_t instructions [4] = { 0x40, 0x18, 0x70, 0x47 };

Was dann unter ziemlich jedem ARM-Prozessor ab ARMv4T, z.B. ARM7TDMI 
funktionieren sollte. Kann ja mal jemand z.B. auf einem Raspberry 
ausprobieren... :-)

von LostInMusic (Gast)


Lesenswert?

>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.

von Stefan F. (Gast)


Lesenswert?


von Rainer V. (a_zip)


Lesenswert?

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

von LostInMusic (Gast)


Lesenswert?

>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.

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.