Hey, ich versuche gerade das freeRTOS auf meinen ARM9 (sam9263) zum laufen zu bringen. Da ich keine Bib für meinen ARM gefunden hab, verändere ich jetzt die vorhandene für den ARM sam7. Dummerweise hänge ich gerade, da ich mich zu wenig mit den Assembler Befehlen der 2 auskenne. In der Bib (die ich nicht auf Lauffähigkeit getestet habe, da ich keinen 7er habe) heisst es, beim starten des ersten Tasks: /* Set the LR to the task stack. */ asm volatile ("LDR R0, =pxCurrentTCB \n\t"); asm volatile ("LDR R0, [R0] \n\t"); asm volatile ("LDR LR, [R0] \n\t"); /* The critical nesting depth is the first item on the stack. */ /* Load it into the ulCriticalNesting variable. */ asm volatile ("LDR R0, =ulCriticalNesting \n\t"); asm volatile ("LDMFD LR!, {R1} \n\t"); asm volatile ("STR R1, [R0] \n\t"); /* Get the SPSR from the stack. */ asm volatile ("LDMFD LR!, {R0} \n\t"); asm volatile ("MSR SPSR, R0 \n\t"); /* Restore all system mode registers for the task. */ asm volatile ("LDMFD LR, {R0-R14}^ \n\t"); asm volatile ("NOP \n\t"); /* Restore the return address. */ /*X*/asm volatile ("LDR LR, [LR, #+60] \n\t"); /* And return - correcting the offset in the LR to obtain the */ /* correct address. */ asm volatile ("SUBS PC, LR, #4 \n\t"); ( void ) ulCriticalNesting; ( void ) pxCurrentTCB; In der mit /*X*/ markierten Zeile ist LR vor der Ausführung 0xAAAAAAAA. Wenn ich das als Adresse in den Speicher sehe, ist das reservierter (also ungültiger(?)) Speicher. Bei der Ausführung verabschiedet er sich und springt den "daborthandler" an (so eine Art Exception?) Was ich nun eigentlich wissen will: LDMFD LR, {R0-R14}^ scheint alle Register auf Startwerte zu setzten. Passiert das mit dem ARM7 nicht? Also wird der Befehl auf dem 7er anders ausgeführt als auf dem 9er? Oder hat jemand eine Idee was hier los sein könnte? Gruß, Olibats
Hi Der LDMFD-Befehl lädt und speichert mehrere Register mit einem Befehl. Funktioniert folgendermaßen: R0 <- [LR] LR <- LR + 1 R1 <- [LR] ... (Ich kenne ihn mit folgendem Syntax: LDMFD LR!, {R0-R14} ) Normalerweise wird dieser Befehl benutzt um Register auf dem Stack zu speichern bzw. wieder Herzustellen. ARM-Prozessoren verfügen über verschiedenen Fehler"interrupts". Heißt: Tritt ein Fehler auf, dann springt der ARM in die entsprechende Routine, die ähnlich einer ISR angegeben wird. Diese können dann den Fehler behandeln. Eine dieser Routinen reagiert auf "Data Abort", ich nehme an, dass es sich bei deiner Funktion "daborthandler" um eben diese Funktion handelt. Der Fehler "Data Abort" tritt auf, wenn der MC einen Speicherzugriff durchführen will, der nicht funktioniert, z.B. Schreibezugriff auf FLASH, bzw. auf nichtexistenden Speicher. Konkret würde ich in deinem Fall vermuten: Der LR ist bei dir nicht korrekt initialisiert und zeigt auf eine falsche Stelle, falls überhaupt der LR gemeint ist. Spontan würde ich dafür nämlich den SP benutzten. Auf jeden Fall ließt du von einem verbotenen Bereich. Gruß Michel
Hallo Olibats, LR sollte eigentlich die Startadresse der Task +4 enthalten, damit es dann mit dem Rücksprungbefehl am Ende funktioniert. AAAAAAAA ist ein Dummywert aus dem Task-Stack, ich denke schon, dass LDMFD funktioniert. Vermutlich ist der Task-Stack vor dem Aufruf dieser Einsprungroutine nicht mit sinnvollen Registerinhalten vorbelegt worden. Das macht eine C-Routine, vielleicht geht sie falsch mit Pointern um (Compilerflags!) oder sie wurde nicht aufgerufen. Mit freundlichen Grüßen Martin
Hallo, soweit ich das bisher habe, soll das so gehen: Wenn der erste Task gestartet wird, dann führt er die asms aus meinem ersten Post aus. Dabei sollte er vermutlich irgendwelche sinnvollen Werte laden. In meinem Fall lädt er die Register offensichtlich mit Dummywerten voll: R1 => 0x01010101 R2 => 0x02020202 ... R13 => wird korrekt auf den anfang gesetzt R14 => 0xAAAAAAAA Wenn ich nun R0-R14 durch R0-R13 ersetze geht es erstmal weiter. Und zwar bis zum ersten Task. Der wird in wilder Endlosschleife ausgeführt und jeder noch so verzweifelte Versuch meinen Arm zum Wechsel zu bewegen schlägt fehl. daborthandler ist übrigens genau dieser beschriebene "Data Abort". Ein Problem, ist, dass ich den Befehl nach dem NOP nicht wirklich verstehe. Was macht er da? Das mit dem 4 abziehen wird ja dann beim SUBS ... gemacht. Wie gesagt, unterbinde ich das überschreiben vom LR dadurch, dass ich den LDMFD Befehl auf R0-R13 ändere, springt er den ersten Task korrekt an. Ändere ich das nicht, dann hüpft er mir ans Ende einer Funktion. Ich nehme an, dass das dann als undefiniertes Verhalten gilt :-)
Weiss zufällig in welchen registern ich den Supervisor (SWI) initialisiere? Ich finde es irgendwie nicht.
was soll denn "der" supervisor sein? es gibt nur einen supervisor mode, schau dir mal die doku zu dem/den statusregister(n) an. da könnte man z.B. den stack initialisieren wollen... swi ist definitiv keine gebräuchliche abkürzung für supervisor, sondern für software interrupt.
Hab ich ja! Dort steht nur "blah, gibt einen Software Interrupt und der Befehl ist SWI" Dann kann man noch einen Parameter mitgeben, der ist aber nur interessant, wenn eine Exception auftritt. Aber nirgends steht WO ich die Adresse der Methode hinschreiben muss!! Deswegen hab ich nach etwas gesucht was es sein könnte. Und Supervisor wurde irgendwie in dem Zusammenhang erwähnt. Daher mein Denkfehler. Ich meine folgendes: void softw_interrupt() { ... } int main() { unsigned int* x = 0x12345678 // <-- *x = (unsigned int)softw_interrupt; while (1) ... } statt dem 12345678 muss ich ja irgendwas einsetzen. DAS finde ich nicht. Geschweige denn finde ich irgendwelche Register, die das ganze strukturieren wie beim AIC, PIT, ...
Mir ist zwar schleierhaft, was du mit deinem Code meinst, aber ich kann gerne erklären, was ein SWI ist. Dein uC führt gerade irgend einen Code aus, z.B. im User Mode. Dieser Code enthält dann die Anweisung 0x00001000 SWI #0x0815 0x00001004 mov r0, r1 Daraufhin macht der Core folgendes: - R14_svc = 0x1004 (Adresse nach dem SWI) - SPSR_svc = CPSR - CPSR[4:0] = b10011 (Supervisor) - CPSR[5] = 0 (ARM State) - CPSR[7] = 1 (Disable IRQ, FIQ werden nicht verändert) - PC = 0x8 (oder 0xffff0008 bei high-vecs) An Adresse 0x8 befindet sich der SWI Vektor, d.h. normalerweise ein Branch oder Load zum PC. Ein Register mit Sprung-Adressen wie beim VIC gibt es da nicht. Gruß, Dominic
> Hab ich ja! Dort steht nur "blah, gibt einen Software Interrupt und der > Befehl ist SWI" Dann kann man noch einen Parameter mitgeben, der ist > aber nur interessant, wenn eine Exception auftritt. Die Exception ist das, was durch SWI ausgelöst wird. Es wird zum SWI-Handler gespungen, und der kann dann den Parameter auslesen. Was der bedeutet, hängt von dir ab. > Aber nirgends steht WO ich die Adresse der Methode hinschreiben muss!! Die Adresse ist fest vorgegeben. Du wirst das in Assembler machen müssen. Ich benutze das mit meinem ARM7TDMI so: .section .vectors .global __vectors .global _start .org 0 _start: __vectors: b startup_routine @ reset vector b undef_routine @ undefined instruction b vPortYieldProcessor @ software interrupt b abort_prefetch_routine @ prefetch abort b abort_data_routine @ data abort b undef_routine @ reserved b irq_routine @ IRQ b undef_routine @ FIQ Im Linkerskript habe ich dann eine Sektion .vectors definiert, die immer am Anfang von .text landet. Bei mir im FreeRTOS löst portYield den SWI aus. Dieses wiederum springt dann wie man sieht einfach zu vPortYieldProcessor weiter, welches dann einen Taskwechsel auslöst.
Hm, Danke für die Hilfe. Die ffff0008 hab ichgesucht. Ich denke jetzt werde ich das hinbekommen.. Danke! Weiss vielleicht jemand eine Art Tutorial oder eine gute Zusammenstellung der Register und Funktionseinheiten des ARM? Ich dachte an sowas, wie hier das AVR GCC Tutorial. In dem Handbuch finde ich mich (offensichtlich) nicht so gut zurecht. Gruß, Olibats
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.