mikrocontroller.net

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


Autor: Daniel Schopf (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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
#include "uart.h"

unsigned int uartchar;

void wait (void)  
{int d;  for (d = 0; d < 1000000; d++)__nop();}

void UART_Rx_ISR(void)
{   
  unsigned int uartlsr;
  unsigned int uartiir;
  unsigned int i;

  while(((uartiir = U1IIR) & UARTIIR_NOINT) == 0) //Loop until no interrupt is pending
  {
    do{
      uartchar = U1RBR;
    }while(U1LSR & UARTLSR_RDR); //Loop as long as RBR contains valid data
  }

  IOCLR = 0x02440000;
  IOSET = 0x02000000;
  wait();
  IOCLR = 0x02440000;

  VICVectAddr = 0x00000000;
}

void initUART1()
{
  //PINSEL0 = 0x00000005; //for Tx and Rx - UART0
  PINSEL0 = 0x00050000; //for Tx and Rx - UART1
  U1IIR;  U1RBR;  U1LSR; //Reset them
  
  U1FCR = UARTFCR_RST_TX | UARTFCR_RST_RX | UARTFCR_EN | UARTFCR_TRIGGER4;
  U1LCR = 0x83; //8bit char length, 1 stop bit, no parity, DLAB = 1

  //for 38400Bd, divisor = 14765000/(38400*16) ~ 24
  U1DLL = 0x30;  U1DLM = 0x00;
  U1LCR &= 0x7F; //set DLAB to 0 

   //Sets the priority for IRQ interrupts
  VICVectCntl0 = 0x27; //Set priority for UART1 interrupt
  VICVectAddr0 = (unsigned long)UART_Rx_ISR; //Holds address of UART1's ISR

  //Set interrupts
  VICIntSelect = 0x00000000; //Set UARTs as member of IRQ interrupts
  VICIntEnable = 0x00000080; //Enable UART1 interrupts
  U1IER = UARTIER_RDA; //enable RDA interrupt  
}

Autor: C-Anfänger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die ISR muss dem Compiler als Interrupt-Handler beigebracht werden.

Autor: Daniel Schopf (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Daniel Schopf (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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").

Autor: Michael G. (let)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Daniel Schopf (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Daniel Schopf (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
void ISR(void) __irq

GANZ WICHTIG ist in diesem Fall: "__irq"

Jetzt funktioniert es.

Danke für eure Tipps.

Lg Daniel

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.