Forum: Mikrocontroller und Digitale Elektronik MSP430 Timer + Port Interrupt


von bumpl (Gast)


Lesenswert?

Hi,

ich habe ein Problem mit den Timern beim MPS430F5438 und den Interrupts.
Folgendes: Ich starte einen Timer, der per Interrupt eine Zählvariable 
setzt.
Zusätzlich soll aber noch auf eine Lo/Hi-Fanke an Pin 1.4 reagiert 
werden.

Code ist hier:
1
void main(void)
2
{
3
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
4
  P1DIR |= 0x01;                            // P1.0 output
5
  TBCTL = TBSSEL_2 + MC_2 + TBCLR + TBIE;   // SMCLK, contmode, clear TBR
6
                                            // enable interrupt
7
  
8
  P1REN |= 0x10;                            // Enable P1.4 internal resistance
9
  P1OUT |= 0x10;                            // Set P1.4 as pull-Up resistance
10
  P1IE |= 0x10;                             // P1.4 interrupt enabled
11
  P1IES |= 0x00;                            // P1.4 Lo/Hi edge
12
  P1IFG &= ~0x10;                           // P1.4 IFG cleared
13
14
  //__bis_SR_register(LPM4_bits + GIE);       // Enter LPM4, enable interrupts
15
  __no_operation();                         // For debugger
16
}
17
18
// Port 1 interrupt service routine
19
#pragma vector=PORT1_VECTOR
20
__interrupt void Port_1(void)
21
{
22
 //mach was
23
}
24
25
26
#pragma vector=TIMERB1_VECTOR
27
__interrupt void TIMERB1_ISR(void)
28
{
29
  count++;
30
}

Das komische ist, dass beides jeweils einzeln funktioniert. Also, wenn 
ich den Timer nicht starte, oder einfach den Interrupt dafür nicht 
aktiviere (also TBIE weglasse), funktioniert der Interrupt auf Pin 1.4 
super.
Schalte ich allerdings den Timer-Interrupt ein, funktioniert dieser auch 
wunderbar, allerdings springt er mir nicht mehr in den Port-Interrupt.

Gitb's da irgendeinen Konflikt mit den Prioritäten? Oder sonst was?

Gruß,

bumpl

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Solange die Interrupts nicht global eingeschaltet sind, wird nicht viel 
passieren.

Sie sind nicht eingeschaltet, weil
  //__bis_SR_register(LPM4_bits + GIE);       // Enter LPM4, enable 
interrupts

auskommentiert ist.

Es würde auch __bis_SR_register(GIE); ausreichen

Außerdem verlässt das Programm Main am Ende. Das darf nie passieren, 
sonst wird Code ausgeführt, der danach kommt, was zu irgendeinem 
beliebigen Verhalten führen kann.

Also sollte am Ende von Main ein for(;;); stehen oder irgend etwas 
anderes, das dafür sorgt, dass main nie verlassen wird.

Grüße,

Peter

von Stefan (Gast)


Lesenswert?

Muss man beim F5xxx nicht auch PxIFGx per Software zurücksetzen (wie 
beim F1xxx/2xxx) bzw. das PxIV Register auslesen um PxIFGx zu löschen?
Sonst springt er ja immer wieder in die Port-ISR!

von Raimund (Gast)


Lesenswert?

Oh...
hab das Aktivieren der Interrupts Testweise mal auskommentiert, aber 
anders hats auch nicht funkioniert...

Main wird glaube ich nicht verlassen, weil ja beide Interrupts einzeln 
funktionieren. Außerdem habe ich das aus 2 Beispielen von TI 
zusammengebastelt, bei denen am Ende auch keine Englosschleißfe läuft.

>Muss man beim F5xxx nicht auch PxIFGx per Software zurücksetzen (wie
>beim F1xxx/2xxx) bzw. das PxIV Register auslesen um PxIFGx zu löschen?
>Sonst springt er ja immer wieder in die Port-ISR!

Das habe ich gemacht (dummerweise hier weggelassen). Wie gesagt: Die 
Interrupts einzeln genommen zeigen gewünschtes Verhalten. Zusammen 
allerdings springt er nie in die __interrupt void Port_1(void) Routine.

Gruß,

bumpl

von Jörg S. (joerg-s)


Lesenswert?

