Forum: Mikrocontroller und Digitale Elektronik [ARM7] ISR zu langsam -> kein Interrupt mehr


You were forwarded to this site from EmbDev.net. Back to EmbDev.net
von Teakep (Gast)


Lesenswert?

Hallo

Ich habe zur zeit folgendes Problem mit einem AT91SAM7X256.
Ein externer Interrupt wird jede ms ausgelöst und in der ISR werden ein 
paar Berechnungen durchgeführt. Grundsätzlich funktioniert das, aber 
unter bestimmten Umständen tritt irgendein Problem auf, das bewirkt, 
dass meine ISR nicht mehr aufgerufen wird - der Controler selber läuft 
einwandfrei weiter. Nach ein paar Tests habe ich herausgefunden, dass es 
offenbar mit der Abarbeitungszeit der ISR zu tun hat. Kommentiere ich 
hierin Code aus, oder vergrößere das Intervall, in dem der Interrupt 
feuert, dann funktioniert wieder alles wie es soll.
Ich kann das Problem jetzt also umgehen, indem ich den Interrupt nur 
alle 2 ms statt jede ms feuere und die ISR selber etwas aufräume, sodass 
sie schneller abgearbeitet werden kann, aber das ist etwas 
unbefriedigend für mich, weil ich nicht genau verstehe, was hier schief 
läuft.
Kann mir jemand von euch erklären, wie dieses Problem zu Stande kommt 
oder ob ich vielleicht irgendwo einen Fehler gemacht habe?

Das Ganze läuft übrigens unter FreeRTOS.
1
portENTER_CRITICAL();
2
{
3
    // Input on PIN_1
4
    AT91F_PIO_CfgInput(AT91C_BASE_PIOA, IOA_PIN_1);
5
6
    // Interrupt on PIN_1
7
    AT91F_PIO_InterruptEnable(AT91C_BASE_PIOA, IOA_PIN_1);
8
9
    // Setup interrupt
10
    AT91F_AIC_ConfigureIt(AT91C_BASE_AIC,
11
                          AT91C_ID_PIOA,
12
                          AT91C_AIC_PRIOR_LOWEST,
13
                          AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE,
14
                          isr_pioa_Wrapper);
15
16
    AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_PIOA);
17
}
18
portEXIT_CRITICAL();
19
20
int dummy = AT91C_BASE_PIOA->PIO_ISR;
1
void isr_pioa_Wrapper(void)
2
{
3
    /* Save the context of the interrupted task. */
4
    portSAVE_CONTEXT();
5
6
    /* Call the handler to do the work.  This must be a separate
7
       function to ensure the stack frame is set up correctly. */
8
    isr_pioa_Handler();
9
10
    /* Restore the context of whichever task will execute next. */
11
    portRESTORE_CONTEXT();
12
}
1
void isr_pioa_Handler(void)
2
{
3
    int dummy = AT91C_BASE_PIOA->PIO_ISR;
4
    dummy = dummy;
5
6
    isr_counter++;
7
8
    // ...
9
10
    /* Clear the interrupt. */
11
    AT91C_BASE_AIC->AIC_EOICR = 0;
12
}

von Nico S. (nico22)


Lesenswert?

Ist doch ganz klar: Deine Interrupts passieren schneller, als sie 
abgearbeitet werden können. Das kann doch nicht funktionieren. Also 
Berechnungen aus der ISR verlagern und in der ISR beispielsweise nur ein 
Flag setzen.

von Andreas B. (Gast)


Lesenswert?

AIC_EOICR wird ganz am Ende geschrieben und das nur mit deaktivierten 
Interrupts. Kann sein, dass das alles gegeben ist, aber ich würde 
erwarten, dass das der eigentliche Interrupt-Handler (ARM7 hat ja nur 
einen, plus einen fürs FIQ) macht.

Also, ich weiß nicht wie das mit FreeRTOS aussieht, dazu noch in 
Kombination mit der Atmel at91lib (? sieht mir zumindest von den 
Definitionen so aus), aber das EOICR im Handler scheint mir suspekt.

von Teakep (Gast)


Lesenswert?

Nico Sch. schrieb:
> Ist doch ganz klar: Deine Interrupts passieren schneller, als sie
> abgearbeitet werden können. Das kann doch nicht funktionieren.

Nach meinem Verständnis führt das aber "nur" dazu, das zwischendurch 
Interrupts verloren gehen und nicht, dass ich gar keinen mehr 
mitbekomme. Oder liege ich hier schon falsch?
Wie gesagt kann ich das Problem ja bereits umgehen, aber ich möchte 
gerne genau verstehen, warum es auftritt, um dann entscheiden zu können, 
ob meine "Lösung" wirklich eine ist, oder ob eine andere nicht 
vernünftiger wäre.

> The nIRQ line can be asserted only if an interrupt condition occurs on an
> interrupt source with a higher priority. If an interrupt condition happens (or
> is pending) during  the interrupt treatment in progress, it is delayed until the
> software indicates to the AIC the end of the current service by writing the
> AIC_EOICR (End of Interrupt Command Register). The write of AIC_EOICR is the
> exit point of the interrupt handling.

Wenn ich am Ende der ISR nicht in AIC_EOICR schreibe, dann wird die ISR 
nur ein einziges mal aufgerufen. Das ist also leider keine Lösung :/
Das habe ich so auch in Beispielen zu FreeRTOS gesehen.

von Andreas B. (Gast)


Lesenswert?

Teakep schrieb:
> Wenn ich am Ende der ISR nicht in AIC_EOICR schreibe, dann wird die ISR
> nur ein einziges mal aufgerufen. Das ist also leider keine Lösung :/
> Das habe ich so auch in Beispielen zu FreeRTOS gesehen.

