Forums

UART1 for LPC2148

Started by dodge1955 February 24, 2006
I'm having a problem with getting UART1 to work on my Embedded Artists
prototype board.  I have a serial display that has only 1 serial line.
 In other words, you can only transmit to the display.  I can't get
P0.8 (UART1 TX) to send any data.  Here is my setup at 9600.  And,
another question is 'Do I really need an interrupt just to transmit? 
It seems like throwing a char out to U1THR should suffice.  It's
probably something simple I'm missing.  Thanks.

Sutton - dodge55
	VICIntSelect = 0;
VICVectAddr2 = (unsigned int) uart1_out;
VICVectCntl2 = 0x20 | 7;  // enables the UART1 interrupt, slot 7
U1FDR = 0x00000010;   // MULVAL = 1, DIVVAL = 0
U1DLM = 0;
U1DLL = 0x48;	 // 9600 baud
U1LCR = 0x03;     // 8 bits, 1 stop, no parity, DLAB = 0
U1FCR = 1;
VICIntEnable |= 0x00000080;

void display_write(char text[])
{
   unsigned char i;

   sprintf(display_output, "%s", text);
   for (i = 0; i < strlen(display_output); i++)
   {
      my_putchar(display_output[i]);
   }
}

void my_putchar(char c)
{
   U1THR = c;
}

void uart1_out(void) __irq
{
   VICVectAddr = 0;
}
	

An Engineer's Guide to the LPC2100 Series

dodge1955 wrote:
> I'm having a problem with getting UART1 to work on
my Embedded Artists
> prototype board.  I have a serial display that has only 1 serial line.
> In other words, you can only transmit to the display.  I can't get
> P0.8 (UART1 TX) to send any data.  Here is my setup at 9600.  And,

You need to set bit 7 (DLAB) of the LCR before setting the
divider.

> another question is 'Do I really need an interrupt
just to transmit?
> It seems like throwing a char out to U1THR should suffice.  It's
> probably something simple I'm missing.  Thanks.

No, I think you don't need an interrupt.

Another thing, although the bit for UART1 in the PCONP register
is supposed to default to 1, I would verify that it is
_really_ set.

> 
> Sutton - dodge55
> 
> 
> VICIntSelect = 0;
> VICVectAddr2 = (unsigned int) uart1_out;
> VICVectCntl2 = 0x20 | 7;  // enables the UART1 interrupt, slot 7
> U1FDR = 0x00000010;   // MULVAL = 1, DIVVAL = 0
> U1DLM = 0;
> U1DLL = 0x48;      // 9600 baud
> U1LCR = 0x03;     // 8 bits, 1 stop, no parity, DLAB = 0
> U1FCR = 1;
> VICIntEnable |= 0x00000080;
> 
> void display_write(char text[])
> {
>    unsigned char i;
> 
>    sprintf(display_output, "%s", text);
>    for (i = 0; i < strlen(display_output); i++)
>    {
>       my_putchar(display_output[i]);
>    }
> }
> 
> void my_putchar(char c)
> {
>    U1THR = c;
> }

I think it would be wise to check if the UART is able to accept the
character. You can do this by checking that bit 5 or 6 of the LSR.

> 
> void uart1_out(void) __irq
> {
>    VICVectAddr = 0;
> }

Regards,
Bertrik

Sutton: try making sure you have room in the transmit buffer before 
sending a character:

void my_putchar(char c)
{
while(!(U0LSR & 0x20));
U0THR = c;
}

This is my setup code:

PCONP |= PCONP_PCUART0;

PINSEL0 = (PINSEL0 & 0xfffffffc) | 0x00000001; // TX only

U0LCR = 0x83;	// 8 bits, no Parity, 1 Stop bit, DLAB = 1
U0DLL = UART0_DIV_LOW;
U0DLM = UART0_DIV_HIGH;
U0LCR = 0x03;  // DLAB = 0
U0IER = 0x00;  // No interrupts
U0FCR = 0x01;  // Use FIFO
U0TER = 0x80;  // Transmitter enabled
	Hope this helps.

Guille
	--- In lpc2000@lpc2..., Bertrik Sikken <bertrik@...> wrote:
