EmbeddedRelated.com
Forums
Memfault Beyond the Launch

UART1 problem receiving but ok transmitt

Started by fredrikssonjohan August 16, 2006
Hi!

I'm stucked with this and can't figure out why it will not work.
Anyone seeing the obvious or have any friendly ideas of what might be
wrong?

OK. I'll try to give an as good description as possible of what I have
and try do. The first problem is that if I send, as a test, 8 "A" I
will get 4 or 5 "A"s in return and then one or two non ascii visible
chars and mostly a FF as end. I would say the successrate is 3-4 per
20 sent blocks of 8 "A". So there is my problem. No clean RX on the
LPC2106 with this MAX1480B.

There is a LPC2106 connected via a 74HC86 and finally the Maxim
MAX1480B opto/power isolated circuit. This is all connected as per
MAXIMSs datasheet and work 100% when sending data. Never miss a single
bit.
As I never have any TX problem I figure that the init part of the port
should be OK.

As a stripped down testing routine I do the following:
while (1)
{
cbuff[icnt] = wait_and_receive();
icnt++;

if (icnt == 8)
{
icnt = 0;
IOSET = (1< pause(TWO_MS);
for (int j = 0; j < 8; j++)
uart1Putch(cbuff[j]);

// Back to RX mode again
IOCLR = (1< pause(TWO_MS);
}
}

Im just waiting for any char in the RX buffer and switch to RS486 TX
mode and send it back. Added a small delay after switching mode on the
RS485 line just to be sure.

Using this bit just for pool until there is a char available
int wait_and_receive(void)
{
int ch;

while((ch = uart1Getch()) == -1) {
;
}
return ch;
}

And this is the actual code checking if the is a char available.
The uart1Getch(...) loooks like this:
if (U1LSR & ULSR_RDR) // check if character is available
return U1RBR; // return character
return -1;

The init is done by this and works perfect for TX
void uart1Init(uint16_t baud, uint8_t mode, uint8_t fmode)
{
// set port pins for UART1
PINSEL0 = (PINSEL0 & ~U1_PINMASK) | U1_PINSEL;

U1IER = 0x00; // disable all interrupts
U1IIR; // clear interrupt ID
U1RBR; // clear receive register
U1LSR; // clear line status register

// set the baudrate
U1LCR = ULCR_DLAB_ENABLE; // select divisor latches
U1DLL = (uint8_t)baud; // set for baud low byte
U1DLM = (uint8_t)(baud >> 8); // set for baud high byte
U1LCR = (mode & ~ULCR_DLAB_ENABLE);
U1FCR = fmode;
}

Wow, sorry for the long message and code, but otherwise I guess
someone is asking how that and that is done so I include it from the
start.

If anyone have a clue or idea I would be very happy guy!

Cheers
Johan

An Engineer's Guide to the LPC2100 Series

--- In l..., "fredrikssonjohan" wrote:
> The init is done by this and works perfect for TX
> void uart1Init(uint16_t baud, uint8_t mode, uint8_t fmode)
> {
> // set port pins for UART1
> PINSEL0 = (PINSEL0 & ~U1_PINMASK) | U1_PINSEL;
>
> U1IER = 0x00; // disable all interrupts
> U1IIR; // clear interrupt ID
> U1RBR; // clear receive register
> U1LSR; // clear line status
register

Johan,

What do you expect the last three lines of code above to do? A lot
depends on how the MACROs are defined, but my guess is that they do
nothing, as no assignment is made. Having siad that, I doubt that's
your main problem.

I'd suggest:

1. Try something much simpler to test with. For example, program 1:
init UART, then loop sending single character, wait for a time (say 1
second), send another character, wait, etc. Program 2: init UART,
loop receiving chracaters, providing some feedback when they're
received (e.g. flash LED or whatever you have available).

2. Try something known to work. You don't say what tools you use, but
most have examples, or if not there are plenty available. Do these
work with your h/w?

In other words, follow the strategy of:

- simple tests before complex ones
- start with something that's known to work, and build from there
- one change at a time

Hope this helps!

Brendan
Silly question perhaps, but have you attached a scope quickly to actually
check you're receiving data to the pin and are you sure of the baud rates
you're setting up as we can't see what 'baud' actually is? We also can't see
U1_PINMASK or U1PINSEL so it's hard to go through the code.

Andy

-----Original Message-----
From: l... [mailto:l...]On Behalf Of
fredrikssonjohan
Sent: 16 August 2006 10:49
To: l...
Subject: [lpc2000] UART1 problem receiving but ok transmitt
Hi!

I'm stucked with this and can't figure out why it will not work.
Anyone seeing the obvious or have any friendly ideas of what might be
wrong?

OK. I'll try to give an as good description as possible of what I have
and try do. The first problem is that if I send, as a test, 8 "A" I
will get 4 or 5 "A"s in return and then one or two non ascii visible
chars and mostly a FF as end. I would say the successrate is 3-4 per
20 sent blocks of 8 "A". So there is my problem. No clean RX on the
LPC2106 with this MAX1480B.

There is a LPC2106 connected via a 74HC86 and finally the Maxim
MAX1480B opto/power isolated circuit. This is all connected as per
MAXIMSs datasheet and work 100% when sending data. Never miss a single
bit.
As I never have any TX problem I figure that the init part of the port
should be OK.

As a stripped down testing routine I do the following:
while (1)
{
cbuff[icnt] = wait_and_receive();
icnt++;

if (icnt == 8)
{
icnt = 0;
IOSET = (1< pause(TWO_MS);
for (int j = 0; j < 8; j++)
uart1Putch(cbuff[j]);

// Back to RX mode again
IOCLR = (1< pause(TWO_MS);
}
}

Im just waiting for any char in the RX buffer and switch to RS486 TX
mode and send it back. Added a small delay after switching mode on the
RS485 line just to be sure.

Using this bit just for pool until there is a char available
int wait_and_receive(void)
{
int ch;

while((ch = uart1Getch()) == -1) {
;
}
return ch;
}

And this is the actual code checking if the is a char available.
The uart1Getch(...) loooks like this:
if (U1LSR & ULSR_RDR) // check if character is available
return U1RBR; // return character
return -1;

The init is done by this and works perfect for TX
void uart1Init(uint16_t baud, uint8_t mode, uint8_t fmode)
{
// set port pins for UART1
PINSEL0 = (PINSEL0 & ~U1_PINMASK) | U1_PINSEL;

U1IER = 0x00; // disable all interrupts
U1IIR; // clear interrupt ID
U1RBR; // clear receive register
U1LSR; // clear line status register

// set the baudrate
U1LCR = ULCR_DLAB_ENABLE; // select divisor latches
U1DLL = (uint8_t)baud; // set for baud low byte
U1DLM = (uint8_t)(baud >> 8); // set for baud high byte
U1LCR = (mode & ~ULCR_DLAB_ENABLE);
U1FCR = fmode;
}

Wow, sorry for the long message and code, but otherwise I guess
someone is asking how that and that is done so I include it from the
start.

If anyone have a clue or idea I would be very happy guy!

Cheers
Johan
--- In l..., "fredrikssonjohan" wrote:
> ... No clean RX on the LPC2106 with this MAX1480B.
>
> [polled uart read implementation]
>
> If anyone have a clue or idea I would be very happy guy!
>
> Cheers
> Johan

Johan, there is a known race condition on LPC architecture that causes
asynchronous updates of peripheral status registers to fail if the CPU
so happens to be reading the same register at the same time.

For example when a character arrives and the asynchronous UART logic
is attempting to set the DR bit of LSR and the CPU so happens to be
reading the register at the same time, the DR bit is lost.

Deterministic experiments demonstrate that this behaviour is
particular and sensitive to specific baud rates -- for example it
fails at 300 baud, but works at 299 or 301 baud.

I suspect you are seeing one or both of the above problems. There may
well be other problems in the code that a code walk through would weed
out. I suggest you try a slightly different baud rate to see if it
works any differently.

The only real work around to the problems I mentioned above is not to
poll the UART, but make it interrupt driven, and hope that the
asynchronous update of the status register will not happen when your
ISR is reading the LSR.

Hope this helps.

Jaya
Umm... Not very sure what's happening...
But there are lots of things to check...
- Should use TEMT status bit to control RX485 direction (to disable
transmitter), the transmitting character gets slowly shifted out
after you wrote it to UART. You can't disable transmitter
immediately after the putchar(). More characters will be stuck
in transmitting UART if your fifo is ON.
- Depending on your circuit, there could be echo back of serial data
to receiver when you are transmitting. => Need to clean up your
test program a bit.
- Some parts like TI SN75176 creates a small glitch (normally gets
filtered off by receiving UART) on the line when transmitter gets
disabled, (some short period of time with both + and - lines
forced high). You are using isolated RS485 with opto-isolators
inside the chip, I have no experience if there is more glitches.
- And remembers if your fifo is ON, and if you have echo, The test
data sent out in the previous loop will be captured in the current
program loop

Should do like what there other 2 guys are suggesting:
- Simplify the program. Go step by step
- Use scope to check signals.

Hope it helps.
Regards

--- In l..., "Brendan Murphy"
wrote:
>
> --- In l..., "fredrikssonjohan" wrote:
> > The init is done by this and works perfect for TX
> > void uart1Init(uint16_t baud, uint8_t mode, uint8_t fmode)
> > {
> > // set port pins for UART1
> > PINSEL0 = (PINSEL0 & ~U1_PINMASK) | U1_PINSEL;
> >
> > U1IER = 0x00; // disable all interrupts
> > U1IIR; // clear interrupt ID
> > U1RBR; // clear receive register
> > U1LSR; // clear line status
> register
>
> Johan,
>
> What do you expect the last three lines of code above to do? A lot
> depends on how the MACROs are defined, but my guess is that they
do
> nothing, as no assignment is made. Having siad that, I doubt
that's
> your main problem.
>
> I'd suggest:
>
> 1. Try something much simpler to test with. For example, program
1:
> init UART, then loop sending single character, wait for a time
(say 1
> second), send another character, wait, etc. Program 2: init UART,
> loop receiving chracaters, providing some feedback when they're
> received (e.g. flash LED or whatever you have available).
>
> 2. Try something known to work. You don't say what tools you use,
but
> most have examples, or if not there are plenty available. Do these
> work with your h/w?
>
> In other words, follow the strategy of:
>
> - simple tests before complex ones
> - start with something that's known to work, and build from there
> - one change at a time
>
> Hope this helps!
>
> Brendan
>
--- In l..., "jayasooriah"
wrote:
>
> --- In l..., "fredrikssonjohan" wrote:
> > ... No clean RX on the LPC2106 with this MAX1480B.
> >
> > [polled uart read implementation]
> >
> > If anyone have a clue or idea I would be very happy guy!
> >
> > Cheers
> > Johan
>
> Johan, there is a known race condition on LPC architecture that
causes
> asynchronous updates of peripheral status registers to fail if the
CPU
> so happens to be reading the same register at the same time.
>
> For example when a character arrives and the asynchronous UART
logic
> is attempting to set the DR bit of LSR and the CPU so happens to be
> reading the register at the same time, the DR bit is lost.
>

This race condition (see the errata) only applies to the error bits
of the LSR. Since these are only set when error conditions are
present in any case, the impact of this is minimal.

The original poster's problems are almost certainly the usual issues
of errors in hardware design or build or errors in sofware control
of the device.

> Deterministic experiments demonstrate that this behaviour is
> particular and sensitive to specific baud rates -- for example it
> fails at 300 baud, but works at 299 or 301 baud.
>
> I suspect you are seeing one or both of the above problems. There
may
> well be other problems in the code that a code walk through would
weed
> out. I suggest you try a slightly different baud rate to see if it
> works any differently.
>
> The only real work around to the problems I mentioned above is not
to
> poll the UART, but make it interrupt driven, and hope that the
> asynchronous update of the status register will not happen when
your
> ISR is reading the LSR.

If this were true, the UART would be pretty much useless. Many, many
people's experience tells us that this is not the case.

Unless there's someone else out there who can confirm the behaviour
you've seen, Jaya, the problem you describe is most likely specific
to your own particular system, rather than some undocumented flaw in
the device (i.e. DR bit not set in LSR).

Brendan.
--- In l..., "Brendan Murphy"
> This race condition (see the errata) only applies to the error bits
> of the LSR. Since these are only set when error conditions are
> present in any case, the impact of this is minimal.

There is no point denying what Philips has admitted it its errata
sheets. In the statement:


If hardware is setting one of these above bits while the software is
reading the contents of the register the reading process clears all
bits in the register including the bit that got set by hardware. The
software reads the old value though and the bit that got set by
hardware is lost.


the "above bits" refers to what is listed in the paragraph above, and
this includes more bits than just just the error bits. Not to mention
RDA and RDT bits problem that is dressed up as an application note IIRC.

If you look at the pattern in the erratas, you will see this is a
generic problem at the perhipheral bus level, not just to specific
registers in specific peripherals.

> If this were true, the UART would be pretty much useless. Many, many
> people's experience tells us that this is not the case.

All it takes is just one deterministic experiment to demonstrate if
there is an error and the results (independently verified) speak for
themselves.

You need professional equipment and formal testing regime to validate
errors of the kind we find in LPC, for example, one that manifests at
300 baud but not at 299 or 301 baud, and another "incorrect shifting
at low frequencies" for the SPI.

Jaya
--- In l..., "jayasooriah" wrote:
>
> --- In l..., "Brendan Murphy"
> > This race condition (see the errata) only applies to the error
bits
> > of the LSR. Since these are only set when error conditions are
> > present in any case, the impact of this is minimal.
>
> There is no point denying what Philips has admitted it its errata
> sheets. In the statement:
>
>
> If hardware is setting one of these above bits while the software is
> reading the contents of the register the reading process clears all
> bits in the register including the bit that got set by hardware. The
> software reads the old value though and the bit that got set by
> hardware is lost.
>
>
> the "above bits" refers to what is listed in the paragraph above,
and
> this includes more bits than just just the error bits. Not to
mention
> RDA and RDT bits problem that is dressed up as an application note
IIRC.
>

You're ignoring the precedent text, which is:



Reading the contents of the IIR,LSR and MSR registers will clear
certain bits in the register.

1. Reading the IIR should clear the THRE status if THRE is the
highest priority pending interrupt (Only affects UART1).

2. Reading LSR should clear the OE/PE/FE/BI bits (affects both UART0
and UART1).

3. Reading MSR should clear the Delta DCD/Trailing Edge RI/Delta
DSR/Delta CTS bits (Only affects UART1).

Problem: If hardware is setting one of these above bits[continues as
you quoted]



It is quite clear from the above which bits are affected: DR is not
one of them, as you claim.

> If you look at the pattern in the erratas, you will see this is a
> generic problem at the perhipheral bus level, not just to specific
> registers in specific peripherals.
>
> > If this were true, the UART would be pretty much useless. Many,
many
> > people's experience tells us that this is not the case.
>
> All it takes is just one deterministic experiment to demonstrate if
> there is an error and the results (independently verified) speak for
> themselves.
>
> You need professional equipment and formal testing regime to
validate
> errors of the kind we find in LPC, for example, one that manifests
at
> 300 baud but not at 299 or 301 baud, and another "incorrect shifting
> at low frequencies" for the SPI.
>

Anyone developing commercial products seriously would need such
equipment and regimes. There's plenty of them out there at this stage
with LPC2xxx products in development and production.

If anyone else can reproduce your results, I'm sure everyone here
would like to hear about it.

Brendan.



--- In l..., "Brendan Murphy"
wrote:

> It is quite clear from the above which bits are affected: DR is not
> one of them, as you claim.

It is quite clear that the problem is not restricted to error bits as
you cliam. That is my point.

You have to ask yourself if DR is set when there is a framing or
parity error, and if FE or PE is lost, what happens to the DR bit.

You also have to ask yourself the what happens when the FIFO is 16
deep, but there is only one status register with the error and DR bits.

> If anyone else can reproduce your results, I'm sure everyone here
> would like to hear about it.

If anyone is not able to reproduce my results, I am sure everyone here
would have heard about it. Have you?

Jaya
--- In l..., "jayasooriah" wrote:
>
> --- In l..., "Brendan Murphy"
> wrote:
>
> > It is quite clear from the above which bits are affected: DR is
not
> > one of them, as you claim.
>
> It is quite clear that the problem is not restricted to error bits
as
> you cliam. That is my point.
>
> You have to ask yourself if DR is set when there is a framing or
> parity error, and if FE or PE is lost, what happens to the DR bit.
>
> You also have to ask yourself the what happens when the FIFO is 16
> deep, but there is only one status register with the error and DR
bits.

This is pointless: the text is there for anyone to read.

>
> > If anyone else can reproduce your results, I'm sure everyone here
> > would like to hear about it.
>
> If anyone is not able to reproduce my results, I am sure everyone
here
> would have heard about it. Have you?

See the following for some comprehensive test results, including some
tests using your own test program:

http://groups.yahoo.com/group/lpc2000/message/17727

and also:

http://groups.yahoo.com/group/lpc2000/message/17783

I've nothing more to say on this: the arguments have been thrashed to
death already.

Brendan

Memfault Beyond the Launch