Forum: Mikrocontroller und Digitale Elektronik LPC 2105 - UART ISR wird nur einmal ausgeführt


von Daniel Schopf (Gast)


Angehängte Dateien:

Lesenswert?

Hallo.

Ich hab mir schon etliche Tutorials und Forenbeiträge zu Gemüte geführt 
aber bis jetzt noch keine Lösung gefunden.

Folgendes Problem:
Ich möchte auf meiner UART1 am LPC2105 ein einfaches Zeichen empfangen. 
Der Aufruf der ISR funktioniert beim ersten Mal ohne Probleme (als Test 
hab ich mir das Zeichen zurückschicken lassen), als Endsignal der ISR 
lasse ich eine LED aufleuchten (da ich keinen Hardwaredebugger zur 
Verfügung habe, kann ich nur mit LEDs "debuggen").

Die Serviceroutine wird bis zum Ende ausgeführt, woraufhin der 
Controller ja zurück in meine while-Schleife in main.c springen sollte.
Aber genau hier hakts.

Ich starte mein Lauflicht und sobald ich ein Zeichen von meinem PC aus 
sende hängt der Controller (die ISR wird aber bis zum Ende ausgeführt).

Habt ihr Ideen? Ich bin schon am verzweifeln.

Fast vergessen IDE & Tools: µVision 4.10 von Keil.

Lg Daniel
1
#include "uart.h"
2
3
unsigned int uartchar;
4
5
void wait (void)  
6
{int d;  for (d = 0; d < 1000000; d++)__nop();}
7
8
void UART_Rx_ISR(void)
9
{   
10
  unsigned int uartlsr;
11
  unsigned int uartiir;
12
  unsigned int i;
13
14
  while(((uartiir = U1IIR) & UARTIIR_NOINT) == 0) //Loop until no interrupt is pending
15
  {
16
    do{
17
      uartchar = U1RBR;
18
    }while(U1LSR & UARTLSR_RDR); //Loop as long as RBR contains valid data
19
  }
20
21
  IOCLR = 0x02440000;
22
  IOSET = 0x02000000;
23
  wait();
24
  IOCLR = 0x02440000;
25
26
  VICVectAddr = 0x00000000;
27
}
28
29
void initUART1()
30
{
31
  //PINSEL0 = 0x00000005; //for Tx and Rx - UART0
32
  PINSEL0 = 0x00050000; //for Tx and Rx - UART1
33
  U1IIR;  U1RBR;  U1LSR; //Reset them
34
  
35
  U1FCR = UARTFCR_RST_TX | UARTFCR_RST_RX | UARTFCR_EN | UARTFCR_TRIGGER4;
36
  U1LCR = 0x83; //8bit char length, 1 stop bit, no parity, DLAB = 1
37
38
  //for 38400Bd, divisor = 14765000/(38400*16) ~ 24
39
  U1DLL = 0x30;  U1DLM = 0x00;
40
  U1LCR &= 0x7F; //set DLAB to 0 
41
42
   //Sets the priority for IRQ interrupts
43
  VICVectCntl0 = 0x27; //Set priority for UART1 interrupt
44
  VICVectAddr0 = (unsigned long)UART_Rx_ISR; //Holds address of UART1's ISR
45
46
  //Set interrupts
47
  VICIntSelect = 0x00000000; //Set UARTs as member of IRQ interrupts
48
  VICIntEnable = 0x00000080; //Enable UART1 interrupts
49
  U1IER = UARTIER_RDA; //enable RDA interrupt  
50
}

von C-Anfänger (Gast)


Lesenswert?

Daniel Schopf schrieb:
> while(((uartiir = U1IIR) & UARTIIR_NOINT) == 0) //Loop until no
> interrupt is pending

Was passiert denn hier? Es wird ein Zuweisung gemacht. Welchen Wert hat 
denn der Ausdruck "uartiir = U1IIR"? Dieser Wert wird dann verUNDet und 
mit 0 verglichen.

von (prx) A. K. (prx)


Lesenswert?

Die ISR muss dem Compiler als Interrupt-Handler beigebracht werden.

von Daniel Schopf (Gast)


Lesenswert?

C-Anfänger schrieb:
> Daniel Schopf schrieb:
>> while(((uartiir = U1IIR) & UARTIIR_NOINT) == 0) //Loop until no
>> interrupt is pending
>
> Was passiert denn hier? Es wird ein Zuweisung gemacht. Welchen Wert hat
> denn der Ausdruck "uartiir = U1IIR"? Dieser Wert wird dann verUNDet und
> mit 0 verglichen.

Hi. uartiir ist meine Variable die U1IIR ausliest und nach generell nach 
einem Interrupt schaut.
Ist die Bedingung 1 (in dem Fall UARTIIR_NOINT 1), dann steht kein 
Interrupt mehr an.

von Daniel Schopf (Gast)


Lesenswert?

A. K. schrieb:
> Die ISR muss dem Compiler als Interrupt-Handler beigebracht werden.

Sorry ich bin Student.
Wie bring ich das meinem Compiler bei? Ich dachte durch Deklaration im 
VIC und zuweisen der Channels (VICVectAddr) weiß er wo die ISR liegt.

Schließlich wird die ISR ja genau EINMAL ausgeführt und nicht 
"quittiert" (nehm ich halt mal so an). Der Prozessor weiß also wo sie 
ist. Er vergisst irgendwie nur, wo er aufgehört hat zu arbeiten.

lg Daniel

von (prx) A. K. (prx)


Lesenswert?

Daniel Schopf schrieb:

> Wie bring ich das meinem Compiler bei? Ich dachte durch Deklaration im
> VIC und zuweisen der Channels (VICVectAddr) weiß er wo die ISR liegt.

Die Position kennt die Maschine dadurch, aber der Compiler weiss nicht 
dass es ein Interrupt-Handler ist. Wie wär's, wenn du mal ins Handbuch 
vom Compiler schaust, da steht da garantiert drin wie man dem das 
mitteilt. Keil ist nicht meine Baustelle, musst schon selber suchen.

> Schließlich wird die ISR ja genau EINMAL ausgeführt

Klar doch, den Weg rein in den Handler findet er, aber beim Weg zurück 
gibt es unweigerlich Müll. Neben ein paar kaputten Registern und einer 
leicht falschen Rückkehradresse werden so die Interrupts auch nicht 
wieder freigegeben (deshalb das "einmal").

von Michael G. (let)


Lesenswert?

Daniel Schopf schrieb:
> Schließlich wird die ISR ja genau EINMAL ausgeführt und nicht
> "quittiert" (nehm ich halt mal so an). Der Prozessor weiß also wo sie
> ist. Er vergisst irgendwie nur, wo er aufgehört hat zu arbeiten.

Such mal nach dem "Insider Guide" (für LPC2000) von "Hitex". Das ist
ein PDF Dokument in dem das kurz erläutert wird.

von Daniel Schopf (Gast)


Lesenswert?

Danke für eure Tipps.
Ich werd dann mal dort nachlesen. Bis jetzt hatte ich nur das Datenblatt 
und das User Manual.

Vielleicht finde ich es ja dort.

lg Daniel

von Daniel Schopf (Gast)


Lesenswert?

Ok, ich könnte grad heulen.
Seit einer Woche spiel ich mich schon damit herum, das Insider Manual 
(mit den Beispielen) hat in einer Stunde das Problem gelöst.

Die Lösung für die, die vielleicht mal dasselbe Problem haben:
Ich verwende einen vectored IRQ

Um die ISR explizit zu kennzeichnen benötigt ihr den folgenden 
Funktionsrumpf:
1
void ISR(void) __irq

GANZ WICHTIG ist in diesem Fall: "__irq"

Jetzt funktioniert es.

Danke für eure Tipps.

Lg Daniel

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.