Wie kann ich auf einem Cortex-M3 (STM32) eine Funktion aus dem RAM ausgeführt werden?
Frage
Ich versuche, eine Funktion von RAM auf einem Cortex-M3-Prozessor (STM32) auszuführen. Die Funktion löscht die und schreibt den internen Blitz, so dass ich muß auf jeden Fall in RAM sein, aber wie mache ich das?
Was habe ich versucht, ist dies: Kopieren Sie die Funktion auf ein Byte-Array im RAM Memcpy mit (Überprüfung, dass es richtig ausgerichtet wird), einen Funktionszeiger auf Punkt auf die Byte-Array-Einstellung ein dann die die Funktion (Zeiger) aufrufen.
Dies funktioniert gut für vielleicht 10 Anweisungen (I die Ausführung mit dem Debugger folgen kann), aber dann bekomme ich einen Fehler Buss und der Prozessor setzt. Der Buss Fehler tritt auf dem zweiten Durchlauf durch eine Schleife, so sollte der Code in Ordnung sein (wie es den ersten Durchlauf arbeitet). Ich denke, dass die schnelleren RAM-Zugriff mucks bis der Bus Timing in irgendeiner Weise ...
Auf jeden Fall ist es ein richtiger Weg, dies zu tun? Wie würde eine Scatter-Datei aussehen, die Orte eine Funktion im RAM automatisch (Ich bin mit Keil uVision für Cortex-M3)?
Edit: Weitere Informationen: Toolchain: Realview MDK-ARM V 4.10 Compiler: Armcc v4.0.0.728 Assembler: Armasm v4.0.0.728 Linker: ArmLink v4.0.0.728 Prozessor: STM32F103ZE
Das IMPRECISERR Bit im Buss Fehlerregister gesetzt, wenn die Reset geschieht.
Lösung
Der Absturz bei Schleifeniterationslatenzzeit ist wahrscheinlich, weil die Funktion in eine absolute Adresse verzweigt und ist auf die neue Funktion Stelle im RAM nicht relativ. Würde die ursprüngliche Code Lage an diesem Punkt verursacht einen Bus Fehler beim Zugriff auf wegen der Flash-Löschoperation?
Ich glaube, dass Sie eine Funktion markieren können kompiliert und korrekt mit CARM kopiert werden in den RAM durch die __ram
Richtlinie auf die Funktionsdefinition anhängen. Für Anleitung, wie man das gleiche zu tun mit den Realview-Compiler die EXECUTING FUNKTIONEN RAM technischer Support-Artikel:
µVision können Sie Module lokalisieren auf bestimmte Speicherbereiche, die im Dialog eingegeben Projekt - Optionen - Ziel . Um dies zu tun, nicht wahr klicken Sie auf eine Quelldatei (oder Dateigruppe) und öffnen Sie den Dialog Optionen - Eigenschaften . Wählen Sie dann den Speicher Regionen unter Speicherbelegung .
Es gibt ein Beispiel in dem Ordner ARMExamplesRAM_Function .
Das sollte Startup-Code generieren zu kümmern, die Funktion des Kopierens auf RAM und Verknüpfung Anrufe an dieser Stelle richtig. Andernfalls, wenn Sie dynamisch Exemplares benötigen, beliebige Funktionen auf RAM, dann schauen Sie in die Erstellung Position unabhängigen Code (PIC) mit Realview.
Andere Tipps
Ohne mehr über Ihre Situation zu wissen, kann ich nur ein paar allgemeinen Dinge vorschlagen ... sicherstellen, dass Sie für diese Funktion einen gültigen Stapel (oder alle Stack-Operationen in der Funktion vermeiden), dass Ihre Interrupts deaktiviert sind, und dass jeder Vektoren im System Vektortabelle weisen nicht auf Code, der weggeht, wenn Sie Flash löschen. Schließlich, stellen Sie sicher, dass Ihre Funktion ist verknüpft an der Adresse laufen Sie es nennen ... der Code nicht versetzbar sein kann und auf einen Punkt springen kann in alten Standort ist.
Da die ARM hat eine begrenzte Fähigkeit, sofort Daten zu laden, Dienstprogramme, den Code für die ARM häufig juxtapose Code und Daten erzeugen. Zum Beispiel kann eine Anweisung wie
void myRoutine(void)
{
myVar1=0x12345678;
myVar2=0x87654321;
}
könnte sich als etwas enden wie:
myRoutine:
ldr r0,=myVar1; Load the address of _myVar
ldr r1,=0x12345678
str r1,[r0]
ldr r0,=myVar1; Load the address of _myVar
ldr r1,=0x87654321
str r1,[r0]
bx lr
which would get translated into:
ldr r0,dat1
ldr r1,dat2
str r1,[r0]
ldr r0,dat3
ldr r1,dat4
str r1,[r0]
bx lr
... followed some time later by
dat1 dcd _myVar1
dat2 dcd 0x12345678
dat3 dcd _myVar2
dat4 dcd 0x12345678
or perhaps even something like:
mar r0,dat1
ldrm r0,[r1,r2,r3,r4]
str r2,[r1]
str r4,[r3]
bx lr
... followed some time later by
dat1 dcd _myVar1
dat2 dcd 0x12345678
dat3 dcd _myVar2
dat4 dcd 0x12345678
Beachten Sie, dass _myVar und 0x12345678 sofort platziert werden kann nach dem Code für die Routine, in der sie erscheinen; wenn Sie versuchen, die Länge der Routine mit einem Etikett, um zu bestimmen, welche die letzte Anweisung folgt, wird eine solche Länge nicht die zusätzlichen Daten aufzunehmen.
Eine weitere Sache zu Notiz mit der ARM ist, dass aus historischen Gründen, Code-Adressen werden oft ihre niedrigstwertigen Bit gesetzt haben, obwohl Code tatsächlich beginnt, auf Halbwortgrenzen. Somit wird ein Befehl, deren Adresse 0x12345679 wird besetzen entweder zwei oder vier Bytes bei 0x12345678 starten. Dies kann Adressenberechnung für Dinge wie memcpy erschweren.
Meine Empfehlung wäre, eine kleine Routine in Assembler-Sprache zu schreiben, zu tun, was Sie brauchen. Es ist nur ein paar Anweisungen, können Sie genau wissen, was der Code tut und was Adresse Abhängigkeiten könnte es haben, und Sie müssen sich keine Sorgen machen über die zukünftigen Compiler-Versionen der Code in einer solchen Art und Weise zu brechen, etwas zu ändern [z die dritte Version des obigen Code würde kein Problem haben, auch wenn dat1
auf einer ungeraden Halbwortgrenze landete seit der LDR-Befehls des M3 liest unaligned umgehen kann, aber der vierte (etwas schneller und kompakter) Version LDRM Verwendung in einem solchen Fall scheitern würde; auch wenn die heutige Version eines Compilers vier LDR Anweisungen verwendet, kann eine zukünftige Version verwenden LDRM].
Mit dem IAR-Compiler (Ich weiß, dass Ihre Frage über Keil ist, aber ich habe es nicht mit spielen) können Sie entweder das gesamte Projekt oder eine einzelne Datei zu sein „Position unabhängig“ markieren. Von der Nutzung in der Vergangenheit mit anderen Prozessoren bedeutet es Sie es „überall“ bewegen können, und es wird immer noch funktioniert ok