EXTI wird doppelt ausgeführt

Gast #6965725
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
}
Gast #6965748
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.
Gast #6965761
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.
Gast #6965822
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.
Gast #6965855
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
}
#6965872
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren