LPC 2105 - UART ISR wird nur einmal ausgeführt

Gast #1933180
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
}
Angehängte Dateien:
Gast #1933776
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.
Gast #1933784
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
#1933797
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").
Gast #1934435
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

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