Forum: Mikrocontroller und Digitale Elektronik C-Funktionen vom RAM ausführen?


von M. (Gast)


Lesenswert?

Hallo zusammen,

weiß jemand, wie man auf weinem AVR32 eine C-Funktion in den RAM 
kopiert,
und von da ausführt?

Grüße
M.

von Mark B. (markbrandis)


Lesenswert?

Meinst Du das hier?

AVR32825: Executing code from external SDRAM

http://www.atmel.com/Images/doc32160.pdf

von Mike (Gast)


Lesenswert?

Also ich bin nicht wirklich fit was so Speicher angeht aber....
Das geflashte Programm liegt ja im ROM. Zur Laufzeit wird das doch in 
einen RAM geladen und dort ausgeführt.
Odr meinst du einen externen RAM?

von Georg G. (df2au)


Lesenswert?

Mike schrieb:
> Zur Laufzeit wird das doch in
> einen RAM geladen und dort ausgeführt.

Warum sollte man das machen? Das bleibt im Flash.

von Werner M. (Gast)


Lesenswert?

Mike schrieb:
> Also ich bin nicht wirklich fit was so Speicher angeht aber....

Den Eindruck macht es. Da wird dir wohl keiner ernsthaft widersprechen 
wollen.

von Dennis K. (Gast)


Lesenswert?

Mark Brandis schrieb:
> Meinst Du das hier?
>
> AVR32825: Executing code from external SDRAM
>
> http://www.atmel.com/Images/doc32160.pdf

Ja/Nein, Ich würde gerne Code vom internen RAM ausführen.

von Dennis K. (Gast)


Lesenswert?

Ich suche auch nach einer Möglichkeit C-Funktion in den RAM
zu kopieren und von da auszuführen.

von Dennis K. (Gast)


Lesenswert?

In den internen RAM

von Vn N. (wefwef_s)


Lesenswert?

Was hindert dich daran, das analog zu obiger Anleitung für ein externes 
RAM zu versuchen?
Du erstellst eine entsprechende Section, kopierst den Inhalt beim booten 
an die richtige Addresse im RAM, fertig.

von Amateur (Gast)


Lesenswert?

Wozu eigentlich?

Die Ausführungszeiten sind nicht kürzer.

Der Aufwand ist größer. Code im Flash zum Einschaltzeitpunkt und später 
ins RAM kopieren.

In diesem Umfeld kommt noch hinzu: RAM ist meist teurer.

von Dennis K. (Gast)


Lesenswert?

vn nn schrieb:
> Was hindert dich daran, das analog zu obiger Anleitung für ein
> externes
> RAM zu versuchen?
> Du erstellst eine entsprechende Section, kopierst den Inhalt beim booten
> an die richtige Addresse im RAM, fertig.

Also könnte ich mit der Anleitung auch auf dem internen RAM Code 
ausführen?

von Mike (Gast)


Lesenswert?

Der Prozessor wird keine C-Funktion ausführen, weder aus dem RAM noch 
aus dem Flash! Die CPU versteht nur Maschinencode!

von TriHexagon (Gast)


Lesenswert?

Mike schrieb:
> Der Prozessor wird keine C-Funktion ausführen, weder aus dem RAM noch
> aus dem Flash! Die CPU versteht nur Maschinencode!

Ich glaube er weiß, dass seine C-Funktion in Maschinencode übersetzt 
wird.

von von Neumann (Gast)


Lesenswert?

Der AVR ist http://de.wikipedia.org/wiki/Harvard-Architektur

Ohne Tricks geht das nicht.

von ich (Gast)


Lesenswert?

Es geht hier um den AVR32 und da geht das!

von squirrel (Gast)


Lesenswert?

Vielleicht geht es ja dem Thread-Ersteller nur darum mal zu testen wie 
man das macht und ob er es hinbekommt Code vom Ram aus auszuführen.

Ob man es glaubt, oder nicht manchmal machen die Leute seltsame Sachen 
um sich in neue Technologien einzuarbeiten.

