Forum: Mikrocontroller und Digitale Elektronik LPC1768 (Cortex-M3) und UART IRQ


von Arne (Gast)


Lesenswert?

Moin zusammen,

ich habe in der Firma ein Board-Support-Package für die STM32F10x 
geschrieben, bin also nicht ganz unerfahren mit Cortex-M3. Nun habe ich 
hier zuhause ein Evalboard mit LPC1768 von Steinert liegen. Clocks sind 
eingestellt, PLL0 rennt. Vektortabelle liegt ab $10000000 und ist dem 
NVIC auch so bekannt. Der Systicktimer läuft und er generiert mir auch 
einen IRQ und landet in der ISR. Nun will ich die UARTs in Betrieb 
nehmen.
Ich habe gesetzt:
- Bit in PCONP für UART0 gesetzt
- PCLKSEL für UART0 auf default = CCLK/4 = 25MHz
- PINSEL0 P0.2 und P0.3 auf UART gestellt
- Baudrate und 8N1 eingestellt
- Bit 0 in UART0FCR (use FIFO) ist gesetzt - lässt sich eh nicht 
ausknipsen
- Bit 5 (für UART0) in NVIC SETENA gesetzt
Entwicklungsumgebung ist IAR 5.50 mit J-Link von Segger.

Problem:
Ich lege ein Byte in meinen Softwareringpuffer zum Versenden mit UART0, 
und setze THREIE in UART0IER. Jetzt sollte - da TransmitHoldingRegister 
leer ist - ein IRQ erzeugt werden, damit meine ISR zum Versenden 
ausgeführt wird. Es wird aber kein IRQ ausgelöst.
Nun habe ich händisch im Debugger im NVIC das Bit 5 für UART0 in 
SETPEND0 gesetzt - und sofort rennt er auf meinen Breakpoint in der ISR.
Hat jemand eine Idee warum der IRQ nicht ausgelöst wird?

thanx, Arne

von Arne (Gast)


Lesenswert?

Keine eine Idee?

von Martin T. (mthomas) (Moderator) Benutzerseite


Lesenswert?

