Forum: Mikrocontroller und Digitale Elektronik MSP430 USART RX interrupt wird nicht aufgerufen.


von Chris (Gast)


Lesenswert?

hallo!

ich initialisiere meine serielle schnittstelle so:
1
void init_uart()
2
{
3
  P3SEL |= 0x30;                            // P3.4,5 = USART0 TXD/RXD
4
  
5
  BCSCTL2 |= DCOR;                          // Rosc
6
  _BIS_SR(OSCOFF);                          // XTAL not used
7
  ME2 |= UTXE0 + URXE0;                     // Enabled USART0 TXD/RXD
8
  UCTL0 |= CHAR;                            // 8-bit character
9
  UTCTL0 |= SSEL1;                          // UCLK = SMCLK
10
  UBR00 = 0x68;                             // 0x68 2MHz 19200
11
  UBR10 = 0x00;                             //
12
  UMCTL0 = 0x00;                            // 0x00 no modulation
13
  UCTL0 &= ~SWRST;                          // Initialize USART state machine
14
  IE2 |= URXIE0;                            // Enable USART0 RX interrupt 
15
}
eigentlich fast original-code von einem ti beispiel.
irgendwie wir aber die interrupt service routine nicht aufgerufen.
zeichen können jedoch gesendet und empfangen werden.

wenn ich den rxbuf0 im mein loop polle wird das zeichen, weches vom pc 
gesendet wird auch auf dem lcd des controllers dargestellt.

folgende interruptroutine wird benutzt, abern icht erreicht
1
#pragma vector=UART0RX_VECTOR
2
__interrupt void usart0_rx (void)
3
{
4
 position(4,1);
5
 printtext("intr");
6
  
7
  while (!(IFG2 & UTXIFG0));                // USART0 TX buffer ready?
8
  TXBUF0 = RXBUF0;                          // RXBUF0 to TXBUF0
9
}

hab ich irgendetwas nicht beachtet?

vielen dank für eure hilfe

von Michael (Gast)


Lesenswert?

Hi,

hast du evtl. das globale Interrupt-enable Flag nicht gesetzt?

von Chris (Gast)


Lesenswert?

das wars wohl...

jetzt habe ich nur ein anderes problem...

der controller startet immer neu, obwohl der wdt ausgeschaltet ist...

