Datum: 19.02.2008 13:22
Hallo, ich experimentiere hier gerade etwas mit einem LPC2148 herum und möchte einen EInfachen Taskswitch programmieren. Dazu wollte ich folgendes machen: 1. Taskswitch im Timerinterrupt durchführen und dazu: 2. Alle Register auf den Stack sichern 3. Stackpointer und Programmcounter sichern 4. Statusregister sichern 5. Statusregister des nächsten Tasks zurückschreiben 6. Programcounter des nächsten Tasks zurückschreiben Dabei sollen in diesem einfachen Experiment erstmal nur ein Task unterbrochen werden und dann in eine fest definierte Funktion gesprungen werden, nach abarbeiten dieser soll der unterbrochene Tasks fortgesetzt werden. Folgendes (nichtmal kompilierendes) Fragment wollte ich für das Unterbrechen des Tasks nutzen:
void __attribute__ ((interrupt("IRQ"))) timer1_isr(void) { T1IR = 0xff; // clear all interrupt of Timer1 asm volatile( "STMDB SP!, {R0} \n\t" // Alle Register der Userapp sichern "STMDB SP!, {R1} \n\t" // Alle Register der Userapp sichern "STMDB SP!, {R2} \n\t" // Alle Register der Userapp sichern "STMDB SP!, {R3} \n\t" // Alle Register der Userapp sichern "STMDB SP!, {R4} \n\t" // Alle Register der Userapp sichern "STMDB SP!, {R5} \n\t" // Alle Register der Userapp sichern "STMDB SP!, {R6} \n\t" // Alle Register der Userapp sichern "STMDB SP!, {R7} \n\t" // Alle Register der Userapp sichern "STMDB SP!, {R8} \n\t" // Alle Register der Userapp sichern "STMDB SP!, {R9} \n\t" // Alle Register der Userapp sichern "STMDB SP!, {R10} \n\t" // Alle Register der Userapp sichern "STMDB SP!, {R11} \n\t" // Alle Register der Userapp sichern "STMDB SP!, {R12} \n\t" // Alle Register der Userapp sichern "STMDB SP!, {LR} \n\t" // Alle Register der Userapp sichern "MOV R0, #2 \n\t" // Unterbrechen der Userapp mit Status=2 kennzeichnen "STR R0, sheduler_back \n\t" "STR R13, userapp_sp \n\t" // Stackpointer sichern "LDR R14, scheduler_main \n\t" // Rücksprungadresse nach R14 "LDR R0, scheduler_main_sr \n\t"// Statusregister zurücksichern "MSR SPSR, R0 \n\t" ); // Interrupt wird abgeschlossen und r14 und CPSR wiederhergestellt VICVectAddr=0; //Dummy write to signal end of interrupt } |
Leider steige ich noch nicht ganz durch die Sntax des Arm Assemblers durch. Meine Hauptsächliche frage ist allerdings, was genau beim Aufruf eines Interrupts passiert? Wenn ich das richtig verstanden habe, bleibt der Stack völlig unangetastet und der Arm sicher Statusregister und Programmcounter in Schattenregister. Ändert der gcc an diesem Verhalten etwas? Kann mein oben skizziertes Vorhaben so funktionieren, oder habe ich etwas grundlegendes nicht bedacht? Vielen Dank für Eure Hilfe, Stefan
Datum: 19.02.2008 13:46
> Wenn ich das richtig verstanden habe, bleibt der Stack völlig > unangetastet und der Arm sicher Statusregister und Programmcounter in > Schattenregister. Ja. > Ändert der gcc an diesem Verhalten etwas? Daran wird er wohl nichts ändern, aber er kann auf die Idee kommen, z.B. andere Register zu sichern, bevor deine asm-Routine aufgerufen wird. Deshalb definiere die Funktion mit __attribute__((naked)). Dann macht er da garantiert überhaupt nichts. > Kann mein oben skizziertes Vorhaben so funktionieren, oder habe ich > etwas grundlegendes nicht bedacht? Du kannst mal in den Scheduler-Code von FreeRTOS reinschauen und ihn verstehen. Deine Register werden z.B. im IRQ-Stack gespeichert und nicht im Task-Stack, wo es sinnvoller wäre.
Datum: 19.02.2008 13:58
Danke für Deine Antwort. Das jeder Task einen eigenen Stack bekommt möchte ich erst als zweiten Schritt implementieren. Bisher soll nur der eine (der im Beispiel unterbrochene) Task einen Stack haben und der zweite Task bei jedem Aufruf einen neuen Stack aufbauen. Ich möchte bevor ich weitermache erstmal den Taskswitch genau verstehen. Allerdings habe ich irgendwie Probleme mit der Syntax vom Inline-Assembler und vertstehe deshalb den Code von FreeRTOS (danke für den Hinweis) auch nicht so ganz... Obiger Code liefert beim kompilieren immer nur den Fehler: \LOCALS~1\Temp/ccS8aaaa.s OFFSET_IMM) not fixed up Grüße, Stefan
Datum: 21.02.2008 08:31
> Das jeder Task einen eigenen Stack bekommt möchte ich erst als zweiten > Schritt implementieren. Es geht mir eher darum, daß auch die ISR einen eigenen Stack hat. Übrigens: Wo wird eigentlich dein Task-Stackpointer gesichert? > Allerdings habe ich irgendwie Probleme mit der Syntax vom > Inline-Assembler Du wirst nicht darum herumkommen, dich damit zu beschäftigen. Insbesondere auch damit, wie man Parameter an den Assembler übergibt. > und vertstehe deshalb den Code von FreeRTOS (danke für den Hinweis) > auch nicht so ganz... Wenn du den verstehst, verstehst du auch, wie du einen Taskwechsel machen mußt. ;-) > Obiger Code liefert beim kompilieren immer nur den Fehler: > > \LOCALS~1\Temp/ccS8aaaa.s OFFSET_IMM) not fixed up In welcher Zeile? PS: Du mußt daran denken, daß so Dinge wie z.B.
T1IR = 0xff; // clear all interrupt of Timer1 |
Register benutzen, die also vorher gesichert werden müssen.
Datum: 06.05.2008 11:21
Kennt jemand Informationsquellen zu diesem Thema? Tutorials?
Datum: 06.05.2008 14:14
Ja, irgendwo in WinARM steckt ein ASM-Tutorial drin, welches alles beschreibt. MfG Mark
Antwort schreiben
Die Angabe einer Email-Adresse ist freiwillig. Wenn Sie automatisch per Email über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.
Wichtige Regeln - erst lesen, dann posten!
- Suchfunktion und Betreffsuche benutzen - vielleicht gibt es schon einen ähnlichen Beitrag
- Aussagekräftigen Betreff wählen
- Im Betreff angeben um welchen Controllertyp es geht (AVR, PIC, ...)
- Groß- und Kleinschreibung verwenden
- Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
- JPEG-Dateien (.jpg) nur für Fotos verwenden, Schaltpläne, Screenshots usw. als PNG oder GIF anhängen
Formatierung (mehr Informationen...)
- [c]C-Code[/c]
- [avrasm]AVR-Assembler-Code[/avrasm]
- [pre]vorformatierter Text (z.B. Code in anderen Sprachen)[/pre]
- [math]Formel in LaTeX-Syntax[/math]
- [[Titel]] - Link zu Artikel