Forum: Mikrocontroller und Digitale Elektronik MSP430 - Timer Interrupt zu früh


von dk (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!
Bei der Programmierung meines Controllers für die Ansteuerung von 
Thyristoren bin ich auf ein Problem mit meinem Timer gestoßen. Mein 
genutztes System:

-MSP430FG4618
-32kHz Quarz für ACLK
-IAR Embedded Workbench Version 5.10.1
-Programmierung in C

Zur besseren Fehlersuche habe ich mein Programm möglichst weit gekürzt. 
Da ich quasi keine Erfahrung mit C habe und es sich um mein erstes 
Projekt mit einem Mikrocontroller handelt, hoffe ich das nicht zuviele 
grundsätzliche Fehler vorhanden sind.

Was im Programm eigentlich passieren soll:
An Pin 0 von Port 1 ist das Ausgangssignal eines Schmitt-Triggers 
angeschlossen, dieser liefert mir alle 20ms eine steigende Flanke. Der 
durch die Flanke ausgelöste Interrupt testet von welchem Pin der 
Interrupt kommt (später sollen 3 Schmitt-Trigger angeschlossen werden) 
und legt dann in den Variablen thyristorA1 und thyristorA2 ab welche 
Ausgangspins später auf High gesetzt werden sollen. Danach wird TimerA 
im up-mode gestartet. TACCR0 wird auf einen Wert in Abhängigkeit von 
alpha gesetzt. In dem Programm im Anhang ist alpha zwar konstant, im 
ungekürzten Programm wird es aber verändert..
Im Timer Interrupt werden dann die Pins an Port 4 entsprechend 
thyrsitorA1 auf High gesetzt und der Timer wieder gestartet, diesmal mit 
TACCR0 = alphaT[2]; was TACCR0 = 560 entsprechen sollte. Beim zweiten 
Timer Interrupt werden die Pins von Port 4 wieder auf Low gesetzt und 
der Timer mit einem größeren Überlaufwert TACCR0 = alphaT[10]; 
(TACCR0=2778) gestartet. Der dritte Timer Interrupt setzt die Pins 
entsprechend thyristorA2 auf High und startet den Timer mit TACCR0 = 
560. Beim letzten Timer Interrupt werden die Pins wieder auf Low gesetzt 
und der Timer nicht wieder gestartet.
Dieser Teil des Programms funktioniert soweit auch (falls man den Basic 
Timer nicht starten würde). Wenn jetzt zusätzlich noch der Basictimer 
genutzt wird, auch wenn er nur eine Varible hochzählt die mit dem Rest 
nichts zu tun hat, kommt es zu Problemen. Wenn ich mir das Signal der 
Ausgangspins auf dem Oszi anschaue, ist manchmal alles wie es sein soll, 
manchmal werden die Pins aber auch im falschen Moment auf High gesetzt. 
Die beiden Fälle in denen der Timer nur bis TACCR0 = alphaT[10] laufen 
soll sind in Ordnung, aber wenn der Timer Interrupt erst bei dem höheren 
Wert TACCR0 = alphaT[10] kommen sollte, wird direkt die ISR aufgerufen. 
D.h. die Phase zwischen den Zeitabschnitten in denen die Pins auf High 
liegen ist fast nicht mehr vorhanden.

Ich glaube ich habe irgendetwas grundsätzliches bei der Nutzung von 
mehreren Interruptquellen falsch gemacht und wäre froh über jeden Tipp!
Im Moment sind alle Variablen als volatile deklariert, wobei ich 
eigentlich dachte es wäre nicht bei allen nötig...dadurch tritt der 
Fehler aber seltener auf. Wenn ich das Programm Schritt für Schritt 
debugge funktiert es wie es soll. Soweit ich den Assembler Code (habe so 
gut wie garkeine Ahnung von Assembler) nachvollziehen kann, konnte ich 
auch keinen Fehler finden....

Danke schonmal für alle Antworten!
Gruß

von dk (Gast)


Lesenswert?

Hallo nochmal!
Ich konnte den oben beschriebenen Fehler noch weiter einschränken, wenn 
ich in dem Programm im ersten Beitrag in:
[c]
#pragma vector = BASICTIMER_VECTOR
__interrupt void BASICTIMER_ISR (void)
{
 uint16_t bt = btcounter;
 if ( bt == 20 )
  {
    bt = 0;
  }
 btcounter = ++bt;
}
[\c]
die Variable "bt" ebenfalls als volatile deklariere tritt der Fehler 
nicht auf, oder zumindest so selten, dass ich ihn nach mehreren Minuten 
nicht mehr am Oszi beobachten konnte. Leider verstehe ich nicht warum es 
so ist, da der Fehler ja bei TimerA auftritt und nicht beim Basic Timer.
Der Assembler Code den der Compiler ausspuckt unterscheidet sich 
dementsprechend auch nur minimal:

Funktioniert nicht:
1
BASICTIMER_ISR:
2
?cstart_end:
3
 003128    120F               push.w  R15
4
  /*volatile*/ uint16_t bt = btcounter;
5
 00312A    421F 110C          mov.w   &btcounter,R15
6
  if ( bt == 20 )
7
 00312E    903F 0014          cmp.w   #0x14,R15
8
 003132    2001               jne     0x3136
9
    bt = 0;                          
10
 003134    430F               clr.w   R15
11
 btcounter = ++bt;                             
12
 003136    531F               inc.w   R15
13
 003138    4F82 110C          mov.w   R15,&btcounter
14
}
15
 00313C    413F               pop.w   R15
16
 00313E    1300               reti
17
__interrupt void P1_ISR (void)
18
{

Funktioniert:
1
BASICTIMER_ISR:
2
?cstart_end:
3
 003128    120F               push.w  R15
4
 00312A    8321               decd.w  SP
5
  volatile uint16_t bt = btcounter;
6
 00312C    4291 110C 0000     mov.w   &btcounter,0x0(SP)
7
  if ( bt == 20 )
8
 003132    90B1 0014 0000     cmp.w   #0x14,0x0(SP)
9
 003138    2002               jne     0x313E
10
    bt = 0;                          
11
 00313A    4381 0000          clr.w   0x0(SP)
12
 btcounter = ++bt;                             
13
 00313E    412F               mov.w   @SP,R15
14
 003140    531F               inc.w   R15
15
 003142    4F81 0000          mov.w   R15,0x0(SP)
16
 003146    4F82 110C          mov.w   R15,&btcounter
17
}
18
 00314A    5321               incd.w  SP
19
 00314C    413F               pop.w   R15
20
 00314E    1300               reti

Kann mir jemand erklären wieso diese lokale Variable im Interrupt des 
Basictimers meinen TimerA beeinflussen kann?
Gruß

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.