>Zusammen allerdings springt er nie in die __interrupt void Port_1(void)
>Routine.
Und im PxIFG Register steht dann nix?

von Stefan (Gast)


Lesenswert?

>Also sollte am Ende von Main ein for(;;); stehen oder irgend etwas
>anderes, das dafür sorgt, dass main nie verlassen wird.
Das wäre sicher ein "sauberer" Programmierstil ;-)
Das ganze sieht aber nach IAR aus... der macht das automatisch!

>P1DIR |= 0x01;       // P1.0 output
Wäre ein Input nicht sinnvoller?

von Stefan (Gast)


Lesenswert?

>>P1DIR |= 0x01;       // P1.0 output
>Wäre ein Input nicht sinnvoller?
Vergiß es... hab mich verguckt.

von bumpl (Gast)


Lesenswert?

Hi,

im Register P1IFG ist P1IFG4 (für den Port 1.4) immer 0.

In dieser Konfiguration funktioniert der Interrupt auf Port 1.4 
hervorragend:
1
void main(void)
2
{
3
  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
4
  P1DIR |= 0x01;                            // Set P1.0 to output direction
5
  P1REN |= 0x10;                            // Enable P1.4 internal resistance
6
  P1OUT |= 0x10;                            // Set P1.4 as pull-Up resistance
7
  P1IE |= 0x10;                             // P1.4 interrupt enabled
8
  P1IES |= 0x10;                            // P1.4 Hi/Lo edge
9
  P1IFG &= ~0x10;                           // P1.4 IFG cleared
10
11
//  TBCTL = TBSSEL_2 + MC_2 + TBCLR + TBIE;   // SMCLK, contmode, clear TBR
12
13
  __bis_SR_register(LPM4_bits + GIE);       // Enter LPM4 w/interrupt
14
  __no_operation();                         // For debugger
15
}
16
17
// Port 1 interrupt service routine
18
#pragma vector=PORT1_VECTOR
19
__interrupt void Port_1(void)
20
{
21
  P1OUT ^= 0x01;                            // P1.0 = toggle
22
  P1IFG &= ~0x010;                          // P1.4 IFG cleared
23
}

Kommentier ich TBCTL wieder ein (sagt man das so? :)), dann geht der 
Interrupt wieder nicht. Starte ich den Timer mit
1
TBCTL = TBSSEL_2 + MC_2 + TBCLR;
geht auch der Interrupt auf Port 1.4 wie vorher ohne Probleme.

Es liegt also wohl an dem Aktivieren des Interrupts für den Timer (bei 
Timer1/A übrigens das gleiche Problem).

Gruß,

bumpl

von Stefan (Gast)


Lesenswert?

Kontaktier mal den TI support.
Wäre ja nicht das erste Mal, dass die Errata nachgebessert werden muss.
Hab die Jungs auch schon ein paar mal in Erklärungsnot gebracht ;-)

von Raimund (Gast)


Lesenswert?

Hi,

tut mir leid, dass ich da nicht früher drauf gekommen bin und das Thema 
hier aufgebracht habe.
Die Lösung ist ziemlich naheliegend. Der Timer läuft mit einem Quarz auf 
32768 Hz. Die Priorität des Timers ist die höchste (15). Der Port 
Interrupt wird einfach nie ausgeführt, weil immer der Timer-Interrupt 
früher dran ist. Ich habe den Timer-Interrupt auf ca. 6,67 Hz gesetzt 
(mehr brauch ich) und jetzt geht auch der Port-Interrupt.

Gibt es denn eine Möglichkeit (vielleicht auch ASM), die Prioritäten der 
Interrupts zu ändern?

Gruß,

bumpl

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Nein, die Interruptprioritäten sind fest vorgegeben.

von S. Z. (szimmi)


Lesenswert?

-Raimund schrieb:
> Hi,
>
> tut mir leid, dass ich da nicht früher drauf gekommen bin und das Thema
> hier aufgebracht habe.
> Die Lösung ist ziemlich naheliegend. Der Timer läuft mit einem Quarz auf
> 32768 Hz. Die Priorität des Timers ist die höchste (15). Der Port
> Interrupt wird einfach nie ausgeführt, weil immer der Timer-Interrupt
> früher dran ist. Ich habe den Timer-Interrupt auf ca. 6,67 Hz gesetzt
> (mehr brauch ich) und jetzt geht auch der Port-Interrupt.
>
> Gibt es denn eine Möglichkeit (vielleicht auch ASM), die Prioritäten der
> Interrupts zu ändern?
>
> Gruß,
>
> bumpl

