Forum: Mikrocontroller und Digitale Elektronik STM32: Kann mir das jemand erklären Interrupt wird zweimal aufgerufen


von Dominic (Gast)


Lesenswert?

Hallo,
ich bin beim STM32F3 gerade auf ein für mich sehr merkwürdiges Phänomen 
gestoßen, was scheinbar aber gar nicht so merkwürdig sein soll. Und zwar 
wird mein externer flankengetriggerter Interrupt einfach zwei Mal 
aufgerufen. Trotz einer Flanke.

Ich habe jetzt wirklich eine Zeit verbracht den Fehler zu finden, aber 
es kann mittlerweile nur noch am Controller liegen. Und ich habe hier 
auch eine offizielle Erklärung des Phänomens gefunden: 
https://www.keil.com/support/docs/3928.htm Nur verstehe ich es nicht 
ganz. Kann das vllt jemand grob erklären, bzw sagen wie man das Problem 
beheben kann?
1
void EXTI4_IRQHandler(void)
2
{
3
  /* USER CODE BEGIN EXTI4_IRQn 0 */
4
  static uint8_t edge[256];
5
  static uint8_t i = 0;
6
  edge[i++] = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4);
7
8
  /* USER CODE END EXTI4_IRQn 0 */
9
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
10
  /* USER CODE BEGIN EXTI4_IRQn 1 */
11
12
  /* USER CODE END EXTI4_IRQn 1 */
13
}

mit
1
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
2
{
3
  /* EXTI line interrupt detected */
4
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
5
  {
6
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
7
    HAL_GPIO_EXTI_Callback(GPIO_Pin);
8
  }
9
}

von jo mei (Gast)


Lesenswert?

Dominic schrieb:
> Kann das vllt jemand grob erklären,

Der Schreibvorgang zum Löschen des Interrupt Flags wirkt nicht
sofort sondern mit einer internen Takt-Verzögerung da die
gesamte Maschine durch verschiedene Takte synchronisiert ist
und die Datenübernahme des gewünschten Bits erst Takt-verschoben
übernommen werden kann - Stichwort Datenübernahme in andere
Clock-Domain.

Dominic schrieb:
> sagen wie man das Problem beheben kann?

So wie es in deinem Link beschrieben ist. Wobei ich die erste
Version als die saubere bevorzugen würde da sie keine weiteren
Nebeneffekte mit sich bringt.

von Dominic (Gast)


Lesenswert?

Ich muss das erstmal ausprobieren. Aber das kann doch keine Lösung sein. 
Und woher weiß man sowas? Für mich ist das ein Konstruktionsfehler.

von jo mei (Gast)


Lesenswert?

Dominic schrieb:
> Für mich ist das ein Konstruktionsfehler.

Wird ja indirekt zugegeben.

Dominic schrieb:
> Aber das kann doch keine Lösung sein.

Wenn du dazu keine Lust hast: Dann lass es eben sein und
wurschtele ohne Problemlösung weiter.

Eine Problemlösung wäre es auch sich vom 20. Stock eines
Hochhauses zu stürzen, dann hat man keine weiteren Probleme
zu lösen.

von (prx) A. K. (prx)


Lesenswert?

Ich würde es als Konstruktionseigenschaft bezeichnen, nicht als 
Konstruktionsfehler. Binse: Komplexe Konstruktionen haben komplexere 
Verhaltensweisen als einfache Konstruktionen. Wenn man sie nutzt, muss 
man damit leben, mehr Dinge beachten zu müssen, als bei einfachen 
Konstruktionen.

Dies setzt sich nahezu beliebig fort. So bieten komplexe Systeme 
vielleicht verschiedene Zugangswege zum gleichen Speicher, mit 
unterschiedlichen Eigenschaften und unterschiedlicher Zugriffszeit. Dann 
gibt es Regeln, wie man damit umzugehen hat, sonst fällt man auf die 
Nase und sieht die gleichen Daten gleichzeitig in unterschiedlichem 
Zustand.

Hat man mehrere Cores mit teils getrennten und teils gemeinsamen Caches, 
dazu dann noch DMA, verkompliziert sich das weiter. Den Vorteil höherer 
Performance erkauft man sich mit hässlichen teils schwer zu findenden 
Fehlern, wenn man sich nicht an den zunehmenden Satz von Regeln hält.

Mit AVRs hat man es einfacher - aber weniger leistungsfähig.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

