Hallo zusammen,
wie immer gilt: ich hab das Forum gründlich nach passenden Threads
durchsucht und keinen finden können, der sich genau mit meiner
Problematik befasst. Falls ich was übersehen habe, bitte ich um kurzen
Hinweis !
Problemstellung:
ich möchte mit dem PIT des AT91SAM7 unter uVision3 zyklische Interrupts
auslösen und verarbeiten. Folgendermaßen bin ich vorgegangen:
1 | //init of Advanced Interrupt Controller
|
2 | *AT91C_AIC_IECR = 0x00000002; //enable PIT IR
|
3 | AT91C_AIC_SMR[1] = 0x00000007; //set priority of PIT IR
|
4 | AT91C_AIC_SVR[1] = (AT91_REG) ISR_periph; //set adress to branch to if peripheral IR occurs
|
5 |
|
6 | //init of Periodic Internal Timer
|
7 | *AT91C_PITC_PIMR = ( 0x000FFFFF & ( TIMER_PARA_MicroCycle * (TIMER_PARA_SysClock / (16 * 1000) ) ) ) ; //set cycle of timer
|
8 | *AT91C_PITC_PIMR |= 0x03000000; //enable the timer and the corresponding IR
|
9 |
|
10 | __irq void ISR_periph (void) //executed every time a peripheral IR occurs
|
11 | {
|
12 | if ( *AT91C_PITC_PISR ) //IR caused by Periodic Interval Timer ?
|
13 | {
|
14 | count++;
|
15 |
|
16 | if (count >= 2)
|
17 | {
|
18 | SET_PWR_LED(ON);
|
19 | }
|
20 |
|
21 | *AT91C_AIC_ICCR = 0x00000002; //clear the IR-Bit
|
22 | tempvar = *AT91C_PITC_PIVR; //reading PIVR resets the timer ir
|
23 |
|
24 | }
|
25 |
|
26 | *AT91C_AIC_EOICR = 0xFFFFFFFF; //end of IR
|
27 | }
|
Soweit funktioniert das auch: die Power-LED geht an, deshalb weiß ich,
dass die ISR mehr als nur einmal angesprungen wird.
Jetzt kommt das eigentliche Problem: laut Datasheet des Controllers soll
in der ISR als erstes das "Interrupt Vector Register" (AIC_IVR) gelesen
werden: "The read of AIC_IVR is the entry point of the interrupt
handling which allows the AIC to consider that the interrupt has been
taken into account by the software." Zwar funktioniert mein IR-Managment
auch ohne diesen Lesezugriff. Allerdings möchte ich IRs auch
verschachteln können (s. Beitrag "AT91SAM7 -> Interrupts verschachteln (nested IRs)"),
was mir bisher nicht gelingt, vermutlich u.a. weil ich das IVR nicht
lese. Daher nun die ISR mit IVR-Zugriff:
1 | __irq void ISR_periph (void) //executed every time a peripheral IR occurs
|
2 | {
|
3 | tempvar = *AT91C_AIC_IVR; //reading IVR as entry point of ISR
|
4 |
|
5 | if ( *AT91C_PITC_PISR ) //IR caused by Periodic Interval Timer ?
|
6 | {
|
7 | count++;
|
8 |
|
9 | if (count >= 2)
|
10 | {
|
11 | SET_PWR_LED(ON);
|
12 | }
|
13 |
|
14 | *AT91C_AIC_ICCR = 0x00000002; //clear the IR-Bit
|
15 | tempvar = *AT91C_PITC_PIVR; //reading PIVR resets the timer ir
|
16 |
|
17 | }
|
18 |
|
19 | *AT91C_AIC_EOICR = 0xFFFFFFFF; //end of IR
|
20 | }
|
Ergebnis: die ISR wird nur noch ein einziges Mal angesprungen. Das
stelle ich dadurch fest, dass da die LED nun nur noch angeht, wenn ich
"SET_PWR_LED(ON);" vor der if-Bedingung ausführe.
Hat irgendjemand einen Tip für mich, wodran es hapert? Spielt das
"__irq" möglicherweise eine Rolle? Habe das in anderen Beispielen so
bisher nie gesehen. Lasse ich das weg, gelingt mir aber auch ohne den
IVR-Zugriff kein zyklisches Aufrufen der ISR.
Gruß,
Tom