Forum: Mikrocontroller und Digitale Elektronik MSP430 TAIFG Timer interrupt bit wird nicht gelöscht


von Jonas W. (jwitte)


Lesenswert?

Hallo,

ich arbeite mich gerade durch ein MSP430 Tutorial und bin im Abschnitt 
timer interrupt service routines. Mein Programm hat einen Timer der bis 
20000 zählt und dann einen Interrupt auslöst. In der Interrupt service 
routine wird dann ein LED-Pin getoggelt. Das funktioniert auch in der 
Anwendung, jedoch sehe ich in der Register-Übersicht beim Debuggen, dass 
zwar der Interrupt ausgelöst wird sobald 20000 ausgelöst wird, aber das 
TAIFG Bit nicht resettet wird. Es bleibt auf HIGH, obwohl in dem 
Tutorial gesagt wurde, dass die ISR den interrupt cleart. Umsomehr 
wundert mich, dass das Programm offenbar problemlos funktioniert. Im 
Tutorial wurde darauf mit einem Satz eingegangen, was mir aber nichts 
erklärt: However, it is also showing the TAIFG flag has gone HI. This is 
just an artifact of how the ISR works with the MSP430FR6989 general 
purpose timer.
Hat jemand eine Erklärung dafür? So etwas würde mich beim Debuggen 
verwirren.

Mein Code:
1
#include <msp430.h>
2
3
#define RED_LED 0x0001        // P1.0 is the Red LED
4
#define STOP_WATCHDOG 0x5A80  // Stop the watchdog timer
5
#define ACLK 0x0100           // Timer ACLK source
6
#define UP 0x0010             // Timer Up mode
7
#define ENABLE_PINS 0xFFFE    // Required to use inputs and outputs
8
9
main()
10
{
11
  WDTCTL = STOP_WATCHDOG;   // Stop the watchdog timer
12
  PM5CTL0 = ENABLE_PINS;    // Required to use inputs and outputs
13
  P1DIR = RED_LED;          // Set Red LED as an output
14
  TA0CCR0 = 20000;          // Sets value of Timer_0
15
  TA0CTL = ACLK + UP;       // Set ACLK, UP MODE
16
  TA0CCTL0 = CCIE;          // Enable interrupt for Timer_0
17
  _BIS_SR(GIE);             // Activate interrupts previously enabled
18
  while(1);                 // Wait here for interrupt
19
}
20
21
//************************************************************************
22
// Timer0 Interrupt Service Routine
23
//************************************************************************
24
#pragma vector=TIMER0_A0_VECTOR // The ISR must be put into a special
25
                                // place in the microcontroller program
26
                                // memory. That's what this line does.
27
                                // While you do not need this comment,
28
                                // the code line itself must always
29
                                // appear exactly like this in your
30
                                // program.
31
                                // "TIMER0_A0_VECTOR" ist definiert in msp430.h
32
//************************************************************************
33
__interrupt void Timer0_ISR (void)  // This officially names this ISR as
34
                                    // "Timer0_ISR"
35
                                    // Dieser Name kann selbst vergeben werden.
36
//************************************************************************
37
{                                   // Like other functions, everything
38
                                    // happens in curly braces
39
  P1OUT = P1OUT ^ RED_LED;          // Toggle red LED
40
}                                   // When all the code is here done, the
41
                                    // ISR ends and the program jumps back
42
                                    // to wherever it was before
43
44
//************************************************************************

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

Jonas W. schrieb:
> Es bleibt auf HIGH, obwohl in dem
> Tutorial gesagt wurde, dass die ISR den interrupt cleart.

Wobei ja der Pure Interrupt Aufruf das bit nicht löschen darf,
sonst kann ja nicht mehr geprüft werden was den Interrupt ausgelöst hat.
 Das Interrupt Bit steht ja im direkten Zusammenhang mit dem TAIV 
Sprungregister.

Ich habe mir angewöhnt aus Prinzip, nach abklären welchen Interrupt 
ausgelöst wurde, den auch manuell zu löschen.

Da der Interruppt Einsprung mehrere Quellen hat, mache ich immer in der 
Interrupt Rutine ein Sprung über das TAxIV Register

So ist auch sicher gestellt das wirklich der Timer die vorgegebene 
Compare erreicht hat, und nicht ein anderer Interrupt dies ausgelöst 
hat.

: Bearbeitet durch User
von Jonas W. (jwitte)


Lesenswert?

Hallo und danke für die Antwort,

Hier ist nochmal das Zitat aus dem Tutorial:

"In the past, we always had to make sure that we cleared the TAIFG flag 
in the TA0CTL register after the timer elapsed. This is automatically 
included by CCS with the TIMER0_A0_VECTOR ISR."