Wenn es möglich ist, müssen die Schritte der obigen Anleitung angepasst 
funktionieren!

von Werner M. (Gast)


Lesenswert?

Amateur schrieb:
> Der Aufwand ist größer. Code im Flash zum Einschaltzeitpunkt und später
> ins RAM kopieren.

Der AVR32 AP hat gar keinen Flash ;-(

von Johnny B. (johnnyb)


Lesenswert?

Vielleicht will er einen Bootloader programmieren, welcher sich selber 
updaten kann oder zur Laufzeit nachladbare Programmteile (Plugins) 
programmieren.
;-)

von Steffen R. (steffen_rose)


Lesenswert?

Georg G. schrieb:
> Mike schrieb:
>> Zur Laufzeit wird das doch in
>> einen RAM geladen und dort ausgeführt.
>
> Warum sollte man das machen? Das bleibt im Flash.

Er wird seine Erfahrungen auf einem anderen System gemacht haben. Bei 
den embedded Linux Systemen u.ä. wird das so gemacht.

von Steffen R. (steffen_rose)


Lesenswert?

Amateur schrieb:
> Die Ausführungszeiten sind nicht kürzer.

Lt. Handbuch benötigt der Flash beim AT32UC3 1 Wait State bei 66MHz. 
Insofern dürfte auch beim AVR32 gelten was für viele andere Prozessoren 
gilt: Bei höheren Taktraten werden Programme aus dem RAM schneller 
ausgeführt als aus dem Flash. Daher werden auch gerne zeitkritische 
Interruptroutinen ins Ram verlagert.

von Stefan (Gast)


Lesenswert?

Code im RAM kann auch sinnvoll sein, wenn man das Flash in der 
Apllikation umprogrammieren will und die program/erase Wartezeiten für 
kritische Programmteile zu lange sind.

von M. (Gast)


Lesenswert?

Also, ich suche eine Möglichkeit um in der Laufzeit noch weitere 
Programmfunktionen in den AVR32 zu laden. Ob in den RAM oder in den 
Flash ist mir erstmal egal.

von TriHexagon (Gast)


Lesenswert?

Schon mit Linkerscripts in Berührung gekommen? Wenn nicht dann ist es 
jetzt Zeit dafür. Was du machen musst ist für deine Funktionen eine 
Section zu erstellen. Mithilfe von externen Variablen im Linkerscript 
überträgst du dann die Informationen, an welcher Adresse der 
Maschinencode im Flash steht und wie groß dieser ist, ins eigentliche 
C-Programm. Dann kopierst du diesen ins RAM und führst die Funktionen 
mittels Funktionszeiger aus.

Keine Ahnung ob du noch was Spezielles beachten musst, habe nur mit ARM 
Erfahrung nicht mit AVR32.

von M. (Gast)


Lesenswert?

nein ich hab mich leider noch nicht mit Linkerscripts beschäftigt.
Was meinst du in den RAM kopieren? Ich dachte der Maschinencode ist im 
Flash.

von Steffen R. (steffen_rose)


Lesenswert?

Wieso im Flash? Ich denke, Du willst Code nachladen.

von Mark B. (markbrandis)


Lesenswert?

M. schrieb:
> Ob in den RAM oder in den Flash ist mir erstmal egal.

Wenn der Flash-Speicher das Ziel sein soll, was ist dann bitte die 
Quelle?

von TriHexagon (Gast)


Lesenswert?

M. schrieb:
> Was meinst du in den RAM kopieren? Ich dachte der Maschinencode ist im
> Flash.

Du sagst es doch schon selbst.

Also entweder musst du das manuell machen oder vom Startupcode machen 
lassen. Linkerscript muss dann natürlich angepasst werden.

Beschäftige dich erstmal mit Linkerscripts.

von M. (Gast)


Lesenswert?

ok mein Fehler.
Ich würde den Maschinencode in der Laufzeit über UART empfangen und dann 
im RAM ausführen. So hab ich mir das erst gedacht.

von TriHexagon (Gast)


Lesenswert?

