Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Message

Re: [lpc2000] Re: Problems w/ UART

2004-10-08 by Robert Adsett

First a question, you say the interrupt is not being generated, how do you 
know?

A few comments on the code below, probably more when I get a chance to 
review it properly.

At 05:12 PM 10/8/04 +0000, you wrote:
>It was a small oversite that it wasn't posted.  I was copying stuff
>out that I didn't need.  Since then I've made another small project
>that just tests the UART.  I am now trying non vector irqs, and they
>still don't work.  Here is the correct code:
>
>
>#include <stdio.h>
>#include "../ArmCommon/types.h"
>#include "../ArmCommon/LPC22xx.h"
>#include "../ArmCommon/LPC2294.h"
>
>#define TX_BUFFER_LENGTH 64
>
>static Uint16 txBytes = 0;
>static Uint16 txRdPos = 0;
>static Uint16 txWrPos = 0;
>static Uint16 txBuffer[TX_BUFFER_LENGTH];
>
>void uart0_config (void);
>void uart0_isr (void);
>void uart0_sendByte (Uint8);
>int putchar(int);
>int main (void);
>
>void uart0_config (void) {
>         // Setup UART 0
>         U0LCR = 0x80; // Enable DLAB
>         U0DLL = 0x36; // Setup BGR
>         U0DLM = 0x00; // ~57.6 kbps @ 50 Mhz
>         U0LCR = 0x03; // Enable UART 0, 8 bits, no parity, 1 stop bit
>
>         // Reset the FIFOs
>         U0FCR = 0xC7; // RX FIFO trigger level 8 chars, reset tx and rx fifo,
>enable fifos
>
>         // Setup Interrupts for UART0
>         VICIntSelect &= 0xFFFFBFFF;     // Make sure 6 is IRQ not FIQ
>         VICIntEnable |= (0x1 << 6); // Enable Uart0 Interrupt
>         VICDefVectAddr = (unsigned long) uart0_isr; // Use Non vectored irq
>         U0IER = 0x7;
>}
>
>void uart0_isr (void) __irq {
>         Uint8 dummy;
>         switch(U0LSR) {

This is potentially a very big problem.  The LSR can (and often will) have 
multiple bits set, so you will almost always be taking the default case 
even if THRE is set (thus my question above).  Given that the default case 
is echoing whatever is in U0RBR (BTW what is CTI?) I would expect almost 
anything if no characters had been sent to the port.  Change this before 
trying anything else.  Then put a pin toggle or something in so you know if 
the interrupt routine is ever reached.

>                 case 0x01: // RDR
>                         break;
>                 case 0x02: // OE
>                         break;
>                 case 0x04: // PE
>                         break;
>                 case 0x08: // FE
>                         break;
>                 case 0x10: // BI
>                         break;
>                 case 0x20: // THRE
>                         if(txBytes != 0) {
>                                 U0THR = txBuffer[txRdPos];
>                                 txRdPos++;
>                                 txRdPos = (txRdPos == 
> TX_BUFFER_LENGTH)?0:txRdPos;
>                                 txBytes--;
>                         }
>                         break;
>                 case 0x40: // TEMT
>                         break;
>                 case 0x80: // FXFE
>                         break;
>                 default: // Must be CTI
>                         uart0_sendByte(U0RBR);  // Echo back

This is potentially a problem.  I haven't looked at in detail but you are 
using the same buffer routine here as you are in the non-interrupt 
code.  The ground is very unstable here.

>         }
>         dummy = U0IIR; // read to clear IRQ
UOIIR is what you should be using to determine the interrupt source.


>         dummy += 1; // keep compiler from optimizing dummy out

And if U0IIR is read and used you don't need this line.  In fact if U0IIR 
is declared volatile (as it should be) you only would need this line if the 
compiler was buggy.

>         VICVectAddr = 0;
>}
>
>void uart0_sendByte(Uint8 a) {
>         // Wait until there is room in the buffer
>         while(txBytes == TX_BUFFER_LENGTH);
>         if(!(U0LSR&0x20)) { // Put it in the software buffer
>                 txBuffer[txWrPos] = a;
>                 txWrPos++;
>                 txWrPos = (txWrPos == TX_BUFFER_LENGTH)?0:txWrPos;
>                 txBytes++;
>         }
>         else { // If the chip buffer is empty, put it there
>                 U0THR = a;
>         }
>}
>
>int putchar(int a) {
>         uart0_sendByte((int)a);
>         return 0;
>}
>
>int main (void) {
>         PINSEL0 = PINSEL0_00_TxD | PINSEL0_01_RxD;
>         VPBDIV = 0x1;
>         uart0_config();
>         printf("piece of crap!");
>         while(1);
>}
>
>The output of this is "pep" when I run it on hardware.  The Keil
>simulator of course says it is fine.

There are multiple examples of working serial interrupt code around, some 
in the files section and the newlib support on 
http://www.aeolusdevelopment.com has some as well.  Most are GNU based, but 
the concepts and pitfalls are the same for all compilers.

Robert

" 'Freedom' has no meaning of itself.  There are always restrictions,
be they legal, genetic, or physical.  If you don't believe me, try to
chew a radio signal. "

                         Kelvin Throop, III

Attachments

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.