>
> dodge1955 wrote:
> > I'm having a problem with getting UART1 to work on my Embedded 
Artists
> > prototype board.  I have a serial display
that has only 1 serial 
line.
> > In other words, you can only transmit to the
display.  I can't get
> > P0.8 (UART1 TX) to send any data.  Here is my setup at 9600.  And,
> 
> You need to set bit 7 (DLAB) of the LCR before setting the
> divider.
> 
> > another question is 'Do I really need an interrupt just to 
transmit?
> > It seems like throwing a char out to U1THR
should suffice.  It's
> > probably something simple I'm missing.  Thanks.
> 
> No, I think you don't need an interrupt.
> 
> Another thing, although the bit for UART1 in the PCONP register
> is supposed to default to 1, I would verify that it is
> _really_ set.
> 
> > 
> > Sutton - dodge55
> > 
> > 
> > VICIntSelect = 0;
> > VICVectAddr2 = (unsigned int) uart1_out;
> > VICVectCntl2 = 0x20 | 7;  // enables the UART1 interrupt, slot 7
> > U1FDR = 0x00000010;   // MULVAL = 1, DIVVAL = 0
> > U1DLM = 0;
> > U1DLL = 0x48;      // 9600 baud
> > U1LCR = 0x03;     // 8 bits, 1 stop, no parity, DLAB = 0
> > U1FCR = 1;
> > VICIntEnable |= 0x00000080;
> > 
> > void display_write(char text[])
> > {
> >    unsigned char i;
> > 
> >    sprintf(display_output, "%s", text);
> >    for (i = 0; i < strlen(display_output); i++)
> >    {
> >       my_putchar(display_output[i]);
> >    }
> > }
> > 
> > void my_putchar(char c)
> > {
> >    U1THR = c;
> > }
> 
> I think it would be wise to check if the UART is able to accept the
> character. You can do this by checking that bit 5 or 6 of the LSR.
> 
> > 
> > void uart1_out(void) __irq
> > {
> >    VICVectAddr = 0;
> > }
> 
> Regards,
> Bertrik
>
	
Bertrik and Guille,

Here is my new code.  Still doesn't work right.  I've even tweaked the
MULVAL and DIVVAL numbers to better match the 12Mhz at 9600 baud.  It
doesn't come out perfect with a 12Mhz clock.  P0.8 blinks like mad,
but still no data out on 9600 PROCOMM.  PROCOMM works great directly
to my 9600 baud display.  But can't get it to work thru the 2148
chip's UART1.  Am I still missing something?

Sutton - dodge55

PINSEL0 |= 0x00010000;
PCONP |= 0x00000010;
U1FDR = 0x0000009A;          // MULVAL = 9, DIVVAL = 10
U1LCR = 0x83;	             // enable Divisor Latches
U1DLM = 0;
U1DLL = 0x25;	             // 9601.71 baud
U1LCR = 0x03;                // 8 bits, 1 stop, no parity, DLAB = 0
U1FCR = 1;
U1TER = 0x80;
U1IER = 0;
	void my_putchar(char c)
{
   if ((U1LSR & 0x20) != 0)	 // TX buffer empty
   {
      U1THR = c;
   }
}

void display_write(char text[])
{
   unsigned char i;

   sprintf(display_output, "%s", text);
   for (i = 0; i < strlen(display_output); i++)
   {
      my_putchar(display_output[i]);
   }
}
	--- In lpc2000@lpc2..., "dodge1955" <sutton@...> wrote:
