Weiß jemand, wie man auf dem MSP430 eine C-Funktion in den RAM kopiert, und von da ausführt? Ich möchte den gesamten FLASH neu beschreiben können, dazu muss die Flash-Routine in den RAM. Speicher hab ich genug, der F1611 hat intern 10k RAM und extern hängen nochma 1MByte dran, da würde ich das TI txt file ablegen. Nur müsste ich vor dem Flaschen meine Funktion in den RAM laden. Wie macht man das? Ich benutze den MSP-GCC.
Achnee. Und woher weiß ich, wie groß meine auszuführende Funktion ist? Kann man sich die Größe einer Funktion im C irgendwie holen? Mit sizeof() bekomm ich nur die größe des Pointers wie es scheint, also 1. Am liebsten würd ich dem Linker gleich sagen, er soll meine Funktion in den RAM packen, aber da hab ich auch keine Infos gefunden, wie das geht.
Grundsätzlich verhindert die MSP430 dein Vorhaben nicht Beitrag "MSP430 + Execution from RAM" Ich kenne es nur vom ARM her. Dort kann man seinen Code komplett oder in Teilen z.B. in die .data Section legen lassen oder eine Section mit eigenem Namen. http://www.embeddedrelated.com/groups/lpc2000/show/5031.php Hat MSPGCC das _attribute_ section? Ich denke ja, hier ist zumindest beschrieben, wie man Code und Daten gezielt im Flash ablegen kann. http://mspgcc.sourceforge.net/faq/x71.html IMHO könnte das auch im RAM funktionieren und wenn man beachtet, ab wann das RAM initialisiert ist bzw. seinen Startup-Code so umschreibt, dass die ggf. verwendete eigene Section auch vom ROM ins RAM kopiert wird. Oder man steckt unschön die Funktion mit in die .data Section und lässt kopieren. Die Grösse der eigenen Section bekommt man ja über das Linkercontrolscript heraus bzw. man kann sich entsprechende *start/*end Variablen definieren. Das und die Kopieraktion kann man bei der .data Section abkucken.
Danke. Ich schau mal, ob ich das in eine eigene FLASH-Page bekomme, die kann ich dann ja ins RAM zur Laufzeit kopieren.
Es muss keine eigene Flash-Page und "manuelles" Kopieren sein. Klar das geht auch. Du musst dann aber dem Compiler/Linker bekanntmachen, dass du eine private Flash-Page und einen privaten RAM Abschnitt hast, in den die Toolchain nix legen darf. D.h. also auch das Linkercontrolskript anpacken. Für den Funktionsaufruf zur RAM-Funktion bräuchtest du dann Funktionspointer bzw. Inline-Assembler. Du musst auch darauf achten, dass der Code an der RAM Zieladresse lauffähig ist. Also die Toolchain für den Code ggf. entsprechende absolute Adressen oder relative Calls produziert. Eleganter finde ich die Methode über die section. Hier kann es ein beliebiger Abschnitt (section) im Flash sein und die Toolchain kümmert sich um den passenden Code. Die treffende Benennung des Abschnitts ist für den Linker, fürs eigene Verständnis und für elegantes Programmieren ;-) nützlich. Es ist aber nicht notwendig, denn man kann (wahrscheinlich, ausprobiert habe ich es nicht) den Code auch in der .data section unterbringen und die wird eh automatisch beim Startup vom Flash ins RAM kopiert.
Der MSP führ den Code aus dem FLASH aus, da wird nix in den RAM kopiert. Wie auch, bei den paar Bytes. Das ist kein ARM :) Mit der section ist ne gute Idee, da muss ich dann nichtmal ins RAM kopieren, denn der MSP kann sich sogar selber flashen, wenn die flash-routine selbst aus dem Flash kommt. Nur steht dann halt die CPU. Ist denn sichergestellt, dass im betreffenden FLASH-Segment dann kein anderer Code als der markierte steht? So ganz eindeutig ist die FAQ bei mspgcc da nicht....
> Der MSP führ den Code aus dem FLASH aus, da wird nix in den RAM kopiert. > Wie auch, bei den paar Bytes. Das ist kein ARM :) Sorry. Ich dachte du willst dies: > Weiß jemand, wie man auf dem MSP430 eine C-Funktion in den RAM kopiert, > und von da ausführt?
Das würde ich am liebsten machen. Dazu muss ich allerdings meine FLASH-Funktion in einem Bereich ablegen, den ich genau kenne, also Start und Größe. Der MSP macht von alleine nix mit Startup und ins RAM kopieren. Es gibt 2 Möglichkeiten: 1. Die Update-Funktion liegt in einem geschützten Bereich im FLASH und wird von da ausgefäührt. Beim Flaschen wird dieser Bereich nicht gelöscht. Klassische Bootloader-Variante. 2. Die Updatefunktion liegt irgendwo in Flash. Auf Befehl wird diese Funktion aus dem Flash in den RAM kopiert und dann von dort ausgeführt. Variante 2 hat den Vorteil, dass man den kompletten Flash neu beschreiben kann, also man kann auch den Bootloader ändern. Leider hab ich erst ma zwischendurch wieder an einem anderen Projekt zu tun, deswegen kann ich da noch nicht weiter machen. Hätte ja sein können, das hat schon mal einer gemacht.
> Der MSP macht von alleine nix mit Startup und ins RAM kopieren. Habe ich das behauptet, dass er das alleine macht? Der Startupcode deines Programms macht das. Der Teil die MSPGCC Toolchain vor deiner ersten Programmanweisung ("main()") hinzugefügt hat. http://mspgcc.sourceforge.net/manual/x1127.html
Abschliessend (meinerseits) noch ein interessanter Link zum Thema: Konstruktion und Regelung eines autonomen Zweirad-Roboters Carsten Fuhrmann und Andreas Tenge implementieren in ihrer Diplomarbeit die Reglerroutinen für den Roboter im RAM. Die Vorgehensweise ist sehr ausführlich und anschaulich beschrieben. http://www.ti.uni-bielefeld.de/downloads/publications/diploma_theses/da13_atenge_cfuhrman_zweirad_fastA4.pdf
Beim C166 (Infineon, ähnliche Architektur) machen wir das folgendermaßen: Wir haben uns eine Funktion memswitch() geschrieben, die folgendermaßen funktioniert: 1. Flashinhalt in RAM kopieren (komplett). 2. Chip Select von RAM und Flash vertauschen (memory mapping) fertig. danach läuft das Programm wie gewohnt weiter, nur eben aus dem RAM. Man sollte natürlich die Interrupts während der Routine abschalten und die Register sichern. Unser memory mapping sieht wie folgt aus: Man muß beim linken darauf achten, das man die Variablen in einen Teil des RAMs linkt, welcher später nicht überschrieben wird (z.B. oberer Teil des RAMs)
Kein schöner Stil, sollte aber funktionieren. Wichtig ist, dass die eigentlichen Flashroutinen nur positionsunabhängigen Code enthalten (was zumindest beim IAR eingestellt werden kann)
1 | // festgelegte Adresse im RAM für die kopierte Funktion
|
2 | uint16_t* destFunc = 0x1234; |
3 | |
4 | // Kopierroutine
|
5 | void flashToRAM(uint16_t* dest, const uint16_t* src, uint16_t len); |
6 | void flashToRAM(uint16_t* dest, const uint16_t* src, uint16_t len) { |
7 | len >>= 1; |
8 | |
9 | while (len) { |
10 | *dest++ = *src++; |
11 | len--; |
12 | }
|
13 | }
|
14 | |
15 | // Dummyroutinen zum Flashen
|
16 | void writeFlash() { |
17 | P4OUT = 123; |
18 | }
|
19 | |
20 | void writeFlashEnd() { |
21 | }
|
22 | |
23 | // Kopieren
|
24 | flashToRAM(destFunc, (uint16_t *)&writeFlash, (uint16_t)&writeFlashEnd - (uint16_t)&writeFlash); |
25 | // Aufrufen
|
26 | void (*RAM)() = (void (*)())destFunc; |
27 | RAM(); |
im Grund ist die Grösse gleich der Differenz der Funktionspointer zweier aufeinanderfolgender Funktionen im C Code. Hast Deine CPU eine Befehlslaenge von einem Byte, kannste zwei Funktionspointer vom Typ char voneinander subrahieren und bekommst die Funktionsgroesse in Byte. Bei einem optimierenden Compiler koennts Probleme geben, wenn er zum Bsp kleine Funktionen "inlined". Das duerfte er aber eigentlich nicht tun, wenn der C Code einen Funktionspointer darauf besitzt. Wenn man mit gcc -S uebersetzt, kann man am Zwischencode sehen, wie der Compiler das arrangiert
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.