So entfällt natürlich das Linkerscript. Das wird gebraucht, wenn der zu 
ausführende Code mit gelinkt werden soll.

Wenn du dann keine Probleme mit der PC Seite hast, ist es ziemlich 
einfach. Maschinencode mit UART empfangen, ins RAM kopieren, mit 
Funktionszeiger ausführen. Assemblerkenntnisse sind möglicherweise 
hilfreich.

von Steffen R. (steffen_rose)


Lesenswert?

Naja, das Linkerscript wird schon gebraucht. Jedoch bei der Erstellung 
des Programmcodes, welcher nachgeladen wird.

Der Code muss entweder adressenunabhängig compiliert werden oder eben 
speziell für die RAM Adresse, auf die er geladen wird.

von Johnny B. (johnnyb)


Lesenswert?

TriHexagon schrieb:
> Maschinencode mit UART empfangen, ins RAM kopieren, mit
> Funktionszeiger ausführen.

Denke ich auch, mehr ist dazu nicht zu sagen, es sollte recht einfach 
sein.
Wenn Du die empfangenen Daten laufend in ein Array schreibst, dann 
kannst Du mittels Funktionspointer (der auf das Array zeigt) dann gleich 
reinspringen.
Sinnvoll wäre natürlich noch, das ganze nach dem Empfang mit einem CRC 
zu prüfen, nicht dass wegen eines Übertragungsfehlers irgend ein Scheiss 
ausgeführt wird.

von M. (Gast)


Lesenswert?

Wenn ich dann zum Beispiel eine Funktion im RAM ausführe, kann ich dann 
aus dieser Funktion heraus, Funktionen im Flash aufrufen?
Müssten nicht dann die Flash und Ram-Funktionen zusammen kompalliert 
werden? Sonst besteht doch kein Zusammenhang, oder?

von Svenska (Gast)


Lesenswert?

Du kannst alle Funktionen getrennt kompilieren, aber du musst sie 
gemeinsam linken. Der Linker weist dann jeder Funktion eine Adresse 
zu, den Flash-Funktionen eine Flash-Adresse, den RAM-Funktionen eine 
RAM-Adresse.

Der Startup-Code des Controllers muss dann die RAM-Funktionen (aus dem 
Flash) an ihre richtige RAM-Adresse kopieren und die Hauptfunktion 
anspringen. Fertig.

von Svenska (Gast)


Lesenswert?

Nachtrag: Wenn du das alles dynamisch haben möchtest, dann brauchst du 
eine Tabelle aller Funktionen mit ihrer zugehörigen Adresse. Die Adresse 
dieser Tabelle muss allen Beteiligten bekannt sein (z.B. per Zeiger an 
einer fixen Adresse)!

Dann kannst du die dort aufgeführten Funktionen mit ihrem Namen 
anspringen, egal wo sie sich befinden.

von M. (Gast)


Lesenswert?

Wie kann man den Funktionen getrennt kompilieren?
Wenn ich auf eine Funktionen im Flash zuweise, kommt ein Fehler von 
Kompiler

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

M. schrieb:
> Wenn ich auf eine Funktionen im Flash zuweise,

wie machst du das?

> kommt ein Fehler von Kompiler

wie heißt der?

von Rolf Magnus (Gast)


Lesenswert?

Man könnte sich mal anschauen, wie der Linux-Kernel das macht. Da gibt's 
zwar nicht die Trennung RAM/Flash, aber es werden auch zur Laufzeit 
Module nachgeladen, die dann Kernel-Funktionen aufrufen können oder auch 
Funktionen anderer Module.

von Steffen R. (steffen_rose)


Lesenswert?

M. schrieb:
> Wie kann man den Funktionen getrennt kompilieren?

z.B. indem Du sie per Funktionspointer anspringst, denen Du die Adresse 
der Funktion, wie oben beschrieben, aus der Funktionstabelle zuweist.

von M. (Gast)


Lesenswert?