>
> I'm having a problem with getting UART1 to work on my Embedded Artists
> prototype board.  I have a serial display that has only 1 serial line.
>  In other words, you can only transmit to the display.  I can't get
> P0.8 (UART1 TX) to send any data.  Here is my setup at 9600.  And,
> another question is 'Do I really need an interrupt just to transmit? 
> It seems like throwing a char out to U1THR should suffice.  It's
> probably something simple I'm missing.  Thanks.
> 
> Sutton - dodge55
> 
> 
> VICIntSelect = 0;
> VICVectAddr2 = (unsigned int) uart1_out;
> VICVectCntl2 = 0x20 | 7;  // enables the UART1 interrupt, slot 7
> U1FDR = 0x00000010;   // MULVAL = 1, DIVVAL = 0
> U1DLM = 0;
> U1DLL = 0x48;	 // 9600 baud
> U1LCR = 0x03;     // 8 bits, 1 stop, no parity, DLAB = 0
> U1FCR = 1;
> VICIntEnable |= 0x00000080;
> 
> void display_write(char text[])
> {
>    unsigned char i;
> 
>    sprintf(display_output, "%s", text);
>    for (i = 0; i < strlen(display_output); i++)
>    {
>       my_putchar(display_output[i]);
>    }
> }
> 
> void my_putchar(char c)
> {
>    U1THR = c;
> }
> 
> void uart1_out(void) __irq
> {
>    VICVectAddr = 0;
> }
>
	
I think the baudrate is incorrect.
The divisor that you're using now does not make sense to me
(looks like a bug in the baudrate calculation program).
Try 78 for U1DLL (calculated from PCLK/(16*baudrate))
and set U1FDR to 0.

Bertrik

dodge1955 wrote:
> Bertrik and Guille,
> 
> Here is my new code.  Still doesn't work right.  I've even tweaked the
> MULVAL and DIVVAL numbers to better match the 12Mhz at 9600 baud.  It
> doesn't come out perfect with a 12Mhz clock.  P0.8 blinks like mad,
> but still no data out on 9600 PROCOMM.  PROCOMM works great directly
> to my 9600 baud display.  But can't get it to work thru the 2148
> chip's UART1.  Am I still missing something?
> 
> Sutton - dodge55
> 
> PINSEL0 |= 0x00010000;
> PCONP |= 0x00000010;
> U1FDR = 0x0000009A;          // MULVAL = 9, DIVVAL = 10
> U1LCR = 0x83;                   // enable Divisor Latches
> U1DLM = 0;
> U1DLL = 0x25;                   // 9601.71 baud
> U1LCR = 0x03;                // 8 bits, 1 stop, no parity, DLAB = 0
> U1FCR = 1;
> U1TER = 0x80;
> U1IER = 0;
> 
> 
> 
> void my_putchar(char c)
> {
>    if ((U1LSR & 0x20) != 0)      // TX buffer empty
>    {
>       U1THR = c;
>    }
> }
> 
> void display_write(char text[])
> {
>    unsigned char i;
> 
>    sprintf(display_output, "%s", text);
>    for (i = 0; i < strlen(display_output); i++)
>    {
>       my_putchar(display_output[i]);
>    }
> }
> 
> 
> 
> 
> 
> 
> --- In lpc2000@lpc2..., "dodge1955" <sutton@...> wrote:
>>
>> I'm having a problem with getting UART1 to work on my Embedded Artists
>> prototype board.  I have a serial display that has only 1 serial line.
>>  In other words, you can only transmit to the display.  I can't get
>> P0.8 (UART1 TX) to send any data.  Here is my setup at 9600.  And,
>> another question is 'Do I really need an interrupt just to transmit?
>> It seems like throwing a char out to U1THR should suffice.  It's
>> probably something simple I'm missing.  Thanks.
>>
>> Sutton - dodge55
>>
>>
>> VICIntSelect = 0;
>> VICVectAddr2 = (unsigned int) uart1_out;
>> VICVectCntl2 = 0x20 | 7;  // enables the UART1 interrupt, slot 7
>> U1FDR = 0x00000010;   // MULVAL = 1, DIVVAL = 0
>> U1DLM = 0;
>> U1DLL = 0x48;      // 9600 baud
>> U1LCR = 0x03;     // 8 bits, 1 stop, no parity, DLAB = 0
>> U1FCR = 1;
>> VICIntEnable |= 0x00000080;
>>
>> void display_write(char text[])
>> {
>>    unsigned char i;
>>
>>    sprintf(display_output, "%s", text);
>>    for (i = 0; i < strlen(display_output); i++)
>>    {
>>       my_putchar(display_output[i]);
>>    }
>> }
>>
>> void my_putchar(char c)
>> {
>>    U1THR = c;
>> }
>>
>> void uart1_out(void) __irq
>> {
>>    VICVectAddr = 0;
>> }
	
