Hallo zusammen, weiß jemand, wie man auf weinem AVR32 eine C-Funktion in den RAM kopiert, und von da ausführt? Grüße M.
Meinst Du das hier? AVR32825: Executing code from external SDRAM http://www.atmel.com/Images/doc32160.pdf
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?
Mike schrieb: > Zur Laufzeit wird das doch in > einen RAM geladen und dort ausgeführt. Warum sollte man das machen? Das bleibt im Flash.
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.
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.
Ich suche auch nach einer Möglichkeit C-Funktion in den RAM zu kopieren und von da auszuführen.
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.
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.
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?
Der Prozessor wird keine C-Funktion ausführen, weder aus dem RAM noch aus dem Flash! Die CPU versteht nur Maschinencode!
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.
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!
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 ;-(
Vielleicht will er einen Bootloader programmieren, welcher sich selber updaten kann oder zur Laufzeit nachladbare Programmteile (Plugins) programmieren. ;-)
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.
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.
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.
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.
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.
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.
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?
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.
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.
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.
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.
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.
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?
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.
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.
Wie kann man den Funktionen getrennt kompilieren? Wenn ich auf eine Funktionen im Flash zuweise, kommt ein Fehler von Kompiler
M. schrieb: > Wenn ich auf eine Funktionen im Flash zuweise, wie machst du das? > kommt ein Fehler von Kompiler wie heißt der?
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.
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.
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
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.
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.
Ihr könnt das ja auch erstmal auf x86 probieren, dort ist es nicht anders, aber etwas zugänglicher.
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?
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.
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.
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?
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.
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?
Wie linke ich diese Objektdatei jetzt? Oder erzeuge ich mir daraus direkt eine .bin?
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.