Ich kenne die Implementierung von FreeRTOS nicht, deshalb war mein 
Verdacht, dass EOICR zweimal geschrieben wird. Denn wegen des einzigen 
normalen Interrupts, den die ARMs ausser Cortex-M bieten, läuft ja alles 
über einen einzigen System-Interrupt-Handler, der dann wiederum je nach 
aufgetretenem externen Interrupt den eigentlichen Handler aufruft.

Normalerweise macht dann dieser System-Handler den ganzen Zyklus: Lesen 
AIC_IVR, Reaktivieren Interrupts, Aufruf des eigentlichen Handlers, 
Deaktivieren Interrupts, Schreiben AIC_EOICR.

Wenn das in FreeRTOS anders läuft, auch gut. Nur müssen die Interrupts 
definitiv deaktiviert sein bevor EOICR geschrieben wird und innerhalb 
des restlichen Handlers nicht wieder reaktiviert werden.

von Teakep (Gast)


Lesenswert?

Ich fürchte ich versteh nicht ganz, worauf du hinaus willst.

Was FreeRTOS durch die Aufrufe von portSAVE_CONTEXT und 
portRESTORE_CONTEXT macht ist:
1
#define portRESTORE_CONTEXT()                                           \
2
{                                                                       \
3
extern volatile void * volatile pxCurrentTCB;                           \
4
extern volatile unsigned portLONG ulCriticalNesting;                    \
5
                                                                        \
6
    /* Set the LR to the task stack. */                                 \
7
    asm volatile (                                                      \
8
    "LDR        R0, =pxCurrentTCB                               \n\t"   \
9
    "LDR        R0, [R0]                                        \n\t"   \
10
    "LDR        LR, [R0]                                        \n\t"   \
11
                                                                        \
12
    /* The critical nesting depth is the first item on the stack. */    \
13
    /* Load it into the ulCriticalNesting variable. */                  \
14
    "LDR        R0, =ulCriticalNesting                          \n\t"   \
15
    "LDMFD  LR!, {R1}                                           \n\t"   \
16
    "STR        R1, [R0]                                        \n\t"   \
17
                                                                        \
18
    /* Get the SPSR from the stack. */                                  \
19
    "LDMFD  LR!, {R0}                                           \n\t"   \
20
    "MSR        SPSR, R0                                        \n\t"   \
21
                                                                        \
22
    /* Restore all system mode registers for the task. */               \
23
    "LDMFD  LR, {R0-R14}^                                       \n\t"   \
24
    "NOP                                                        \n\t"   \
25
                                                                        \
26
    /* Restore the return address. */                                   \
27
    "LDR        LR, [LR, #+60]                                  \n\t"   \
28
                                                                        \
29
    /* And return - correcting the offset in the LR to obtain the */    \
30
    /* correct address. */                                              \
31
    "SUBS   PC, LR, #4                                          \n\t"   \
32
    );                                                                  \
33
    ( void ) ulCriticalNesting;                                         \
34
    ( void ) pxCurrentTCB;                                              \
35
}
36
/*-----------------------------------------------------------*/
37
38
#define portSAVE_CONTEXT()                                              \
39
{                                                                       \
40
extern volatile void * volatile pxCurrentTCB;                           \
41
extern volatile unsigned portLONG ulCriticalNesting;                    \
42
                                                                        \
43
    /* Push R0 as we are going to use the register. */                  \
44
    asm volatile (                                                      \
45
    "STMDB  SP!, {R0}                                           \n\t"   \
46
                                                                        \
47
    /* Set R0 to point to the task stack pointer. */                    \
48
    "STMDB  SP,{SP}^                                            \n\t"   \
49
    "NOP                                                        \n\t"   \
50
    "SUB    SP, SP, #4                                          \n\t"   \
51
    "LDMIA  SP!,{R0}                                            \n\t"   \
52
                                                                        \
53
    /* Push the return address onto the stack. */                       \
54
    "STMDB  R0!, {LR}                                           \n\t"   \
55
                                                                        \
56
    /* Now we have saved LR we can use it instead of R0. */             \
57
    "MOV    LR, R0                                              \n\t"   \
58
                                                                        \
59
    /* Pop R0 so we can save it onto the system mode stack. */          \
60
    "LDMIA  SP!, {R0}                                           \n\t"   \
61
                                                                        \
62
    /* Push all the system mode registers onto the task stack. */       \
63
    "STMDB  LR,{R0-LR}^                                         \n\t"   \
64
    "NOP                                                        \n\t"   \
65
    "SUB    LR, LR, #60                                         \n\t"   \
66
                                                                        \
67
    /* Push the SPSR onto the task stack. */                            \
68
    "MRS    R0, SPSR                                            \n\t"   \
69
    "STMDB  LR!, {R0}                                           \n\t"   \
70
                                                                        \
71
    "LDR    R0, =ulCriticalNesting                              \n\t"   \
72
    "LDR    R0, [R0]                                            \n\t"   \
73
    "STMDB  LR!, {R0}                                           \n\t"   \
74
                                                                        \
75
    /* Store the new top of stack for the task. */                      \
76
    "LDR    R0, =pxCurrentTCB                                   \n\t"   \
77
    "LDR    R0, [R0]                                            \n\t"   \
78
    "STR    LR, [R0]                                            \n\t"   \
79
    );                                                                  \
80
    ( void ) ulCriticalNesting;                                         \
81
    ( void ) pxCurrentTCB;                                              \
82
}

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.