Details zum LPC17xx gerade nicht im Kopf aber es ist bei UART-Hardware 
nicht unüblich, dass der 
Hardware-bereit-für-nächstes-Zeichen-senden-Interrupt nur durch den 
Zustandswechsel Hold-Reg. voll -> Hold-Reg. leer ausgelöst wird (wäre 
damit entgegen der Annahme: "Jetzt sollte - da TransmitHoldingRegister 
leer ist - ein IRQ erzeugt werden"). Mögliche Abhilfe: in 'putchar()' 
prüfen, ob Interrupt aktiv, wenn ja: Zeichen in Warteschlange 
zwischenspeichern, wenn nicht: Zeichen in Hardwareregister und Interrupt 
aktivieren. In der ISR nächstes Zeichen aus Warteschlange in TX-Register 
oder wenn Schlange leer, Interrupt ausschalten. Kann man beim LPC17xx 
wahrscheinlich mittels Hardware-FIFO und/oder DMA noch einiges 
erweitern.

von Tueftler (Gast)


Lesenswert?

hast du die ISR per
  NVIC_EnableIRQ(....);
  NVIC_SetPriority (...);
enabled?

von Arne (Gast)


Lesenswert?

Weiss nicht wie es beim AVR ist, aber beim STM32 wird sofort in die ISR 
gesprungen, wenn das TransmitHoldingRegister leer ist und der Interrupt 
im UART aktiviert ist. Aber der STM32 hat auch keinen FIFO (jedenfalls 
kann man wohl nix per SW konfigurieren). Der LPC17xx hat Rx und Tx FIFO. 
Hab jetzt was im Manual gefunden... verstanden habe ich es nicht.

> Hardware-bereit-für-nächstes-Zeichen-senden-Interrupt nur durch den
> Zustandswechsel Hold-Reg. voll -> Hold-Reg. leer ausgelöst wird (wäre
> damit entgegen der Annahme: "Jetzt sollte - da TransmitHoldingRegister
> leer ist - ein IRQ erzeugt werden"
Hab es mir dreimal durchgelesen, aber beide Aussagen sind für mich 
gleichwertig!
Werde es morgen mal nach Deinem Vorschlag umbauen. Zerhagelt mir mein 
schönes API. :-(

von Arne (Gast)


Lesenswert?

Tueftler schrieb:
> hast du die ISR per
>   NVIC_EnableIRQ(....);
>   NVIC_SetPriority (...);
> enabled?

Schrieb ich ja:
- Bit 5 (für UART0) in NVIC SETENA gesetzt.

und Priorität ist per default nach Reset auf 0 -> höchste Priorität.

von Manfred (Gast)


Lesenswert?

Ich bin ja auch erst am Einarbeiten mit dem LPC, aber ich verstehe das 
Datenblatt so: Man schreibt sein Byte in U0THR. Wenn der FIFO an ist, 
kümmert der sich darum, daß das Byte in den FIFO kommt (also kein 
eigener Softwareringbuffer erforderlich). Der FIFO schiebt das Byte dann 
automatisch raus, wenn UART0 sendebereit ist. Also kein Interrupt zum 
Senden erforderlich. Im Datenblatt ist leider nicht beschrieben, wann 
THREI0 triggert. Ich vermute aber mal, daß er beim Übergang von THR full 
nach empty triggert. Würde sonst ja auch keinen Sinn machen, wenn das 
leere THR triggern würde. Wäre sonst ja fast immer am triggern ...
Also eigentlich genau das, was Martin schon geschrieben hatte.

von Arne (Gast)


Lesenswert?

@Michael:
was meinst Du mit "THREI0"?
Hab gestern abend noch dran rumgefummelt, aber es kam nur Quark im 
Terminalprg an. Das alte Manual beschrieb noch ein FIFOLVL Register, das 
den Füllstand von TX/RX-FIFO angab. Ist im aktuellen Manual nicht drin 
und ist im LPC auch nicht "eingebaut" :-(

von Arne (Gast)


Lesenswert?

Soll natürlich @Manfred heissen - mea culpa.

von Manfred (Gast)


Lesenswert?

Arne schrieb:
> Soll natürlich @Manfred heissen - mea culpa.

Macht nichts, ich hab mich auch verschrieben :-)

Ich meinte das Bit THRE Interrupt Enable im Register U0IER (für den 
UART0). Damit lag ich aber leider falsch.

Weiter unten wird es doch noch beschrieben:
The UARTn THRE interrupt (UnIIR[3:1] = 001) is a third level interrupt 
and is activated when the UARTn THR FIFO is empty provided certain 
Initialization conditions have been met. These initialization conditions 
are intended to give the UARTn THR FIFO a chance to fill up with data to 
eliminate many THRE interrupts from occurring at system start-up. The
initialization conditions implement a one character delay minus the stop 
bit whenever THRE = 1 and there have not been at least two characters in 
the UnTHR at one time since the last THRE = 1 event. This delay is 
provided to give the CPU time to write data to UnTHR without a THRE 
interrupt to decode and service. A THRE interrupt is set immediately if 
the UARTn THR FIFO has held two or more characters at one time and 
currently, the UnTHR is empty. The THRE interrupt is reset when a UnTHR 
write occurs or a read of the UnIIR occurs and the THRE is the highest 
interrupt (UnIIR[3:1] = 001).

Frei übersetzt: Der Interrupt kommt nur, wenn schon mal mindestens 2 
Zeichen im FIFO waren und U0THR dann leer wird.

von Arne (Gast)


Lesenswert?

Der Sendestring kommt immer noch stellenweise zerhackt am PC an.
Meine putchar() Funktion füllt nun solange direkt den TxFIFO solange 
THRE==1 ist.
Sobald THRE==0 ist, wird das Zeichen in meinen SW-Ringpuffer gelegt und 
der THREIE Interrupt aktiviert. Scheint bisher nicht zuverlässig zu 
funktionieren.
Es bleibt schwierig...

von Lutz (Gast)


Lesenswert?

Es wird langsam Zeit für den Code ...

von Arne (Gast)


Lesenswert?

Ich denke, ich weiss inzwischen wo das Problem liegt.
Mein API schiebt die zu vesendenden Zeichen IMMER einzeln durch eine 
Funktion durch. Wenn THRE==1, dann lege ich das Zeichen beim LPC1768 
direkt in das THR. Beim nächsten Zeichen ist THRE==0 und ich lege das 
Zeichen in meinen SW-Ringpuffer. Nun kommt das Problem, dass ich in der 
Funktion nie weiss zu welchem Grad der FIFO gefüllt ist (THRE==0 heisst 
1..16 Byte im FIFO), aber zwingend zwei Zeichen im FIFO sein müssen, 
damit überhaupt der THRE-Interrupt getriggert wird. Darf das aktuelle 
Zeichen noch in den FIFO oder nicht? Mitzählen bringt nichts, da ich ja 
nicht weiss wie schnell die Zeichen aus dem Schiebereg. auf die Reise 
gehen (könnte man sich errechnen, ist aber wohl zu fehlerhaft). Somit 
wäre die Zählung nur ein Schätzeisen.

Habe mir einige Besipiele für LPC17xx und LPC2000 angeschaut. Alle 
nudeln das ohne SW-Ringpuffer ab. Entweder sie pollen THRE und legen 
dann ein Char in den FIFO (was den FIFO ad absurdum führt) oder sie 
schieben max. 16 Byte in den FIFO und warten dann im Hauptprogramm. 
Beides sehr primitive "Lösungen"!

von Lowtzow .. (lowtzow)


Lesenswert?

hast du das Problem lösen können?

von minti (Gast)


Lesenswert?

Hallo,

ich wollte mal fragen, ob es mittlerweile hier eine Lösung des Problemes 
gibt.

Ich selber habe die identische Situation mit der ISR und einem Software 
Ringpuffer. Im Terminalprogramm erhalte ich immer nur zwei Zeichen. 
Danach funktioniert der uart gar nicht mehr.

Daher wäre ich über weitere Lösungsansätze sehr dankbar.
Vielleicht lässt sich für eine so wichtige Anwendung, wie den UART dann 
auch anschließend etwas in der Codesammlung unterbringen.

von Arne (Gast)


Lesenswert?

ja, geht inzwischen.

von minti (Gast)


Lesenswert?

@Arne: könntest Du mir die Lösung auch zukommen lassen bzw. allen hier. 
Alternativ wäre ich auch glücklich wenn ich wüsste was ich ändern muss, 
damit das ganze läuft.

von Alex (Gast)


Lesenswert?

Hallo Arne,
ich steh vor dem gleichen Problem und würde mich über deine Lösung 
freuen.
Kannst du sie bitte online stellen.
Bestimmt sind auch andere daran Interessiert.

von Holger H. (holger-h-hennef) Benutzerseite


Lesenswert?

Link:
http://docs.lpcware.com/lpcopen/group___p_e_r_i_p_h__11_x_x___u_a_r_t.html#gac1a9d00d4f324e319e1486138b097874
Da ist glaube ich was für euch dabei..ist zwar vom LPC11x aber
die sind von der Arcitektur fast gleich.

void Chip_UART_SetupFIFOS ... *pRX = &rec_buffer[0]

Das Sratchpad ist auch dabei. via Timer @

Frage:
Habt ihr ein Api Manual als Doxygen Format ? für den LPC1768 Chip.
-----------------------------------------------------------------
Gruss Holger.

von Holger H. (holger-h-hennef) Benutzerseite


Lesenswert?

Hier der Link:
Wichtig ist hier:
LPC_UART->TER = ( 0x80); // enable transmit #


https://github.com/someone42/hardware-bitcoin-wallet/blob/master/lpc11uxx/usart.c

Ich teste das im Loop-Back-Mode:
 LPC_UART->MCR |= (    (1<<4)   ) ;    /* $10Lopp-Back*/
Im Code ist das IRQ Ident gelesen und danach einmal geschiftet
Diese Shifte verstehe ich nicht
  IIRValue >>= (0x01); was soll das ???
Legende:
[DMAS:2][S:1][S:0] [rx_irq_flg:-(1)RHR]
1
 LPC_UART->FCR = ( 0x01   ); // (0x04 | 0x02 );    /* 0x07 Enable and reset TX and RX FIFO. */
2
  LPC_UART->FCR = (0x07); // clear receive and transmit FIFOs, trigger level = 1 character
3
  LPC_UART->TER = ( 0x80); // enable transmit ###########
4
############
5
   // [DMAS:2][S:1][S:0][rx_irq_flg:-(1)RHR]
6
 // must I shift this RHR Rec-Hold Reg away --Pending Rec-Holding Reg
7
/* ########### Fifo-Betrieb oder Modem ??? ################*/
8
 // IIRValue >>= (0x01);      /* ???skip pending bit in IIR */
9
 // [DMA_S:2][S:1][S:0] no RHR get over LSR Reg
10
  IIRValue &= ( 0x07);  /* check bit 1~3, interrupt identification */
11
  if (IIRValue == IIR_RLS)    /* Receive Line Status */
12
  { /*                    Line-StausReg*/
13
    LSRValue = LPC_UART->LSR; //  (0x01) ^ (1 <<0 ) RHR -get over LSR
14
    /* Receive Line Status*/
15
    // *          --OVERRUN,Parrity-Err.,FRAMErr---[-RX-FIFO-Error],--/BREAK-Indicator#IRQ*;/
16
    if (LSRValue & ( LSR_OE | LSR_PE | LSR_FE | LSR_RXFE | LSR_BI) )
17
    {
18
      /* There are errors or break interrupt */

von Holger H. (holger-h-hennef) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hier ist ein Fifo
1
  LPC_UART->LCR = /*0x80*/ (0x03);    /*/7-Div,/6-BRK.emit,5Par-set Divisor EnableDLAB = 0 */
2
 /* Close Latch für divisor Feq*/
3
  //         FIFO $07
4
  LPC_UART->FCR = ( 0x01   ); // (0x04 | 0x02 );    /* 0x07 Enable and reset TX and RX FIFO. */
5
  LPC_UART->FCR = (0x07); // clear receive and transmit FIFOs, trigger level = 1 character
6
7
  /*############################*/
8
  LPC_UART->FCR = ( 0x01   ); // Bit-Map[no/Tx-Fifo-Reset][no/Rx-Fifo-Res][E-Yes]
9
    LPC_UART->FCR |= (0x40 | 0x01); // bit 6 Trigger Level_1-Stage + [E-Yes]-FifFo-ON
10
11
  /*  Wichtig: $80 Set ******** ##############*/
12
  LPC_UART->TER = ( 0x80); // enable transmit ???-->>>Hardware must even in Loop-Back-Mode ??

von Holger H. (holger-h-hennef) Benutzerseite


Angehängte Dateien:

Lesenswert?

Das ist wohl nur im auto Hand-Schake via Full-Modem mit Fifo möglich.
also z.B (CTS RTS, DSR DTR CD ect. Criss -Cross DTE DCE)
Das pdf Datenblatt ist wohl geaendert worden...
Link:
Fifo Problem.
http://knowledgebase.nxp.com/showthread.php?t=2231
############################################################
Mit dem Loop-Back teste ich auch noch den Modem-Config.
Ist als Bild auf dem EXAR pdf abgebildet.
Bits für (Opt#2/Int, OPT#1 ). usw.
Auch die Config . IER (Bit#2) bzw. (Bit#3) ist das der exMux für
Hardwire-Modem?? bzw. (LSR Reg. via couppling (Bit#2)- von IER)

########################################################################
1
  void UARTSend(uint8_t *BufferPtr, uint32_t Length)
2
{
3
  
4
  while ( Length != 0 )
5
  {
6
    /* THRE status, contain valid data */
7
#if CONFIG_UART_ENABLE_TX_INTERRUPT==1
8
    /* Below flag is set inside the interrupt handler when THRE occurs. */
9
      while ( !(UARTTxEmpty & 0x01) );
10
    LPC_UART->THR = *BufferPtr;
11
      UARTTxEmpty = 0;  /* not empty in the THR until it shifts out */
12
#else
13
  /* To_Do: FIFO aktiv via pre prept user app-info from Scratch-Pad */
14
      //while-case#1:
15
    ///  while ( ! (LPC_UART->LSR & LSR_THRE) );// $20 #define THR (1<<5)
16
      /* Wait till U0THR and U0TSR are both empty */
17
      // wait for Transmit-Shift-Reg.Emty until even Stop-Bit-Emited , see option 2Stop-bit
18
      //while-case#(2): [Hold-Reg-buff$20]-->(Shift-Reg.$40)-->
19
      while ( (LPC_UART->LSR &  LSR_TEMT) == (0x00) );// $40 #define TEMT (1<<6)
20
    LPC_UART->THR = *BufferPtr; // Feeed THReg.
21
#endif
22
      BufferPtr++;
23
      Length--;
24
  }
25
  return;
26
}

von Holger H. (holger-h-hennef) Benutzerseite


Angehängte Dateien:

Lesenswert?

if(!(tx_data % 16))
% 4 ist für fifo-len = 4
der maximale Fifo ist 14 , warum % 16 ???
 ?
void UART_Tx(char *BufferPtr, int Length)
 {
  unsigned char tx_data = 0;
   while ( Length != 0 )
   {
      if(!(tx_data % 16)) // ???
      {
        while ( !(LPC_UART->LSR & LSR_THRE) );
      }
       LPC_UART->THR = *BufferPtr;
      BufferPtr++;
      tx_data ++;
      Length--;
   }
   return;
 }
########################################################################
Ich habe das TX IRQ Enable nicht gesetzt, somit muss ich immer
bit 5 & 6 abfragen.
siehe via LSR  . Sonst gehen nur 2 Zeichen, ( wohl Buff-Intern ??)wie 
ich das mit Loop-Back (Fazit Bem: 14-Byte Fifo + 2 Buff  = 16 ???  )
getestet habe.
Um das noch weiter zu testen, nehme ich den TX IRQ Enable noch hinzu.
########################################################################
Anlage Bild ist für den 'Fifo-Size [1,4,8,14] 'bit[1]bit[1] = 14 = 0x0E
########################################################################
Hint zum Umgang mit der IDE.

LPCXpresso Introduction part 2 training video
http://www.youtube.com/watch?v=cLvGwmJAA7k

von xeniter (Gast)


Lesenswert?

Hab noch ein Problem gefunden an folgender Stelle:

LPC_UART->THR = *BufferPtr;
// XXX
UARTTxEmpty = 0;  /* not empty in the THR until it shifts out */



schreiben auf THR resettet den interupt wenn zwischen den Zeilen ein 
Interupt auftritt(XXX) und dieser zu lange braucht und der uart das 
zeichen rausgeschrieben hat tritt der IIR_TRHE interupt auf UARTTxEmpty 
wird auf 1 gesetzt jedoch gleich nach dem Interrupt auf 0.

Somit bleibt er in der Endlosschleife beim nächsten mal while ( 
!(UARTTxEmpty & 0x01) ); hängen weil der ISR schon gekommen ist

Leider ist der Fehler in der standard lib, werde ihn noch melden

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.