Forum: Compiler & IDEs Taskswitch auf Arm7 Controller


von Stefan (Gast)


Lesenswert?

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:
1
void __attribute__ ((interrupt("IRQ"))) timer1_isr(void)
2
{
3
  T1IR = 0xff;      // clear all interrupt of Timer1
4
  asm volatile(
5
      "STMDB  SP!, {R0}  \n\t"     // Alle Register der Userapp sichern
6
      "STMDB  SP!, {R1}  \n\t"     // Alle Register der Userapp sichern
7
      "STMDB  SP!, {R2}  \n\t"     // Alle Register der Userapp sichern
8
      "STMDB  SP!, {R3}  \n\t"     // Alle Register der Userapp sichern
9
      "STMDB  SP!, {R4}  \n\t"     // Alle Register der Userapp sichern
10
      "STMDB  SP!, {R5}  \n\t"     // Alle Register der Userapp sichern
11
      "STMDB  SP!, {R6}  \n\t"     // Alle Register der Userapp sichern
12
      "STMDB  SP!, {R7}  \n\t"     // Alle Register der Userapp sichern
13
      "STMDB  SP!, {R8}  \n\t"     // Alle Register der Userapp sichern
14
      "STMDB  SP!, {R9}  \n\t"     // Alle Register der Userapp sichern
15
      "STMDB  SP!, {R10}  \n\t"     // Alle Register der Userapp sichern
16
      "STMDB  SP!, {R11}  \n\t"     // Alle Register der Userapp sichern
17
      "STMDB  SP!, {R12}  \n\t"     // Alle Register der Userapp sichern
18
      "STMDB  SP!, {LR}  \n\t"     // Alle Register der Userapp sichern
19
      "MOV  R0, #2    \n\t"     // Unterbrechen der Userapp mit Status=2 kennzeichnen
20
      "STR  R0, sheduler_back \n\t"     
21
      "STR R13, userapp_sp \n\t"      // Stackpointer sichern
22
      "LDR R14, scheduler_main \n\t"  // Rücksprungadresse nach R14
23
      "LDR R0, scheduler_main_sr \n\t"// Statusregister zurücksichern
24
      "MSR SPSR, R0 \n\t"
25
  ); // Interrupt wird abgeschlossen und r14 und CPSR wiederhergestellt
26
  VICVectAddr=0;  //Dummy write to signal end of interrupt
27
}

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

von Rolf Magnus (Gast)


Lesenswert?

> 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.

von Stefan (Gast)


Lesenswert?

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

von Rolf Magnus (Gast)


Lesenswert?

> 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.
1
 T1IR = 0xff;      // clear all interrupt of Timer1
Register benutzen, die also vorher gesichert werden müssen.

von ewiebe (Gast)


Lesenswert?

Kennt jemand Informationsquellen zu diesem Thema? Tutorials?

von Mork (Gast)


Lesenswert?

Ja, irgendwo in WinARM steckt ein ASM-Tutorial drin, welches alles 
beschreibt.

MfG Mark

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.