EmbeddedRelated.com
Forums

UART stuck waiting for THRE

Started by mattwoolsey May 10, 2008
This should work but it doesn't. I'm just running the simple
blinky.c example, but my UART 0 gets stuck waiting for the tranmit
hold register empty bit to set:

//-------------------------------
#include

void init_serial (void)
{
PINSEL0 = 0x00000005;
UxLCR = 0x83;
UxDLL = (VPB_CLOCK/16/BAUD_RATE) & 0xFF;
UxDLM = ((VPB_CLOCK/16/BAUD_RATE) >> 8) & 0xFF;
UxLCR = 0x03;
}

int sendchar (int ch)
{
while (!(U0LSR & 0x20)); <------------ stuck here!!!

return (UxTHR = ch);
}
//-------------------------------

>From main, I'm calling init_serial, then calling sendchar a few
times. Only the first character comes out the serial port. If I
comment out the while loop waiting for the THRE bit, then all the
characters print just fine. Is this a bug in the LPC2103 or maybe a
compiler problem with the Keil Realview compiler? Or am I just
missing something really simple?

Thanks for any help.

MX

An Engineer's Guide to the LPC2100 Series

> while (!(U0LSR & 0x20)); <------------ stuck here!!!

Hi MX

Reading the status register will reset any flags in it. This would get
stuck if the flag was cleared previously due to a read (this can
happen when working with a debugger which is displaying the register
since it can read and reset flags before the code gets to this point).

Otherwise this routine should spin until the flag is det due to a
previous character being complete. However check that the register is
really being handled as a volatile register (check header). If this is
not the case some optimisers will cause the register to be read once
and then spin on its first value, thus never seeing the flag being set
(endlos loop resulting).

Regards

Mark

http://www.uTasker.com

> "Reading the status register will reset any flags in it"

No!
Only writes to U0THR will clear the 0x20 flag in U0LSR.

~ Paul Claessen

----- Original Message -----
From: "Mark Butcher"
To:
Sent: Saturday, May 10, 2008 2:21 PM
Subject: [lpc2000] Re: UART stuck waiting for THRE
> while (!(U0LSR & 0x20)); <------------ stuck here!!!

Hi MX

Reading the status register will reset any flags in it. This would get
stuck if the flag was cleared previously due to a read (this can
happen when working with a debugger which is displaying the register
since it can read and reset flags before the code gets to this point).

Otherwise this routine should spin until the flag is det due to a
previous character being complete. However check that the register is
really being handled as a volatile register (check header). If this is
not the case some optimisers will cause the register to be read once
and then spin on its first value, thus never seeing the flag being set
(endlos loop resulting).

Regards

Mark

http://www.uTasker.com

U0LSR is declared in the Keil "lpc21xx" header as:

#define U0LSR (*((volatile unsigned char *) 0xE000C014))

so it's already volatile.

MX
--- In l..., "Mark Butcher"
wrote:
>
> > while (!(U0LSR & 0x20)); <------------ stuck here!!!
>
> Hi MX
>
> Reading the status register will reset any flags in it. This would
get
> stuck if the flag was cleared previously due to a read (this can
> happen when working with a debugger which is displaying the register
> since it can read and reset flags before the code gets to this
point).
>
> Otherwise this routine should spin until the flag is det due to a
> previous character being complete. However check that the register
is
> really being handled as a volatile register (check header). If this
is
> not the case some optimisers will cause the register to be read once
> and then spin on its first value, thus never seeing the flag being
set
> (endlos loop resulting).
>
> Regards
>
> Mark
>
> http://www.uTasker.com
>

I got it to work by changing the sendchar parameter:

int sendchar(char ch)

instead of:

int sendchar(int ch)

Seems like the compiler should have promoted char parameters to int
and worked just fine, but apparently the compiler is doing something
strange with it.

MX
--- In l..., "mattwoolsey"
wrote:
>
> This should work but it doesn't. I'm just running the simple
> blinky.c example, but my UART 0 gets stuck waiting for the tranmit
> hold register empty bit to set:
>
> //------------------------------
-
> #include void init_serial (void)
> {
> PINSEL0 = 0x00000005;
> UxLCR = 0x83;
> UxDLL = (VPB_CLOCK/16/BAUD_RATE) & 0xFF;
> UxDLM = ((VPB_CLOCK/16/BAUD_RATE) >> 8) & 0xFF;
> UxLCR = 0x03;
> }
>
> int sendchar (int ch)
> {
> while (!(U0LSR & 0x20)); <------------ stuck here!!!
>
> return (UxTHR = ch);
> }
> //------------------------------
-
>
> From main, I'm calling init_serial, then calling sendchar a few
> times. Only the first character comes out the serial port. If I
> comment out the while loop waiting for the THRE bit, then all the
> characters print just fine. Is this a bug in the LPC2103 or maybe
a
> compiler problem with the Keil Realview compiler? Or am I just
> missing something really simple?
>
> Thanks for any help.
>
> MX
>

That doesn't make any sense.
Did you get my email? (request for zipped up project files)

~ Paul Claessen

----- Original Message -----
From: "mattwoolsey"
To:
Sent: Saturday, May 10, 2008 3:27 PM
Subject: [lpc2000] Re: UART stuck waiting for THRE
I got it to work by changing the sendchar parameter:

int sendchar(char ch)

instead of:

int sendchar(int ch)

Seems like the compiler should have promoted char parameters to int
and worked just fine, but apparently the compiler is doing something
strange with it.

MX
--- In l..., "mattwoolsey"
wrote:
>
> This should work but it doesn't. I'm just running the simple
> blinky.c example, but my UART 0 gets stuck waiting for the tranmit
> hold register empty bit to set:
>
> //------------------------------
-
> #include void init_serial (void)
> {
> PINSEL0 = 0x00000005;
> UxLCR = 0x83;
> UxDLL = (VPB_CLOCK/16/BAUD_RATE) & 0xFF;
> UxDLM = ((VPB_CLOCK/16/BAUD_RATE) >> 8) & 0xFF;
> UxLCR = 0x03;
> }
>
> int sendchar (int ch)
> {
> while (!(U0LSR & 0x20)); <------------ stuck here!!!
>
> return (UxTHR = ch);
> }
> //------------------------------
-
>
> From main, I'm calling init_serial, then calling sendchar a few
> times. Only the first character comes out the serial port. If I
> comment out the while loop waiting for the THRE bit, then all the
> characters print just fine. Is this a bug in the LPC2103 or maybe
a
> compiler problem with the Keil Realview compiler? Or am I just
> missing something really simple?
>
> Thanks for any help.
>
> MX
>

Doesn't make sense to me either.

Sorry, didn't get your email. I'm working at home today and the
email goes to work. I'm just checking for responses on yahoo.

I'll send you a zipped copy to try.

Thanks,

MX
--- In l..., "Paul Claessen" wrote:
>
> That doesn't make any sense.
> Did you get my email? (request for zipped up project files)
>
> ~ Paul Claessen
>
> ----- Original Message -----
> From: "mattwoolsey"
> To:
> Sent: Saturday, May 10, 2008 3:27 PM
> Subject: [lpc2000] Re: UART stuck waiting for THRE
> I got it to work by changing the sendchar parameter:
>
> int sendchar(char ch)
>
> instead of:
>
> int sendchar(int ch)
>
> Seems like the compiler should have promoted char parameters to int
> and worked just fine, but apparently the compiler is doing
something
> strange with it.
>
> MX
> --- In l..., "mattwoolsey"
> wrote:
> >
> > This should work but it doesn't. I'm just running the simple
> > blinky.c example, but my UART 0 gets stuck waiting for the
tranmit
> > hold register empty bit to set:
> >
> > //----------------------------
--
> -
> > #include
> >
> > void init_serial (void)
> > {
> > PINSEL0 = 0x00000005;
> > UxLCR = 0x83;
> > UxDLL = (VPB_CLOCK/16/BAUD_RATE) & 0xFF;
> > UxDLM = ((VPB_CLOCK/16/BAUD_RATE) >> 8) & 0xFF;
> > UxLCR = 0x03;
> > }
> >
> > int sendchar (int ch)
> > {
> > while (!(U0LSR & 0x20)); <------------ stuck here!!!
> >
> > return (UxTHR = ch);
> > }
> > //----------------------------
--
> -
> >
> > From main, I'm calling init_serial, then calling sendchar a few
> > times. Only the first character comes out the serial port. If I
> > comment out the while loop waiting for the THRE bit, then all the
> > characters print just fine. Is this a bug in the LPC2103 or
maybe
> a
> > compiler problem with the Keil Realview compiler? Or am I just
> > missing something really simple?
> >
> > Thanks for any help.
> >
> > MX
>
At 07:27 PM 5/10/2008 +0000, mattwoolsey wrote:
>I got it to work by changing the sendchar parameter:
>
> int sendchar(char ch)
>
>instead of:
>
> int sendchar(int ch)
>
>Seems like the compiler should have promoted char parameters to int
>and worked just fine, but apparently the compiler is doing something
>strange with it.

Could be a sign problem

> > return (UxTHR = ch);

This will first convert UxTHR to an int before comparing to ch. Depending
on how you get ch you might get a different value in.

For instance if chars are signed and UxTHR is declared as unsigned char
there will be a mismatch on any character with the high bit set.

I know PC-Lint will catch this, I know some commercial compilers won't and
I know some developers will think a warning on signed/unsigned comparisons
is not worth checking.

Robert

"A million lines of code costs $20m to $40m ..... a million times
the cost of the flash chips it lives in. .... Yet accounting screams
over each added penny in recurring costs, while chanting the
dual mantras 'software is free,' and 'hey, it's only a software
change.'" Jack Ganssle in "A Million Lines of Code"

Robert Adsett - http://www.aeolusdevelopment.com/

The value of 'ch' is irrelevant for this problem.
Even if there was a sign problem, even if the compiler decided to generate a random value, the UART
still should simply send whatever it was it got.
Besides, it works the first time, he sees the character coming out the UART, and then the next time
it HANGS in a loop that doesn't even address the 'ch' parameter!

Must be something else...

~ Paul Claessen
----- Original Message -----
From: "Robert Adsett"
To: ;
Sent: Saturday, May 10, 2008 4:06 PM
Subject: Re: [lpc2000] Re: UART stuck waiting for THRE
> At 07:27 PM 5/10/2008 +0000, mattwoolsey wrote:
>>I got it to work by changing the sendchar parameter:
>>
>> int sendchar(char ch)
>>
>>instead of:
>>
>> int sendchar(int ch)
>>
>>Seems like the compiler should have promoted char parameters to int
>>and worked just fine, but apparently the compiler is doing something
>>strange with it.
>
> Could be a sign problem
>
>> > return (UxTHR = ch);
>
> This will first convert UxTHR to an int before comparing to ch. Depending
> on how you get ch you might get a different value in.
>
> For instance if chars are signed and UxTHR is declared as unsigned char
> there will be a mismatch on any character with the high bit set.
>
> I know PC-Lint will catch this, I know some commercial compilers won't and
> I know some developers will think a warning on signed/unsigned comparisons
> is not worth checking.
>
> Robert
>
> "A million lines of code costs $20m to $40m ..... a million times
> the cost of the flash chips it lives in. .... Yet accounting screams
> over each added penny in recurring costs, while chanting the
> dual mantras 'software is free,' and 'hey, it's only a software
> change.'" Jack Ganssle in "A Million Lines of Code"
>
> Robert Adsett - http://www.aeolusdevelopment.com/
>
That's not a comparison. It is writing ch to UxTHR. Besides, the
problem is in the previous line with the while loop.
The assembly of the bad code looks like this:

//------------------

sendchar PROC
;;;82 //int sendchar (char ch)
;;;83 { /* Write character to Serial Port */
000034 e1a01000 MOV r1,r0
;;;84
;;;85 while (!(UxLSR & 0x20));
000038 e1a00000 MOV r0,r0
|L1.60|
00003c e59f003c LDR r0,|L1.128|
000040 e5d00014 LDRB r0,[r0,#0x14]
000044 e3100020 TST r0,#0x20
000048 0afffffb BEQ |L1.60|
;;;86
;;;87 return (UxTHR = ch);
00004c e20100ff AND r0,r1,#0xff
000050 e59f2028 LDR r2,|L1.128|
000054 e5c20000 STRB r0,[r2,#0]
;;;88 }
000058 e12fff1e BX lr
;;;89
ENDP

|L1.128|
000080 e000c000 DCD 0xe000c000

//--------

The assembly for the while loop looks ok to me, although I haven't
done a lot of ARM assembly.

And here's the working version:

//--------

sendchar PROC
;;;84
;;;85 while (!(UxLSR & 0x20));
000034 e1a00000 MOV r0,r0
|L1.56|
000038 e59f1038 LDR r1,|L1.120|
00003c e5d11014 LDRB r1,[r1,#0x14]
000040 e3110020 TST r1,#0x20
000044 0afffffb BEQ |L1.56|
;;;86
;;;87 return (UxTHR = ch);
000048 e59f1028 LDR r1,|L1.120|
00004c e5c10000 STRB r0,[r1,#0]
;;;88 }
000050 e12fff1e BX lr
;;;89
ENDP

|L1.120|
000078 e000c000 DCD 0xe000c000
//--------

MX
--- In l..., Robert Adsett
wrote:
>
...
>
> Could be a sign problem
>
> > > return (UxTHR = ch);
>
> This will first convert UxTHR to an int before comparing to ch.
Depending
> on how you get ch you might get a different value in.
>
> For instance if chars are signed and UxTHR is declared as unsigned
char
> there will be a mismatch on any character with the high bit set.
>
> I know PC-Lint will catch this, I know some commercial compilers
won't and
> I know some developers will think a warning on signed/unsigned
comparisons
> is not worth checking.
>
> Robert
>