Forum: Compiler & IDEs Arm Gcc Funktion ins Ram


von stefan (Gast)


Lesenswert?

Hallo,

wie kann ich, um meine Firmware per IAP zu updaten, eine Funktion ins 
Ram kopieren und von das ausführen?

von Martin T. (mthomas) (Moderator) Benutzerseite


Lesenswert?

Am Einfachsten, indem man die Funktion der .data section zuweist vgl. 
gcc-manual function-attributes. Dann wird die Funktion beim üblichen 
C-Startup mit dem Rest von .data (initialisierte Variablen ungleich 0) 
ins RAM kopiert. Mögliche Fallen (und Abhilfen): evtl. alignment nicht 
korrekt (dann eigene C-Section für die RAM Funktionen anlegen und im 
Linker-Script eintragen) und/oder long-calls erforderlich (dann 
long-call attribute ergänzen).
Mglw. ist mein Beispiel hilfreich: 
http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/index.html#gcc_ramfunc

Martin Thomas

von Stefan (Gast)


Lesenswert?

Danke für die Antwort. Werde ich mal probieren. Kann ich das ganze auch 
erst dann machen, wenn ich es brauche? Also die Funktion nachträglich 
ins Ram kopieren? Wenn ich teile des Heaps dafür überschreibe ist mir 
das ansich egal, da ich die danach eh nicht mehr brauche...

Grüße, Stefan

von Rolf Magnus (Gast)


Lesenswert?

> Kann ich das ganze auch erst dann machen, wenn ich es brauche? Also die
> Funktion nachträglich ins Ram kopieren?

Im Prinzip schon. Dann mußt du dich allerdings selbst um alles kümmern. 
Du müßtest dazu im Linkerskript eine neue Sektion anlegen. Als 
Inspiration dazu kann dir die .data-Sektion im bisher verwendeten 
Linkerskript dienen. Du gibst dabei im Linkerskript zwei Adressen an, 
einmal die im Flash, an die die Funktion geschrieben wird, und dann die 
im RAM, in der der Code später ausgeführt werden soll. arm-elf-objdump 
-h gibt dir diese Adressen als LMA und VMA an.
Außerdem definierst du im Linkerskript Symbole, über die du dann vom 
Programm aus drauf zugreifen kannst. Die kannst du dann mit memcpy 
verwenden, um die Funktion vor ihrem Aufruf an ihre Zielstelle zu 
befördern.

von Stefan (Gast)


Lesenswert?

Ok, hab ich fast verstanden. NUr eins nicht: Wie komm ich an die Adresse 
für die Position im Flash?
Darf die Adresse im Ram mit dem Data-Segment kollidieren? - Also die 
gleiche sein?

von Rolf Magnus (Gast)


Lesenswert?

> NUr eins nicht: Wie komm ich an die Adresse für die Position im Flash?

Du meinst aus dem Programm heraus? Du mußt dazu ein Symbol im 
Linkerskript definieren. Im Prinzip muß es völlig analog zur Sektion 
.data gemacht werden. Die .data-Sektion sieht in meinem Linkerskript 
z.B. so aus:
1
  /* put data into ROM. It will be copied to RAM at startup time */
2
  .data   : AT (ADDR (.jcr) + SIZEOF (.jcr))
3
  {
4
    __data_start = . ;
5
    *(.data .data.* .gnu.linkonce.d.*)
6
    KEEP (*(.gnu.linkonce.d.*personality*))
7
    SORT(CONSTRUCTORS)
8
  } > ram
9
10
  __data_load_start = LOADADDR(.data);
11
  __data_load_end = __data_load_start + SIZEOF(.data);

Das AT am Anfang gibt dabei an, wo die Sektion im Flash stehen soll. In 
diesem Fall ist das nach dem Ende der Sektion .jcr. Du müßtest für deine 
eigene Sektion raussuchen, welche Sektion bisher die letzte im Flash ist 
und deine dann dahinter anhängen.
Die Definitionen von __data_load_start und __data_load_end sind die 
Symbole für den C-Code.  Dann könnte man in C mit:

extern unsigned char __data_load_start[];
extern unsigned char __data_load_end[];
const size_t data_size = __data_load_end - __data_load_start;

die Startadresse und die Größe der Sektion im Flash verfügbar machen. 
Analog dazu gibt's oben noch __data_start für die Adresse im RAM. Damit 
hast du alles, was zum Aufruf von memcpy benötigt wird. Danach kannst du 
die Funktion dann ganz normal aufrufen wie jede andere auch.
Ob bzw. wie man dem Linker sagen könnte, daß eine RAM-Doppelbelegung in 
diesem Fall erlaubt ist, weiß ich nicht.

von Stefan (Gast)


Lesenswert?

Tausend Dank für Deine super Erklärung. NUn sollte es klar sein.
Hast Du vielleicht noch einen Link, wo ich sowas nachlesen kann um mich 
noch weiter zu bilden. Vor allem was es mit den Sektionen (.jcr) auf 
sich hat?

Ansich müsste ich die Funktion ja auch unabhängig davon was 
__data_load_start ist, an eine beliebige Stelle im Ram kopieren können, 
da alle Sprünge ja relativ sein sollten, oder?

Grüße, Stefan

von Rolf Magnus (Gast)


Lesenswert?

> Hast Du vielleicht noch einen Link, wo ich sowas nachlesen kann um mich
> noch weiter zu bilden. Vor allem was es mit den Sektionen (.jcr) auf
> sich hat?

Es gibt die Deokumentation vom GNU-Linker, aber da stehen die Rollen der 
einzelnen Sektionen nicht drin. Letztendlich sind die auch 
Compiler-abhängig. Ich kenne keine Liste, die die ganzen Sektionen 
beschreibt.

> Ansich müsste ich die Funktion ja auch unabhängig davon was
> __data_load_start ist, an eine beliebige Stelle im Ram kopieren können,
> da alle Sprünge ja relativ sein sollten, oder?

Da bin ich mir nicht sicher. Du kannst es versuchen, dann eben über 
einen selbst definierten Funktionszeiger, aber ich würde die Zieladresse 
lieber vom Linkerskript nehmen. Ich weiß nicht, ob innerhalb der 
Funktion wirklich alle Adressen immer relativ und von außen immer 
absolut sind. Spätestens, wenn deine Funktion eine andere aufruft, die 
auch im RAM ist, wird's nicht mehr gehen.

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.