Forum: Mikrocontroller und Digitale Elektronik Interrupt latency zu lang


von geronimer (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

Ich arbeit mir dem EvalBoard ADUC7026 - ARM Prozessor. Der unten 
angehängte code löst einen Interrupt jede 5µs (200kHz) auf. Dabei wird 
an ein Pin (P4.3) gesetzt und gelöscht
und am Oszi angeschaut. Im main sind einfach die Configs gesetzt für den 
Interrupt und auch hier wird ein anderer Pin (P4.2) gesetzt
und gelöscht um am Oszi zu erkennen, wie lange der Interrupt eigentlich 
braucht.

Mein egentliches Problem: Man sieht am Oszi ganz gut wie der Pin (P4.2) 
im main mal ein und ausgeschaltet wird bis zum Interrupt,
danach ist zu erkennen, dass der Interrupt ganze 1.6µs braucht um den 
Pin P4.3 zu setzen. Nach dem löschen braucht er wieder 1µs
zum main zu sprigen.

Obwohl ich einen Fast Interrupt reQuest verwende hat sich an der latency 
nichts verändert. Weiß vielleicht jemand warum es
so lange dauert? Oder wie man die interrupt latency verbessern könnte?

Danke im voraus!

Gruß

von (prx) A. K. (prx)


Lesenswert?

Beim ARM7 muss man üblicherweise Interrupt-Handler Funktionen als solche 
kennzeichnen. Und zwar unterschiedlich je nachdem ob IRQ oder FIQ. 
Andernfalls kann es Most im Hauptprogramm geben.

Dazu kommt, dass beim ARM7 Interrupt-Funktionen immer native 
ARM-Funktionen sind, keine Thumb-Funktionen. ARM-Funktionen laufen beim 
ADuC7000 im RAM deutlich flotter als im ROM. Such mal beim Compiler, wie 
man Funktionen ins RAM legen kann.

Erheblich schneller geht es mit einem FIQ-Handler in Assembler, weil 
dann die Adressen und Werte nicht erst im Handler geladen werden müssen, 
sondern in den separaten Registern vom FIQ-Kontext schon vorbesetzt 
werden können. Zudem entfällt dann der bei FIQs ziemlich hässliche 
Overhead durch den Compiler.

In C wird der FIQ oft überhaupt nicht schneller sein als der IRQ. Wenn 
der Compiler aus lieber Gewohnheit die Register ab R0 zuerst verwendet, 
der FIQ-Kontext aber erst bei R8 anfängt, so dass die verwendeten 
Register so oder so gesichert werden müssen.

M.a.W: Der FIQ bringt nur bei Handler in Assembler wirklich Vorteile.

von geronimer (Gast)


Lesenswert?

Danke für deine Antwort. Ich versuch mal deine Tipps umzusetzen.

Gruß

von Klaus (Gast)


Lesenswert?

Hallo,

benütze mal sowas

void FIQ_Routine (void)   _attribute_ ((interrupt("FIQ")));
void FIQ_Routine (void)
{
 ...
}

statt einer normalen Funktionsdeclaration
falls es dein Compiler zulässt


Gruss Klaus

von geronimer (Gast)


Lesenswert?

Hallo,

der Compiler gibt zwar keine Fehler aus, jedoch macht der Code nicht 
mehr das was er eigentlich machen soll. Ich habe gar keine output mehr.

Wenn ich GP_TIMER_BIT auskommentiere funktioniert zwar die main, aber 
ein Interrupt wird nicht ausgelöst.

gruß

von Klaus (Gast)


Lesenswert?

Hallo,

schau Dir mal deine crt.s (die startup Routine) genau an und vergleiche 
sie eventuell mit anderen die du im Netz findest.

die Adresse der FIQ Routine sollte bereits dort in den _vectors 
auftauchen z.B. so :


_start:

# Exception Vectors

_vectors:  ldr PC, Reset_Addr
      ldr PC, Undef_Addr
      ldr PC, SWI_Addr
      ldr PC, PAbt_Addr
      ldr PC, DAbt_Addr
      ldr PC, ReservAddr  /* Reserved Vector (holds Philips ISP sum) */
      ldr PC, [PC,#-0xFF0]  /* see page 71 of "Insiders Guide to the 
Philips ARM7-Based Microcontrollers" by Trevor Martin  */
      ldr PC, FIQ_Addr

Reset_Addr: .word  Reset_Handler    /* defined in this module below  */
Undef_Addr: .word  UNDEF_Routine    /* defined in main.c  */
SWI_Addr:  .word  SWI_Routine     /* defined in main.c  */
PAbt_Addr:  .word  UNDEF_Routine    /* defined in main.c  */
DAbt_Addr:  .word  UNDEF_Routine    /* defined in main.c  */
IRQ_Addr:  .word  IRQ_Handler     /* defined in main.c  */
ReservAddr: .word 0           /* rounds the vectors and ISR addresses to 
64 bytes total  */
FIQ_Addr:  .word  FIQ_Routine     /* defined in main.c  */


Obige Sequenz stammt aus einem meiner Projekte und ist für einen LPC2148 
von NXP, auch ein ARM7 Prozessor, und läuft bestens

Gruss Klaus

von geronimer (Gast)


Lesenswert?

Hallo,

die startup Routine ist so ziemlich gleich.

Ich hebe jetzt mal den Tipp von A. K. befolgt und gefunden wie man die 
IRQ-Funktion ins RAM ablegt und von dort abruft.

void IRQ_Function (void) _attribute_ ((interrupt ("IRQ"))) 
_attribute_ ((section (".ram_func")));

Das hat jetzt viel gebracht. Interrupt wird viel schneller abgearbeitet.

Jedoch habe ich das Problem. Wenn ich variablen außerhalb meiner IRQ 
funktion definiere, z.B. als

int Index;

dann kann die Funtion damit nichts anfangen. Wenn ich sie innerhalb der 
IRQ-Funktion definiere, kann es zwar damit arbeiten aber dann habe ich 
Problem, dass es immer wieder neu initialisiert wird.

Gruß

von (prx) A. K. (prx)


Lesenswert?

Achte auf "volatile": 
http://www.mikrocontroller.net/articles/Interrupt#Wichtige_Eigenschaften_von_ISRs

> dann kann die Funtion damit nichts anfangen.

Wie äussert sich das?

von geronimer (Gast)


Lesenswert?

Hallo,

volatile habe ich schon probiert gehabt. Leider ohne Erfolg. Danke für 
den Link.

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.