This code just discards bytes when the FIFO's full!

    if ((U1LSR & 0x20) != 0)  // TX buffer empty
    {
       U1THR = c;
    }

You should do this instead:

while(!(U1LSR & 0x20));
U1THR = c;

Mind the semi-colon after the while. You can reword it like this:

while( (U0LSR & 0x20) == 0x00 )
{
// Do nothing but wait
}
U0THR = c;

Guille

--- In lpc2000@lpc2..., "dodge1955" <sutton@...> wrote:
>
> Bertrik and Guille,
> 
> Here is my new code.  Still doesn't work right.  I've even tweaked 
the
> MULVAL and DIVVAL numbers to better match the
12Mhz at 9600 baud.  
It
> doesn't come out perfect with a 12Mhz clock.  P0.8
blinks like mad,
> but still no data out on 9600 PROCOMM.  PROCOMM works great directly
> to my 9600 baud display.  But can't get it to work thru the 2148
> chip's UART1.  Am I still missing something?
> 
> Sutton - dodge55
> 
> PINSEL0 |= 0x00010000;
> PCONP |= 0x00000010;
> U1FDR = 0x0000009A;          // MULVAL = 9, DIVVAL = 10
> U1LCR = 0x83;	             // enable Divisor Latches
> U1DLM = 0;
> U1DLL = 0x25;	             // 9601.71 baud
> U1LCR = 0x03;                // 8 bits, 1 stop, no parity, DLAB = 0
> U1FCR = 1;
> U1TER = 0x80;
> U1IER = 0;
> 
> 
> 
> void my_putchar(char c)
> {
>    if ((U1LSR & 0x20) != 0)	 // TX buffer empty
>    {
>       U1THR = c;
>    }
> }
> 
> void display_write(char text[])
> {
>    unsigned char i;
> 
>    sprintf(display_output, "%s", text);
>    for (i = 0; i < strlen(display_output); i++)
>    {
>       my_putchar(display_output[i]);
>    }
> }
> 
> 
> 
> 
> 
> 
> --- In lpc2000@lpc2..., "dodge1955" <sutton@> wrote:
> >
> > I'm having a problem with getting UART1 to work on my Embedded 
Artists
> > prototype board.  I have a serial display
that has only 1 serial 
line.
> >  In other words, you can only transmit to the
display.  I can't 
get
> > P0.8 (UART1 TX) to send any data.  Here is my
setup at 9600.  And,
> > another question is 'Do I really need an interrupt just to 
transmit? 
> > It seems like throwing a char out to U1THR
should suffice.  It's
> > probably something simple I'm missing.  Thanks.
> > 
> > Sutton - dodge55
> > 
> > 
> > VICIntSelect = 0;
> > VICVectAddr2 = (unsigned int) uart1_out;
> > VICVectCntl2 = 0x20 | 7;  // enables the UART1 interrupt, slot 7
> > U1FDR = 0x00000010;   // MULVAL = 1, DIVVAL = 0
> > U1DLM = 0;
> > U1DLL = 0x48;	 // 9600 baud
> > U1LCR = 0x03;     // 8 bits, 1 stop, no parity, DLAB = 0
> > U1FCR = 1;
> > VICIntEnable |= 0x00000080;
> > 
> > void display_write(char text[])
> > {
> >    unsigned char i;
> > 
> >    sprintf(display_output, "%s", text);
> >    for (i = 0; i < strlen(display_output); i++)
> >    {
> >       my_putchar(display_output[i]);
> >    }
> > }
> > 
> > void my_putchar(char c)
> > {
> >    U1THR = c;
> > }
> > 
> > void uart1_out(void) __irq
> > {
> >    VICVectAddr = 0;
> > }
> >
>
	
Oops, after a closer look, your U1FDR and U1DLM/DLL settings
appear to be correct. Sorry about the confusion.

Bertrik