Ich hab jetzt einen ganz einfachen Versuch gemacht.
Ich hab eine kompilierte o-Datei mit einer LED-Blink-Funktion in eine 
bin-Datei umgewandelt und diese an den AVR32 über UART übertragen. 
Anschließend habe ich den Inhalt in den internen RAM gespeichert.

Folgendermaßen sieht mein Code aus:
1
typedef void (*USER_FUNC)(void);
2
USER_FUNC Fktpointer;
3
U8 * bufferRam[1024];
4
5
int main (void)
6
{
7
8
// bin wird empfangen
9
// Inhalt wird im bufferRam geschpeichert
10
11
Fktpointer=&bufferRam;
12
13
(*Fktpointer)();    // Funktionsaufruf
14
15
}

Die LED blinkt aber leider nicht

von Steffen R. (steffen_rose)


Lesenswert?

M. schrieb:
> Ich hab eine kompilierte o-Datei mit einer LED-Blink-Funktion in eine
> bin-Datei umgewandelt

Wie?
Die Objektdatei enthält noch unaufgelöste Referenzen, welche erst durch 
das Linken aufgelöst werden.

von TriHexagon (Gast)


Lesenswert?

M. schrieb:
> Ich hab eine kompilierte o-Datei mit einer LED-Blink-Funktion in eine
> bin-Datei umgewandelt und diese an den AVR32 über UART übertragen.

Das Kompilat ist nichts wert, solange der Linker nicht drübergegangen 
ist.

Wie gesagt ihr müsst euch mit Linkerscripts und den verschiedenen 
Sections auseinander setzen. Ihr müsst den Linker anweisen alle Sections 
direkt nebeneinander zu setzen. Die .text Section und eine bestimmte 
Funktion direkt am Anfang setzten lassen um einfach darauf springen zu 
können. Den Kompiler einstellen, dass er nur relative Sprungadressen 
nutzt (wenn man das Programm an jede Speicherstelle setzten will). Und 
am Ende die elf/hex in bin umwandeln. Die Daten anschließend senden, ins 
RAM kopieren und an den Anfang springen (Funktionsdeklaration beachten).

Das hört sich etwas kompliziert an, ist es aber nicht, Wenn man sich mit 
dem Linken etwas auseinander gesetzt hat.

von TriHexagon (Gast)


Lesenswert?

Ihr könnt das ja auch erstmal auf x86 probieren, dort ist es nicht 
anders, aber etwas zugänglicher.

von M. (Gast)


Lesenswert?

ich erstelle also zuerst eine neue Section. Kann ich die neue Section 
hinter dem Sack setzen?

Wie kann ich dann die gelinkte Datei in den definierten RAM-Berech 
kopieren? Muss ich dazu umbedingt Assembler verwenden?

von TriHexagon (Gast)


Lesenswert?

M. schrieb:
> ich erstelle also zuerst eine neue Section. Kann ich die neue Section
> hinter dem Sack setzen?

Du setzt .text .bss .data direkt nebeneinander. Für den Startcode 
erstellst du eine neue Section und setzt diese vor .text, also am 
Anfang.

M. schrieb:
> Wie kann ich dann die gelinkte Datei in den definierten RAM-Berech
> kopieren? Muss ich dazu umbedingt Assembler verwenden?

C reicht. Du kopierst die Daten wie gewohnt in den Speicher, also 
entweder mit memcpy() oder einer eigenen Funktion.

von Svenska (Gast)


Lesenswert?

Ich glaube, dir fehlt ein Verständnis dafür, was Compiler und Linker 
eigentlich tun. Was du vorhast, ist nicht so einfach.

Object-Dateien enthalten keine gültigen Adressen, sondern nur 
Platzhalter. Der Linker sieht alle Funktionen eines Projekts und füllt 
damit alle Adressen aus. Das sind nicht nur Funktionen, sondern auch 
z.B. Labels oder Schleifenköpfe, weil die angesprungen werden können. 
Und wenn der Linker sagt, dass der Kopf deiner Endlosschleife an 
0x12345678 steht, dann wird das Schleifenende an genau diese Adresse 
springen - egal, ob die Funktion nun da ist oder nicht.