Also stimmt das ganz einfach nicht?

Dann nochmal eine andere Frage: Verstehe ich das richtig:

1) TAIFG zeigt an, dass für Timer_A ein Interrupt vorliegt.
2) Als nächstes muss ich das TAIV Bit im TA0IV Register auslesen um 
herauszufinden, was für ein Interrupt vorliegt. Diese Überprüfung 
geschieht auch in der ISR.

Und muss ich dann sowohl TAIFG und TAIV clearen sobald der Interrupt 
verarbeitet wurde?

Mit freundlichen Grüßen,
J Witte

von wv (Gast)


Lesenswert?

Hallo Jonas,
das entscheidende beim TimerA ist folgendes:
Two interrupt vectors are associated with the 16-bit Timer_A module:
• TACCR0 interrupt vector for TACCR0 CCIFG
• TAIV interrupt vector for all other CCIFG flags and TAIFG
Da der TA0CCR0-Interrupt exklusiv nur beim Erreichen des TA0CCR0-Wertes 
gesetzt wird, wird dieser auch beim Einsprung in die ISR automatisch 
gelöscht und man braucht da auch nicht nach Quellen unterscheiden, da es 
nur eine Quelle gibt. Dein Code ist richtig.
Da Du TA0CCTL0 = CCIE; gesetzt hast, wäre das zu untersuchende Flag das 
CCIFG in diesem Register. Ob man das Zurücksetzen beim Debuggen sieht, 
weiß ich im Moment nicht, das hängt auch von den Einstellungen des 
Debuggers ab, ob z.B. der Timeroszillator während des Single-steps 
weiterläuft oder auch angehalten wird.
Das TAIFG im Register TA0CTL wird immer gesetzt, wenn irgendein 
Timerinterrupt ausgelöst wird, hat aber keine Auswirkung, wenn nicht 
gleichzeitig auch TA0IE gesetzt wurde, was in Deinem Code nicht der Fall 
ist.

Gruß wv

von Jonas W. (jwitte)


Lesenswert?

Verstehe ich das richtig:

- Wenn ich TA0CCR0 verwende wird CCIFG automatisch gecleart.
- Wenn ich TA0CCR1 bis TA0CCR6 verwende muss ich das jeweilige CCIFG Bit 
selber clearen.
- TAIV gibt an welcher Interrupt vorliegt. Es wird immer gesetzt außer 
bei TA0CCR0.
- TAIV hat eine eigene ISR.
- TAIFG wird immer gesetzt, bei allen Interrupts.
- Wenn ich auch TAIE setzen würde, müsste ich bei jedem Interrupt 
zusätzlich TAIFG clearen.
- Wenn ich TAIE nicht setze, führen zum Beispiel Timer Overflows nicht 
zu einem Interrupt (wie in TAIV beschrieben).

VG Jonas

von wv (Gast)


Lesenswert?

Hallo Jonas,
das ist so richtig.
Es gibt also nur zwei Interruptroutinen:
TIMER0_A0_VECTOR --> nur für CCR0
TIMER0_A1_VECTOR --> für alle anderen Capture/Compare Register und 
Timer-Overflow
Gruß wv

von Patrick L. (Firma: S-C-I DATA GbR) (pali64)


Lesenswert?

TAIV ist das Register dass die Sprungadresse je nach Interrupt enthält.

Ist das Interrupt gelöscht enthält TAIV 0000h.

Und es steht ja dass man es Manuell löschen muss, wenn man nicht die 
Standard Library verwendet:

Jonas W. schrieb:
> "In the past, we always had to make sure that we cleared the TAIFG flag
> in the TA0CTL register after the timer elapsed.
Was bedeutet dass man sicher sein soll dass es Zurückgesetzt ist.
Ansonsten kann bei einem anderem Interrupt nicht mehr festgestellt 
werden, wer den Interrupt ausgelöst hat weil mehr als 1 Bit gesetzt ist.

> This is automatically
> included by CCS with the TIMER0_A0_VECTOR ISR."

Was bedeutet dass wenn mann das CCS TIMER0_A0_VECTOR ISR library 
verwendet dieses das Bit löscht. (Also nicht die CPU direkt, sondern das 
Library enthält ein [BIC.W  #TAIFG,&TAxCTL] befehl).

Dieser wird vom Compiler in die ISR gesetzt und der Debugger sieht das 
löschen erst nach dem dieser Befehl ausgeführt wird.
Deshalb ist es noch gesetzt wenn du den Halt Befehl im Debugger setzt 
oder per Single-stepp ausführst.

Würde das Bit nicht gelöscht, könnte dieser Interrupt nicht richtig 
Identifiziert bzw ausgeführt werden.

: Bearbeitet durch User
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.