Warum funktioniert Bit-Toggle mit XOR nicht im Interrupt?

OP #6357966
Lesenswert?

Hat jemand eine Idee, warum beim STM32F103C8 ein Bit-Toggle per XOR in 
einem Timer-Interrupt nicht funktioniert?
1
void TIM2_IRQHandler() {
2
  GPIOC->ODR ^= GPIO_ODR_ODR13;
3
  TIM2->SR &= ~TIM_SR_UIF;
4
}

Entsprechendes Assembly (sieht okay aus):
1
    71:         GPIOC->ODR ^= GPIO_ODR_ODR13; 
2
0x0800031A 6801      LDR      r1,[r0,#0x00]
3
0x0800031C F4815100  EOR      r1,r1,#0x2000
4
0x08000320 6001      STR      r1,[r0,#0x00]

Sobald ich mit dem Debugger durchsteppe, funktioniert es auch. Nur im 
laufenden Betrieb nicht.

Das hier dagegen funktioniert auch im Betrieb:
1
void TIM2_IRQHandler() {
2
  if(is_led_on) {
3
    GPIOC->ODR &= (uint16_t)( ~GPIO_ODR_ODR13 );
4
    is_led_on = false;
5
  } else {
6
    GPIOC->ODR |= GPIO_ODR_ODR13;
7
    is_led_on = true;
8
  }
9
  TIM2->SR &= ~TIM_SR_UIF;
10
}

Für den jeweiligen Fall erhalte ich die angehängten Messungen mit einem 
Logic Analyzer.

Das funktioniert übrigens auch:
1
  while(true) {
2
    GPIOC->ODR ^= GPIO_ODR_ODR13;
3
    wait(1000000);
4
    GPIOC->ODR ^= GPIO_ODR_ODR13;
5
    wait(1000000);
6
  }
Angehängte Dateien:
#6357982
Lesenswert?

Falsch herum, so wäre es richtig:
1
void TIM2_IRQHandler() {
2
  TIM2->SR &= ~TIM_SR_UIF;
3
  GPIOC->ODR ^= GPIO_ODR_ODR13;
4
}


Hintergrund ist der Schreibpuffer im Cortex-M, der dazu führt das der 
Interrupt Handler 2x hintereinander ausgeführt wird, weil das Flag nicht 
rechtzeitig vor dem Tail-Chaining zurück gesetzt wird.

Der nachfolgende GPIO Zugriff ändert dies - nun ist das Interrupt Flag 
im NIVC zurück gesetzt während des Rücksprungs.
Gast #6358103
Lesenswert?

Jim M. schrieb:
> Hintergrund ist der Schreibpuffer im Cortex-M, der dazu führt das der
> Interrupt Handler 2x hintereinander ausgeführt wird, weil das Flag nicht
> rechtzeitig vor dem Tail-Chaining zurück gesetzt wird.

Wegen dieser Sache hatte ich mal eine andere mutmaßliche Fehlfunktion an 
der ist schier verzweifelte.

Vielleicht sollte ST mal eine Anleitung veröffentlichen, wie man korrekt 
zischen den Zeilen des Referenzhandbuches liest und welche 
Kapitel-Übergreifenden Zusammenhänge es da gibt, die nicht direkt im 
Text stehen.

Wenn man von AVR auf STM32 wechselt, fällt man da sonst in ziemlich 
schockierend kaltes Wasser.
#6358176
Lesenswert?

Bei den Boliden sind Interrupt-Controller und CPU getrennt getaktete 
Einheiten. Daher dauert es ein paar Takte, ehe ein Befehl von der CPU 
beim Interrupt-Controller wirksam geworden ist. Das genaue Verhalten 
sollte aber im Manual zum Interrupt-Controller stehen.

Ähnliches gibt es auch beim asynchronen Timer des AVR (z.B. ATtiny261). 
Da dauert es mehrere Takte, ehe ein Löschen des Interruptflags alle 
Synchronisationsstufen des Timers durchlaufen hat. Der Pferdefuß dabei 
ist, diese Verzögerung ist auch im synchronen Mode wirksam.

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