jetzt wird der meinloop nicht mehr erreinch :(
1
void main(void)
2
{
3
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
4
  
5
  _DINT(); // disable all interrupts
6
  
7
  init_uart();
8
  
9
  P1DIR = 0xFF;    // P1.x Output für LCD
10
  lcd_init();
11
  
12
  position(1,1);
13
  printtext("Temperatur Test");
14
 _EINT(); // enable all interrupts
15
16
while(1);

von CHRiS (Gast)


Lesenswert?

main-loop natürlich... sry, war schon spät

von Falk B. (falk)


Lesenswert?

@ Chris (Gast)
1
#pragma vector=UART0RX_VECTOR
2
__interrupt void usart0_rx (void)
3
{
4
 position(4,1);
5
 printtext("intr");
6
  
7
  while (!(IFG2 & UTXIFG0));                // USART0 TX buffer ready?
8
  TXBUF0 = RXBUF0;                          // RXBUF0 to TXBUF0
9
}

AUA! So eine Warteschleife in einem Interrupt ist schlicht sträflich!
Ebenso die printtext() Funktion. Solche langsames Zeug hat in Interrupts 
nciht zu suchen.

>der controller startet immer neu, obwohl der wdt ausgeschaltet ist...

Wahscheinlich knallt es mit deinen Interrupts. Hast du einen Handler für 
den TX-Interrupt, wenn du ihn freigegeben hast?

>jetzt wird der meinloop nicht mehr erreinch :(

Welcher Mainloop? Du hast eine einmalige Sequenz und danach eine 
Endlosschleife ohne Inhalt.

MFG
Falk

von CHRiS (Gast)


Lesenswert?

>> AUA! So eine Warteschleife in einem Interrupt ist schlicht sträflich!
>> Ebenso die printtext() Funktion. Solche langsames Zeug hat in Interrupts
>> nciht zu suchen.

das ist aus einem TI Beispiel und nur zum ausprobieren - auch die 
printtext war nur zum testen

>> Welcher Mainloop? Du hast eine einmalige Sequenz und danach eine
>> Endlosschleife ohne Inhalt.

den Inhalt hab ich rausgenommen, weil ich den thread nicht so 
vollballern wollte

>> Wahscheinlich knallt es mit deinen Interrupts. Hast du einen Handler für
>> den TX-Interrupt, wenn du ihn freigegeben hast?

weiss nicht genau was du meinst?!?!

Vielen Dank CHRiS

von Michael (Gast)


Lesenswert?

Die Endlosloop ist schon richtig in diesem Fall. Dort wird überprüft, ob 
das Byte wirklich schon gesendet worden ist.

In den Code Examples geschieht dies aber nach jedem gesendeten Byte.

von CHRiS (Gast)


Lesenswert?

>> In den Code Examples geschieht dies aber nach jedem gesendeten Byte.

Hier doch auch oder?

von Falk B. (falk)


Lesenswert?

@ CHRiS (Gast)

>das ist aus einem TI Beispiel und nur zum ausprobieren - auch die
>printtext war nur zum testen

Das kann aber auch beim Testen daneben gehen.

>den Inhalt hab ich rausgenommen, weil ich den thread nicht so
>vollballern wollte

Mit solchen halben Fragmenten kann niemand was sinnvolles anfangen. 
Poste VOLLSTÄNDIGEN Quelltext als Anhang.

>> Wahscheinlich knallt es mit deinen Interrupts. Hast du einen Handler für
>> den TX-Interrupt, wenn du ihn freigegeben hast?

>weiss nicht genau was du meinst?!?!

???
Wenn ein Interrupt freigegben wird, zu dem kein Interrupthandler 
existiert, dann gibts beim Auftreten eben diese Interrupts eien Reset.

MFG
Falk

von CHRiS (Gast)


Lesenswert?

wie sieht so ein Interrupthandler aus?
hab ich irgendwie leider noch nichts von gehört oder vielleicht unter 
einem anderen Begriff kennengelernt.

vielen Dank schonmal für deine Hilfe

von Falk B. (falk)


Lesenswert?

@ CHRiS (Gast)

>wie sieht so ein Interrupthandler aus?
>hab ich irgendwie leider noch nichts von gehört oder vielleicht unter
>einem anderen Begriff kennengelernt.

Interrupthandler == Interruptroutine

;-)

MFG
Falk

von CHRiS (Gast)


Lesenswert?

1
#pragma vector=UART0RX_VECTOR
2
__interrupt void usart0_rx (void)
3
{
4
 position(4,1);
5
 printtext("intr");
6
  
7
  while (!(IFG2 & UTXIFG0));                // USART0 TX buffer ready?
8
  TXBUF0 = RXBUF0;                          // RXBUF0 to TXBUF0
9
}

DING DING DING - 2 Runde!!! :D
hehe... stimmt ich hab ja nur RX... kein TX :D

das könnte es natürlich sein - werde ich ausprobieren sobald ich zu 
Hause bin!

Besten Dank nochmal!!!!!!

von Chris (Gast)


Lesenswert?

1
#pragma vector=UART0RX_VECTOR
2
__interrupt void usart0_rx (void)
3
{  
4
  while (!(IFG2 & UTXIFG0));                // USART0 TX buffer ready?
5
  TXBUF0 = RXBUF0;                         // RXBUF0 to TXBUF0
6
}
7
8
#pragma vector=UART0TX_VECTOR
9
__interrupt void usart0_tx (void)
10
{
11
 asm("nop"); // ur zum testen
12
}

jetzt habe ich beide interrupthandler eingefügt - ok soweit! cpu 
resettet nicht mehr ständig, trotzdem werden die zeichen nicht empfangen 
/ gesendet!
Im prinzip müsste das programm dochein echo vom empfangenen Zeichen 
senden??!!??!?!?

Gruß CHRiS

von Falk B. (falk)


Lesenswert?

@ Chris (Gast)

>Im prinzip müsste das programm dochein echo vom empfangenen Zeichen
>senden??!!??!?!?

Neee, du vermischst Polling mit Interrupts. Das geht daneben! Wenn du 
Pech hast hängt die CPU ewig im TX-Interrupt fest (kann ich jetzt nicht 
genau sagen, kenn den MSP nicht so detailiert). Toggle mal ne LED im 
TX-Interrupt.

MFG
Falk

von CHRiS (Gast)


Lesenswert?

ihr werdet es nicht glauben....

ich schalte die schaltung heute morgen an.... OHNE ÄNDERUNGEN AM 
PROGRAMM
und die MCU resettet sich wieder ständig :(

von Falk B. (falk)


Lesenswert?

@ CHRiS (Gast)

>ich schalte die schaltung heute morgen an.... OHNE ÄNDERUNGEN AM
>PROGRAMM
>und die MCU resettet sich wieder ständig :(

Wer weiss was du gestern WIRKLICh in den MSP geladen hast. Oder 
vielleicht hast den MSP gestern gar nicht gestartet.
Machs doch einfach mal ordentlich.

1.) Echo mit Polling.
2.) Echo nur mit RX Inerrupt (wenn gleich das nicht so schön ist)
3.) Echo mit RX+TX Interrupt, wobei die Übergabe der Daten über eine 
Variable + Flag erfolgen muss.

MFG
Falk

von Christian R. (supachris)


Lesenswert?

Ich denke, die Baudrate stimmt einfach nicht.
In den geposteten Schnipseln hier steht nur, dass du den externen 
Widerstand an den DCO legst. Ist denn da überhaupt einer dran? Und was 
verleitet dich zu der Annahme, dass der DCO dann mit exakt 2MHz läuft? 
OHne jegliche weitere Initialisierung?
Und was hat diese Einstellung überhaupt in der UART-Init zu suchen?

Dann weiter: Wieo hältst du dich nicht an die Code-Beispiele und die 
User Guides? Bei der Init. der UART MUSS der Software-Reset-Bit die 
ganze Zeit gesetzt sein. Das Rücksetzen am Ende ist richtig, aber VOR 
der Init musst du es setzen.

Weiter: In der while(1) solltest du eine Zeile aufnehmen, in der du das 
globale Interrupt-Bit setzt, damit es nach Beenden der ISR auf jeden 
Fall an ist.

Den TX-Int brauchst du momentan noch nicht, das ist nur, wenn du 
energiesparend große Datenmengen verschicken willst. Da kannst du, 
während das Senden luft, die CPU schlafen legen.

von CHRiS (Gast)


Lesenswert?

das hab ich teilweise zum testen aus dem TI beispiel genommen
1
void main(void)
2
{
3
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
4
  P3SEL |= 0x30;                            // P3.4,5 = USART0 TXD/RXD
5
  BCSCTL2 |= DCOR;                          // Rosc
6
  _BIS_SR(OSCOFF);                          // XTAL not used
7
  ME2 |= UTXE0 + URXE0;                     // Enabled USART0 TXD/RXD
8
  UCTL0 |= CHAR;                            // 8-bit character
9
  UTCTL0 |= SSEL1;                          // UCLK = SMCLK
10
  UBR00 = 0x68;                             // 2MHz 19200
11
  UBR10 = 0x00;                             //
12
  UMCTL0 = 0x00;                            // no modulation
13
  UCTL0 &= ~SWRST;                          // Initialize USART state machine
14
  IE2 |= URXIE0;                            // Enable USART0 RX interrupt
15
16
  _BIS_SR(LPM0_bits + GIE);                 // Enter LPM0 w/ interrupt
17
}
18
19
#pragma vector=UART0RX_VECTOR
20
__interrupt void usart0_rx (void)
21
{
22
  while (!(IFG2 & UTXIFG0));                // USART0 TX buffer ready?
23
  TXBUF0 = RXBUF0;                          // RXBUF0 to TXBUF0
24
}

Der Widerstand ist natürlich vorhanden.

von Falk B. (falk)


Lesenswert?

@ CHRiS (Gast)

>Der Widerstand ist natürlich vorhanden.

Mensch Chris, du hast es immer noch nicht kapiert. Gehs erstmal LANGSAM 
an. Und für den UART brauchst du einen Quarz, der DCO vom MSP geht 
nicht!

Wie beim AVR.

http://www.mikrocontroller.net/articles/AVR-Tutorial:_UART#Senden

Und mach es erst mal per Polling! Empfangen UND Senden!

MFG
Falk

von CHRiS (Gast)


Lesenswert?

>> Mensch Chris, du hast es immer noch nicht kapiert.

Stimmt :(

ICh hab so ein Header Board hie aus dem Shop, reicht es wenn ich den 
32kHz  Quartz davon verwende? oder braucht man unbedingt einen externen?

von Christian R. (supachris)


Lesenswert?

Alsooo....wenn du den DCO nutzen willst (höhere Bitraten als 9600 gehn 
nur mit HF-Quarz oder DCO), dann solltest du diesen unbedingt nach dem 
32khz Quarz einstellen. Dazu gibts folgenden Code:
1
//------------------------------------------------------------------------------
2
void Set_DCO (void)                         // Set DCO to selected frequency
3
//------------------------------------------------------------------------------
4
{
5
6
  unsigned int Compare, Oldcapture = 0;
7
8
  BCSCTL1 |= DIVA_3;                        // ACLK= LFXT1CLK/8
9
  CCTL2 = CM_1 + CCIS_1 + CAP;              // CAP, ACLK
10
  TACTL = TASSEL_2 + MC_2 + TACLR;          // SMCLK, cont-mode, clear
11
12
  while (1)
13
  {
14
    while (!(CCIFG & CCTL2));               // Wait until capture occured
15
    CCTL2 &= ~CCIFG;                        // Capture occured, clear flag
16
    Compare = CCR2;                         // Get current captured SMCLK
17
    Compare = Compare - Oldcapture;         // SMCLK difference
18
    Oldcapture = CCR2;                      // Save current captured SMCLK
19
20
    if (DELTA == Compare) break;            // If equal, leave "while(1)"
21
    else if (DELTA < Compare)               // DCO is too fast, slow it down
22
    {
23
      DCOCTL--;
24
      if (DCOCTL == 0xFF)
25
      {
26
        if (!(BCSCTL1 == (XT2OFF + DIVA_3)))
27
        BCSCTL1--;                          // Did DCO roll under?, Sel lower RSEL
28
      }
29
    }
30
    else
31
    {
32
      DCOCTL++;
33
      if (DCOCTL == 0x00)
34
        {
35
          if (!(BCSCTL1 == (XT2OFF + DIVA_3 + 0x07)))
36
          BCSCTL1++;                        // Did DCO roll over? Sel higher RSEL
37
        }
38
    }
39
  }
40
  CCTL2 = 0;                                // Stop CCR2
41
  TACTL = 0;                                // Stop Timer_A
42
}

DELTA gibts den Vervielfachungsfaktor an, z.b:
1
#define DELTA 256                           // target DCO = DELTA*(4096) = 1048576

Damit kannst du dir was aussuchen, der DCO wird auf diese Frequenz 
möglichst passend justiert. Damit kann man den UART verwenden. 
Allerdings sollte man das ab und zu wieder aufrufen, der DCO ist recht 
temperaturinstabil. Spannungsschwaknungen mag er auch überhaupt nicht.

Da musst du dann natürlich den passenden Teilerfaktor plus evtl. 
Modulation für deine UART ausrechnen.

von Falk B. (falk)


Lesenswert?

@ CHRiS (Gast)

>ICh hab so ein Header Board hie aus dem Shop, reicht es wenn ich den
>32kHz  Quartz davon verwende?

Ja, aber dann musst du den UART so konfigurieren, dass er mit ACLK 
arbeitet. Und maximale Baudrate sind dann 9600. Ist in den Beispielen 
von TI dabei.

> oder braucht man unbedingt einen externen?

Der ist auch extern und nciht intern (im Chip).

MFG
Falk

von Christian R. (supachris)


Angehängte Dateien:

Lesenswert?

Übrigens gibts doch da direkt ein Beispiel bei TI, siehe Anhang.

von CHRiS (Gast)


Angehängte Dateien:

Lesenswert?

hallo!

ich habe jetzt nach und nach mal alle beispielsourceoes ausprobiert.
leider funktionieren nur die wo kein externer quartz benötigt wird. 
also nur die mit dem 100 kOhm Widerstand.

Zur Zeit benutze ich die gleichen Einstellungen wie im angehängten 
Sourcecode.

Hat einer eine Idee warum die anderen Sources nicht laufen?

von Christian R. (supachris)


Lesenswert?

Vielleicht schwingt der Quarz nicht? Kaputt? Falsche Last-Kapazität?
LAss dir doch mal den ACLK auf dem entsprechenden PortPin ausgeben und 
schau ihn dir an.

von CHRiS (Gast)


Lesenswert?

-- kleines Zwischenergebnis --

Das Senden per polling funktioniert wunderbar 9600 Baud (mit Source von 
17:15) - kann ich daraus schliessen, dass die Schnittstelle richtig 
funktioniert?

von CHRiS (Gast)


Angehängte Dateien:

Lesenswert?

wieder das alte problem :(
senden klappt wunderbar...
sobald ich das globale interrupt flag setze bleibts die cpu stehen

- Uart ist so initialisiert, dass nur der RX interrupt freigegeben ist
- senden per polling funktioniert wunderbar

kann einer nochmal einen blick über den code werfen?

und bitte nicht töten wenn ein paar Sachen noch unschön programmiert 
sind... aufräumen wollte ich wenn alles funktioniert

von Falk B. (falk)


Lesenswert?

@ CHRiS (Gast)

>wieder das alte problem :(
>senden klappt wunderbar...
>sobald ich das globale interrupt flag setze bleibts die cpu stehen

Mensch Chris, du bist wirklich ziemlich lernresistent. Warum glaubst du 
immer alles anders machen zu müssen als die Beispiele? Was soll der 
Quark?
1
#pragma vector=UART0RX_VECTOR
2
__interrupt void usart0_rx (void)
3
{
4
  _EINT(); 
5
  _NOP();
6
}

Das ist würdig, in grosse Buch "How to shoot yourself in the foot" 
plaziert zu werden. Lies dir mal in Datenblatt vom MSP durch, wie der 
UART RX Interrupt funktioniert? Wie wird er ausgelöst? Wie wir er 
gelöscht? Und dann schau deinen Code an und weine.

Ich sags zum letzten Mal.

MACH ES ERSTNMAL NUR MIT POLLING (Senden und Empfangen)!

>- senden per polling funktioniert wunderbar

>und bitte nicht töten wenn ein paar Sachen noch unschön programmiert
>sind... aufräumen wollte ich wenn alles funktioniert

FALSCH!!!!
Wie sagt ein Kollege so schön. "Wir haben keine Zeit es richtig zu 
machen, aber viel Zeit es dreimal zu machen." :-(

MfG
Falk

von CHRiS (Gast)


Lesenswert?

>> Mensch Chris, du bist wirklich ziemlich lernresistent. Warum glaubst du
>> immer alles anders machen zu müssen als die Beispiele? Was soll der
>> Quark?

ja die Zeilen darunter sind wirklich richtiger Müll.... liegt evtl. 
daran, dass ich seit heute Morgen 9 Uhr da dran sitze :(

Ich gelobe Besserung! Jetzt erstmal nur Polling!

von CHRiS (Gast)


Lesenswert?

-> Eine Frage noch :)

ich habe jetzt alles was mit der UART zu tun hat auskommentiert und das 
globale Interrupt Flag gesetzt mit _EINT().
Trotztdem bleibt das Programm einfach hängen.... vor der while 
schleife...

von CHRiS (Gast)


Lesenswert?

hab den Fehler gefunden!!

hab bei der Initialisierung des ADC das Interrupt Enable gesetzt obwohl 
ich es nicht brauche ... :D

Schluss für heute... Samstag gehts weiter.

Trotzdem Danke für EURE Hilfe und Geduld mit mir!!!

von szimmi (Gast)


Lesenswert?

Der Stoff aus dem schlechte Soaps gemacht werden :-)

von Christian R. (supachris)


Lesenswert?

Zumal man sowas mit dem Debugger doch rausbekommt. Die Adresse steht 
dann auf dem Interrupt-Vektor, der ja nicht belegt ist, dann einfach mal 
ins Datenblatt gucken und man wüsse, wer den Int ausgelöst hat.
Und in der ISR den Int wieder freigeben...naja, verschachtelte Ints, 
aber da muss man genau wissen, was man macht...

von CHRiS (Gast)


Lesenswert?

>> naja, verschachtelte Ints, aber da muss man genau wissen, was man macht...

jap - und da ich Anfänger in dem Bereich bin hab ich dadurch viel 
gelernt!

von Falk B. (falk)


Lesenswert?

@ CHRiS (Gast)

>jap - und da ich Anfänger in dem Bereich bin hab ich dadurch viel
>gelernt!

Was denn? Wie man es NICHT macht?

MFG
Falk

von CHRiS (Gast)


Lesenswert?

>>Was denn? Wie man es NICHT macht?

ja, das z.B.

von Christian R. (supachris)


Lesenswert?

Kein Wunder übrigens, dass die Beispiele mit Quarz nicht funktionieren. 
Gleich als 2. Befehl im Init schaltest du den Quarz ja aus.

von CHRiS (Gast)


Lesenswert?

ne ne...
da habe ich zum ausprobieren die original TI Beispiele genommen ohne 
meinen Kram drum herum!

von Falk B. (falk)


Lesenswert?

@ CHRiS (Gast)

>da habe ich zum ausprobieren die original TI Beispiele genommen ohne
>meinen Kram drum herum!

Dan hast du wohl die falschen genommen.

MFG
Falk

von Christian R. (supachris)


Lesenswert?

Oder der Quarz ist nicht richtig angeschlossen, kalte Lötstelle oder 
sowas. Ist ja schließlich billigst-Zeugs aus Bulgarien

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.