Bertrik Sikken wrote:
> I think the baudrate is incorrect.
> The divisor that you're using now does not make sense to me
> (looks like a bug in the baudrate calculation program).
> Try 78 for U1DLL (calculated from PCLK/(16*baudrate))
> and set U1FDR to 0.
> 
> Bertrik
> 
> dodge1955 wrote:
>> Bertrik and Guille,
>>
>> Here is my new code.  Still doesn't work right.  I've even tweaked the
>> MULVAL and DIVVAL numbers to better match the 12Mhz at 9600 baud.  It
>> doesn't come out perfect with a 12Mhz clock.  P0.8 blinks like mad,
>> but still no data out on 9600 PROCOMM.  PROCOMM works great directly
>> to my 9600 baud display.  But can't get it to work thru the 2148
>> chip's UART1.  Am I still missing something?
>>
>> Sutton - dodge55
>>
>> PINSEL0 |= 0x00010000;
>> PCONP |= 0x00000010;
>> U1FDR = 0x0000009A;          // MULVAL = 9, DIVVAL = 10
>> U1LCR = 0x83;                   // enable Divisor Latches
>> U1DLM = 0;
>> U1DLL = 0x25;                   // 9601.71 baud
>> U1LCR = 0x03;                // 8 bits, 1 stop, no parity, DLAB = 0
>> U1FCR = 1;
>> U1TER = 0x80;
>> U1IER = 0;
>>
>>
>>
>> void my_putchar(char c)
>> {
>>    if ((U1LSR & 0x20) != 0)      // TX buffer empty
>>    {
>>       U1THR = c;
>>    }
>> }
>>
>> void display_write(char text[])
>> {
>>    unsigned char i;
>>
>>    sprintf(display_output, "%s", text);
>>    for (i = 0; i < strlen(display_output); i++)
>>    {
>>       my_putchar(display_output[i]);
>>    }
>> }
>>
>>
>>
>>
>>
>>
>> --- In lpc2000@lpc2..., "dodge1955" <sutton@...> wrote:
>>>
>>> I'm having a problem with getting UART1 to work on my Embedded
Artists
>>> prototype board.  I have a serial display that has only 1 serial
line.
>>>  In other words, you can only transmit to the display.  I can't get
>>> P0.8 (UART1 TX) to send any data.  Here is my setup at 9600.  And,
>>> another question is 'Do I really need an interrupt just to
transmit?
>>> It seems like throwing a char out to U1THR should suffice.  It's
>>> probably something simple I'm missing.  Thanks.
>>>
>>> Sutton - dodge55
>>>
>>>
>>> VICIntSelect = 0;
>>> VICVectAddr2 = (unsigned int) uart1_out;
>>> VICVectCntl2 = 0x20 | 7;  // enables the UART1 interrupt, slot 7
>>> U1FDR = 0x00000010;   // MULVAL = 1, DIVVAL = 0
>>> U1DLM = 0;
>>> U1DLL = 0x48;      // 9600 baud
>>> U1LCR = 0x03;     // 8 bits, 1 stop, no parity, DLAB = 0
>>> U1FCR = 1;
>>> VICIntEnable |= 0x00000080;
>>>
>>> void display_write(char text[])
>>> {
>>>    unsigned char i;
>>>
>>>    sprintf(display_output, "%s", text);
>>>    for (i = 0; i < strlen(display_output); i++)
>>>    {
>>>       my_putchar(display_output[i]);
>>>    }
>>> }
>>>
>>> void my_putchar(char c)
>>> {
>>>    U1THR = c;
>>> }
>>>
>>> void uart1_out(void) __irq
>>> {
>>>    VICVectAddr = 0;
>>> }

Hi Sutton,

> I'm having a problem with getting UART1 to work on
my Embedded Artists
> prototype board.  I have a serial display that has only 1 serial line.
>  In other words, you can only transmit to the display.  I can't get
> P0.8 (UART1 TX) to send any data.  Here is my setup at 9600.  And,
> another question is 'Do I really need an interrupt just to transmit?
> It seems like throwing a char out to U1THR should suffice.  It's
> probably something simple I'm missing.  Thanks.

Below is code to implement 115200 baud at any peripheral clock frequency
based on 12MHz with lowest % error.  All items have been tested, and numbers
were derived from my utility.  This concept can be applied for any
peripheral clock or baud rate.  When I have some time I will create defines
for all standard baud rates for lowest % error.