(prx) A. K. schrieb:
> Mit AVRs hat man es einfacher

Wobei es da aber auch Ausnahmen gibt. Die asynchronen Timer brauchen 
mehrere Takte, ehe ein Interruptflag als gelöscht gelesen wird. Die 
Verzögerung ist im Datenblatt angegeben und erfolgt auch im synchronen 
Mode.

Bei den 32Bit-Boliden löscht man die Flags direkt nach dem Eintritt in 
den Interrupthandler, sofern möglich.

Ein doppeltes Auslösen kann allerdings auch an einem prellenden Taster 
liegen.

von Peter D. (peda)


Lesenswert?

(prx) A. K. schrieb:
> Hat man mehrere Cores mit teils getrennten und teils gemeinsamen Caches,
> dazu dann noch DMA, verkompliziert sich das weiter.

Und oftmals lassen sich auch für Peripherie und Core verschiedene 
Taktteiler einstellen.

von Jim M. (turboj)


Lesenswert?

Dominic schrieb:
> Kann das vllt jemand grob erklären, bzw sagen wie man das Problem
> beheben kann?

Cortex-M3 (und -M4) haben einen Schreibpuffer, und du kannst halt den 
Rücksprung aus dem Interrupt ausführen während der Schreibbefehl zum 
Löschen des Flags noch im Puffer steht.

Abhilfe ist dadurch auch klar: Warten bis der Schreibbefehl "durch" ist. 
In den meisten Fällen löscht man einfach die Flags VOR den anderen 
Aktionen im Handler.

Ein anderer eleganter Weg ist ein nachfolgendens Dummy Lesen eines 
beliebigen Registers (das keine Nebenwirkungen haben darf[1]) im selben 
Peripherial. Denn dieses Lesen muss zwingend auf den Schreibvorgang 
warten, Stichwort "Strongly ordered" memory.

von m.n. (Gast)


Lesenswert?

Jim M. schrieb:
> Ein anderer eleganter Weg ist ein nachfolgendens Dummy Lesen eines
> beliebigen Registers (das keine Nebenwirkungen haben darf[1]) im selben
> Peripherial.

Hast auch eine "elegante" HAL-Funktion dafür? Sonst kann es der TO nicht 
umsetzen ;-)
Oder weniger provokativ: lass das HAL-Zeug weg und programmiere die 
Register direkt. Dann weißt Du, wo Du was tust.

von Stefan F. (Gast)


Lesenswert?

Dominic schrieb:
> Ich muss das erstmal ausprobieren. Aber das kann doch keine Lösung sein.
> Und woher weiß man sowas? Für mich ist das ein Konstruktionsfehler.

Damit hatte ich auch so meine Probleme. Ohne die Hilfe hier im Forum 
hätte ich den Effekt nie verstanden. Im Datenblatt steht das jedenfalls 
nur zwischen den Zeilen versteckt - wie so viele andere Infos auch.

Die ATmegas sind schon sehr viel besser dokumentiert.

von Stefan F. (Gast)


Lesenswert?

Dominic schrieb:
> Ich muss das erstmal ausprobieren. Aber das kann doch keine Lösung sein.
> Und woher weiß man sowas? Für mich ist das ein Konstruktionsfehler.

Damit hatte ich auch so meine Probleme. Ohne die Hilfe hier im Forum 
hätte ich den Effekt nie verstanden. Im Datenblatt steht das jedenfalls 
nur zwischen den Zeilen versteckt - wie so viele andere Infos auch.

Die ATmegas sind schon sehr viel besser dokumentiert.

von foobar (Gast)


Lesenswert?

Würde es nicht reichen, wenn er seinen Code in den 
HAL_GPIO_EXTI_Callback packen würde statt direkt in den IRQ-Handler? 
Dann würde erst das IRQ-Flag gelöscht, danach sein Code ausgeführt (der 
memory-writes macht) und dann der IRQ beendet.  Problem gelöst.

Btw, hat denn schon jemand mal überprüft, ob sein STM32F3xx überhaupt 
diesen zusätzlichen Write-Buffer hat?  Nicht dass er einfach nur 
prellende Tasten hat, oder sowas.


PS: An sich erwarte ich, dass solche Eigenheiten in dem CPU-spezifischen 
Teil des HAL behandelt werden, insb wenn der Problem bekannt ist ...

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.