Daraus folgt: Du musst deine Funktionen als "position independent 
code" (PIC) kompilieren (siehe Compiler-Referenz). Nur dann kannst du 
die Funktion an eine beliebige Adresse kopieren und aufrufen. Dann steht 
da nämlich nicht mehr 0x12345678, sondern "-0x120 relativ zu PC".

Also: Kompiliere deinen Blinker als PIC-Code. Dann linkst du 
positionsunabhängig und lässt dir das Ergebnis als binary ausgeben. Als 
nächsten Schritt musst du den Einsprungpunkt-Offset (d.h. die Adresse 
der ersten Instruktion deines Blinkers relativ zum Anfang des binary) 
herausbekommen.

Dann kann dein Loader diese Binärdatei per UART empfangen, in einen 
Buffer schreiben, einen Funktionspointer auf Buffer+Offset erzeugen und 
den anspringen.

von M. (Gast)


Lesenswert?

Svenska schrieb:
> araus folgt: Du musst deine Funktionen als "position independent
> code" (PIC) kompilieren (siehe Compiler-Referenz). Nur dann kannst du
> die Funktion an eine beliebige Adresse kopieren und aufrufen. Dann steht
> da nämlich nicht mehr 0x12345678, sondern "-0x120 relativ zu PC".

Nach deiner Erklärung muss ich keine neue Section erstellen?

von Svenska (Gast)


Lesenswert?

Richtig.

Wenn du ein Programm hast, von dem Teile im RAM und Teile im Flash 
ausgeführt werden, dann kann der Linker die ganze Magie für dich machen. 
Dann brauchst du je eine Code-Section für Flash und RAM, sagst an, 
welche Funktion wo liegen soll, linkst das und fertig.

Wenn du aber (relativ) unabhängige Programme per UART übertragen willst, 
dann ist das prinzipiell mit einem Betriebssystem und Anwendungen 
vergleichbar. Da gibt es dann spezielle Binärformate (ELF, PE), du musst 
dich mit relocation rumschlagen und so weiter. Ich vermute, dass du 
davon auch keine Ahnung hast. Interessiert es dich, dann gibt es unter 
Stichworten wie ELF-Loader genug Beispielcodes und das wäre der Weg der 
Wahl.

Position Independent Code erspart dir Relocation auf Kosten der 
Performance. Ohne Relocation gibt es keinen zwingenden Grund für höhere 
Binärformate mehr, deswegen ist mein Vorschlag der vermutlich einfachste 
Weg, wenn man alles zu Fuß machen will.

Sections gibt es nur bei ELF u.ä.; solange du also keine ELF-Datei per 
UART übertragen (und parsen) willst, kommen die Section-Definitionen auf 
deinem AVR32 nie an.

von M. (Gast)


Lesenswert?

Hallo,

ich hab mich noch weiter mit dem Thema beschäftigt aber ich komme immer 
noch nicht weiter.
Ich möchte den unteren Code positionsunabhängig kompilieren und über 
UART an den AT32UC3B0256 übertragen und in den RAM kopieren. Im RAM 
möchte ich den Code dann ausführen.

Dieser Code befindet sich in helloworld.c
1
int global = 100;
2
3
void world() {
4
  global++;
5
}
6
7
void hello(void) {
8
  world();
9
}

Mein Code kompiliere ich mit folgenden Befehl
avr32-gcc -c helloworld.c -fpic

Heraus kommt die Objektdatei helloworld.o

Wenn ich diese Datei mit dem unteren Befehl disassembliere, bekomme ich 
folgendes:

avr32-objdump mp_init.o -xd
1
helloworld.o:     file format elf32-avr32
2
helloworld.o
3
architecture: avr32, flags 0x00000011:
4
HAS_RELOC, HAS_SYMS
5
start address 0x00000000
6
private flags = 2: [PIC]
7
8
Sections:
9
Idx Name          Size      VMA       LMA       File off  Algn
10
  0 .text         0000003c  00000000  00000000  00000034  2**2
11
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
12
  1 .data         00000004  00000000  00000000  00000070  2**2
13
                  CONTENTS, ALLOC, LOAD, DATA
14
  2 .bss          00000000  00000000  00000000  00000074  2**0
15
                  ALLOC
16
  3 .debug_frame  00000050  00000000  00000000  00000074  2**2
17
                  CONTENTS, RELOC, READONLY, DEBUGGING
18
  4 .comment      00000031  00000000  00000000  000000c4  2**0
19
                  CONTENTS, READONLY
20
SYMBOL TABLE:
21
00000000 l    df *ABS*  00000000 helloworld.c
22
00000000 l    d  .text  00000000 .text
23
00000000 l    d  .data  00000000 .data
24
00000000 l    d  .bss   00000000 .bss
25
00000000 l    d  .debug_frame   00000000 .debug_frame
26
00000000 l    d  .comment       00000000 .comment
27
00000000 g     O .data  00000004 global
28
00000000 g     F .text  00000024 world
29
00000000         *UND*  00000000 _GLOBAL_OFFSET_TABLE_
30
00000024 g     F .text  00000018 hello
31
32
Disassembly of section .text:
33
34
00000000 <world>:
35
   0:   eb cd 40 c0     pushm   r6-r7,lr
36
   4:   1a 97           mov     r7,sp
37
   6:   48 76           lddpc   r6,20 <world+0x20>
38
   8:   1e 26           rsub    r6,pc
39
   a:   ec f8 00 00     ld.w    r8,r6[0]
40
                        a: R_AVR32_GOT16S       global
41
   e:   70 08           ld.w    r8,r8[0x0]
42
  10:   f0 c9 ff ff     sub     r9,r8,-1
43
  14:   ec f8 00 00     ld.w    r8,r6[0]
44
                        14: R_AVR32_GOT16S      global
45
  18:   91 09           st.w    r8[0x0],r9
46
  1a:   e3 cd 80 c0     ldm     sp++,r6-r7,pc
47
  1e:   00 00           add     r0,r0
48
  20:   00 00           add     r0,r0
49
                        20: R_AVR32_GOTPC       .text+0x8
50
        ...
51
52
00000024 <hello>:
53
  24:   eb cd 40 c0     pushm   r6-r7,lr
54
  28:   1a 97           mov     r7,sp
55
  2a:   48 46           lddpc   r6,38 <hello+0x14>
56
  2c:   1e 26           rsub    r6,pc
57
  2e:   f0 16 00 00     mcall   r6[0]
58
                        2e: R_AVR32_GOT18SW     world
59
  32:   e3 cd 80 c0     ldm     sp++,r6-r7,pc
60
  36:   00 00           add     r0,r0
61
  38:   00 00           add     r0,r0
62
                        38: R_AVR32_GOTPC       .text+0x2c
63
        ...

Ist das soweit richtig und wie muss ich jetzt weiter vorgehen?

von M. (Gast)


Lesenswert?

Wie linke ich diese Objektdatei jetzt? Oder erzeuge ich mir daraus 
direkt eine .bin?

von M. (Gast)


Lesenswert?

Jemand eine Idee?

von M. (Gast)


Lesenswert?

Jemand eine Idee??

von Mark B. (markbrandis)


Lesenswert?

Vielleicht hilft dieser Thread weiter:

http://embdev.net/topic/129598

Da ist auch ein Link auf ein Beispiel drin, wenn auch nicht für AVR32.

von Steffen R. (steffen_rose)


Lesenswert?

Globale Variable dürften ein Problem darstellen.

von M. (Gast)


Lesenswert?

Hat schon jemand mit position unabhängigen code Erfahrung?

von M. (Gast)


Lesenswert?

Mark Brandis schrieb:
> Vielleicht hilft dieser Thread weiter:
>
> http://embdev.net/topic/129598
>
> Da ist auch ein Link auf ein Beispiel drin, wenn auch nicht für AVR32.

hat irgendwie leider nicht weiter geholfen

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.