To transmit character out of UART no interrupts are required.  Just write
the character to the UART_THR after initializing UART.

Unrelated but important when using LPC214x and USB peripheral, it states in
manual core clock must run at a minimum of 18MHz.
	Joel

/*
****************************************************************
* UART w/fraction divider register values for lowest % error
****************************************************************
*/

#define BAUDRATE 115200L

#if (PCLK_UART=`MHZ)
  #define UART_DLM        0
  #define UART_DLL       24
  #define UART_MULVAL    14
  #define UART_DIVADDVAL  5
#elif (PCLK_UART=HMHZ)
  #define UART_DLM        0
  #define UART_DLL       23
  #define UART_MULVAL    15
  #define UART_DIVADDVAL  2
#elif (PCLK_UART=6MHZ)
  #define UART_DLM        0
  #define UART_DLL        8
  #define UART_MULVAL     9
  #define UART_DIVADDVAL 13
#elif (PCLK_UART=0MHZ)
  #define UART_DLM        0
  #define UART_DLL       12
  #define UART_MULVAL    14
  #define UART_DIVADDVAL  5
#elif (PCLK_UART=$MHZ)
  #define UART_DLM        0
  #define UART_DLL       13
  #define UART_MULVAL    14
  #define UART_DIVADDVAL  0
#elif (PCLK_UART=MHZ)
  #define UART_DLM        0
  #define UART_DLL        8
  #define UART_MULVAL     9
  #define UART_DIVADDVAL  2
#elif (PCLK_UART=MHZ)
  #define UART_DLM        0
  #define UART_DLL        3
  #define UART_MULVAL     7
  #define UART_DIVADDVAL 12
#elif (PCLK_UART=MHZ)
  #define UART_DLM        0
  #define UART_DLL        3
  #define UART_MULVAL    12
  #define UART_DIVADDVAL 14
#elif (PCLK_UART== 9MHZ)
  #define UART_DLM        0
  #define UART_DLL        2
  #define UART_MULVAL     9
  #define UART_DIVADDVAL 13
#elif (PCLK_UART== 6MHZ)
  #define UART_DLM        0
  #define UART_DLL        3
  #define UART_MULVAL    12
  #define UART_DIVADDVAL  1
#if 0 /* bauds > 38400 are not working with fdr for pclk == 3MHz */
#elif (PCLK_UART== 3MHZ)
  #define UART_DLM        0
  #define UART_DLL        1
  #define UART_MULVAL     8
  #define UART_DIVADDVAL  5
#endif
#endif
	/*
****************************************************************
* UART Init
****************************************************************
*/

#define _BAUDDIVIDE ((PCLK_UART+BAUDRATE*8L)/(BAUDRATE*16L))

  // Setup Port-Mode to alternate function
  _PINSEL0  |= _PINSEL_UART_MODE;       // Set UART-port to alt func

  _PCONP    |= (1 << _UART_PCONP_BIT);  // Enable UART unit
  _UART_IER  = 0x00;           // Initially disable all interrupts
  _UART_LCR  = 0x80;           // Set DLAB to init Baudrate gen

#ifdef UART_MULVAL             // This mcu has fraction divider
  _UART_DLM = UART_DLM;        // MSB of baud divider
  _UART_DLL = UART_DLL;        // LSB of baud divider
  _UART_FDR = (UART_MULVAL<<4) | UART_DIVADDVAL;
#else
  _UART_DLL  = (_BAUDDIVIDE & 0xFF);
  _UART_DLM  = ((_BAUDDIVIDE >> 8) & 0xFF);
#endif

  _UART_LCR &= ~0x80;          // reset DLAB to lock baudrate gen access
  _UART_LCR  = 0x03            // 8 data bits
                 |(0 << 2)     // 1 stop bit
                 |(0 << 3)     // NO parity
                 |(0 << 4)     // Parity setting (bit 5:4) does not care
                 |(0 << 6)     // Disable Break transmission
                 |(0 << 7);    // Clear DLAB

//  _UART_FCR  = 0;            // Disable FIFO
  _UART_FCR  = 3;              // Enable FIFO