MSP430 Timer + Port Interrupt

Gast #1464095
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
Persönliche Seite #1464140
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
Gast #1464224
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
Gast #1464502
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?
Gast #1465095
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
Gast #1465763
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
#1465823
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?
#1465917
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.
#1466030
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
}
#1466213
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.
Gast #1467899
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

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