Forum: Mikrocontroller und Digitale Elektronik EXTI wird doppelt ausgeführt


von Spock der Vulkanier (Gast)


Lesenswert?

Hallo,

mein EXIT0 auf PA0 wird stets doppelt ausgeführt. Woran kann das liegen?
1
EXTI->IMR |= EXTI_IMR_MR0; //Interrupt
2
EXTI->FTSR |= EXTI_FTSR_TR0; //fallende Flanke
3
EXTI->PR |= EXTI_PR_PR0; //Pending löschen
4
NVIC->ICPR[EXTI0_IRQn / 32] |= 1 << (EXTI0_IRQn % 32);
5
NVIC->ISER[EXTI0_IRQn / 32] |= 1 << (EXTI0_IRQn % 32);
6
NVIC->IP[EXTI0_IRQn / 4] |= (1 << 4) << (8 * (EXTI0_IRQn % 4));
7
8
void EXTI0_IRQHandler() {
9
  EXTI->PR |= EXTI_PR_PR0; //pending löschen
10
11
  if (gpfIsr) {
12
    gpfIsr();
13
  }
14
}

von Stefan F. (Gast)


Lesenswert?

Spock der Vulkanier schrieb:
> Woran kann das liegen?

Kontaktprellen.

Oder du verlässt die ISR zu schnell nach "pending löschen". Das ist 
möglich, weil die CPU schneller rennt, als der Interrupt Controller.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Spock der Vulkanier schrieb:
> Woran kann das liegen?
Was ist die Interruptquelle? Wie sieht das reale Signal am 
Interrupteingang aus?

: Bearbeitet durch Moderator
von Spock der Vulkanier (Gast)


Lesenswert?

Ich habe mich getäuscht. Nach dem initialisieren wird der immer einmal 
ausgelöst.

Warum ist das so? Der Interrupt bin ist Input, mit Pullup, EXTI0, PA0 
und mit einem anderen Pin verbunden, Output und vor dem initialisieren 
des EXTI auf HIGH gesetzt.

Der EXTI wird dann auf fallende Flanke konfiguriert.

Beitrag #6965756 wurde von einem Moderator gelöscht.
von Stefan F. (Gast)


Lesenswert?

Ich vermute, dass deine ISR sofort nach dem Freigeben in EXTI->IMR 
aufgerufen wird, noch bevor du das Pending-Flag löschst. Und das 
passiert wohl, weil der Pin vorher mal kurz auf LOW war, nämlich bevor 
der Pullup aktiviert wurde.

Tausche mal die Reihenfolge:

> EXTI->IMR |= EXTI_IMR_MR0; //Interrupt

Ist wie gesagt nur eine Vermutung.

von Spock der Vulkanier (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Das sollte zum Schluss kommen, nachdem alle anderen Parameter
> konfiguriert sind.

Das ändert leider nichts. Direkt nach
> EXTI->IMR |= EXTI_IMR_MR0;
wird in PR das Flag gesetzt und der Interrupt ausgelöst, obwohl das 
Signal High ist.

von Peter D. (peda)


Lesenswert?

Spock der Vulkanier schrieb:
> Direkt nach
>> EXTI->IMR |= EXTI_IMR_MR0;
> wird in PR das Flag gesetzt und der Interrupt ausgelöst

Das Init sollte natürlich unter Interruptsperre erfolgen.

von Stefan F. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Tausche mal die Reihenfolge:
> EXTI->IMR |= EXTI_IMR_MR0; //Interrupt

Das fehlte der Rest des Satzes:

Tausche mal die Reihenfolge:
EXTI->IMR |= EXTI_IMR_MR0; //Interrupt
soll zum Schluss kommen.

Ich nehme an, dass hast du bereits so verstanden.

Peter D. schrieb:
> Das Init sollte natürlich unter Interruptsperre erfolgen.

Hilft das?
Er hat den EXTI0_IRQn im NVIC ja schon erst nach dem Löschen des 
Pending Flags freigegeben.

von Peter D. (peda)


Lesenswert?

Spock der Vulkanier schrieb:
> if (gpfIsr) {
>     gpfIsr();
>   }

Sowas sollte eine Warnung ergeben.
Kann denn eine Funktion überhaupt auf Adresse 0 gelinkt werden?

von Spock der Vulkanier (Gast)


Lesenswert?

Das Problem ist nicht gravierend, aber ich habe schon etliche 
Reihenfolgen probiert, es ändert sich nichts. Ich forsche mal weiter. 
PA0 ist mit PA8 verbunden.
1
static tpfNmBspIsr gpfIsr = NULL;
2
3
void EXTI0_IRQHandler() {
4
  EXTI->PR |= EXTI_PR_PR0;
5
6
  if (gpfIsr) {
7
    gpfIsr();
8
  }
9
}
10
11
int main(){
12
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
13
  STM32::configPin(GPIOA, 0, STM32::Flags::INPUT, STM32::Flags::OPENDRAIN, STM32::Flags::PULLUP, 0);
14
  STM32::configPinOutput(GPIOA, 8);
15
  STM32::setPin(GPIOA, 8);
16
17
  NVIC->ICPR[EXTI0_IRQn / 32] |= 1 << (EXTI0_IRQn % 32);
18
  NVIC->ISER[EXTI0_IRQn / 32] |= 1 << (EXTI0_IRQn % 32);
19
  NVIC->IP[EXTI0_IRQn / 4] |= (1 << 4) << (8 * (EXTI0_IRQn % 4));
20
  EXTI->FTSR |= EXTI_FTSR_TR0;
21
  EXTI->PR |= EXTI_PR_PR0;
22
  EXTI->IMR |= EXTI_IMR_MR0;
23
24
  while(1);
25
}

von Stefan F. (Gast)


Lesenswert?

Spock der Vulkanier schrieb:
> Ich forsche mal weiter.

Ja, halte uns auf dem Laufenden, wenn du die Erklärung oder Lösung 
findest.

von Peter D. (peda)


Lesenswert?

Jetzt hast Du alles recht planlos umgewürfelt.

Wie gesagt, das globale Interrupt enable darf erst nach dem Init 
erfolgen und das pending clear als letztes vom Init.
Kann sein, daß das pending clear etwas Zeit braucht, also vor dem global 
enable noch mal einige NOPs probieren.
Bei den 32Bittern ist das Interrupthandling ja sehr komplex, da braucht 
es lange Laufzeiten für die Signale zum Synchronisieren.

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.