Irgendetwas schleift hier trotzdem noch. In Deinem Ursprungsprogramm 
wird der Timer vom SMCLK, und dieser vom DCO (ca. 1MHz) getaktet. somit 
bekommst Du aller 65536 * 1us = 65,536 ms einen Timer-Interrupt. Wenn 
der P1-Interrupt nun deswegen nicht drankommt, weil der Timer ständig 
läuft, ist mir das schleierhaft, da die Timer-ISR dann schlappe 65ms 
etwas zu tun hätte...
Das Problem hat nichts mit Prioritäten zu tun. Kannst Du nochmal Dein 
vollstaendiges Programm posten, welches nun problemlos läuft?

von Jörg S. (joerg-s)


Lesenswert?

>Irgendetwas schleift hier trotzdem noch. In Deinem Ursprungsprogramm
>wird der Timer vom SMCLK, und dieser vom DCO (ca. 1MHz) getaktet. somit
>bekommst Du aller 65536 * 1us = 65,536 ms einen Timer-Interrupt. Wenn
>der P1-Interrupt nun deswegen nicht drankommt, weil der Timer ständig
>läuft, ist mir das schleierhaft, da die Timer-ISR dann schlappe 65ms
>etwas zu tun hätte...
Richtig, ausserdem müsste das IFG Bit vom Pin ja trotzdem gesetzt 
werden.

von Raimund W. (bumpl)


Lesenswert?

Hi,

macht Sinn... Hier ist nun der Quellcode, der klappt:
1
#include "msp430x54x.h"
2
3
const F_A = 4915;
4
5
unsigned int count = 0;
6
7
void main(void)
8
{
9
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
10
  P1DIR |= 0x01;                            // P1.0 output
11
  
12
  TA0CCTL0 = CCIE;                          // CCR0 interrupt enabled
13
  TA0CCR0 = F_A;
14
  TA0CTL = TASSEL_1 + MC_1 + TACLR;         // ACLK, upmode
15
  
16
  P1REN |= 0x10;                            // Enable P1.4 internal resistance
17
  P1OUT |= 0x10;                            // Set P1.4 as pull-Up resistance
18
  P1IE |= 0x10;                             // P1.4 interrupt enabled
19
  P1IES |= 0x00;                            // P1.4 Lo/Hi edge
20
  P1IFG &= ~0x10;                           // P1.4 IFG cleared
21
22
  __bis_SR_register(LPM3_bits + GIE);       // Enter LPM3, enable interrupts
23
  __no_operation();                         // For debugger
24
}
25
26
// Port 1 interrupt service routine
27
#pragma vector=PORT1_VECTOR
28
__interrupt void Port_1(void)
29
{
30
 //mach was
31
32
  P1IFG &= ~0x010;                          // P1.4 IFG cleared
33
}
34
35
36
#pragma vector=TIMER0_A0_VECTOR
37
__interrupt void TIMER_A_ISR(void)
38
{
39
  count++;
40
  P1OUT ^= 0x01;
41
  TA1CCR0 += F_A;
42
  
43
}

von S. Z. (szimmi)


Lesenswert?

Hiho,
also nochmal zu Deinem Urspungsprogramm.
Du sagtest, es hat entweder der eine oder der andere Interrupt 
zugeschlagen.
Den PORT1 Interrupt sehe ich ja noch ein, der andere (Timer) Interrupt 
kann gar nicht gekommen sein, da im LPM4 der SMCLK nicht läuft, somit 
auch der Timer steht.
Alles sehr seltsam. Dein letztes Programm sieht allerdings ganz gut aus, 
ACLK und LPM3, das passt.

von bumpl (Gast)


Lesenswert?

Hi,

hab's grad eben mit dem ersten Code noch mal versucht. Wenn der 
Timer-Interrupt aktiviert ist (... + TBIE), funktionert NUR der 
Timer-Interrupt. Entferne ich den Timer-Interrupt, dann funktioniert der 
Port-Interrupt (aber logischerweise nicht mehr der Timer-Interrupt).

Gruß,

bumpl

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.