LPC11U14 and USART (UART) problem

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

LPC11U14 and USART (UART) problem

1,285件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by fjarnjak on Tue Jul 10 23:38:01 MST 2012
Hello all,

I have noticed a strange problem on USART for LPC11U14 MCU (LPCXpresso board).

If I use this loop in main() method to send some string and watch TX using protocol analyzer I get correct string output.

 
while(1)
{
    UARTSend(buff, 4);
    sleep_ms(10); // If removed -> garbage out ?!?
}
 


If I [B]***remove***[/B] sleep_ms(10); call I get garbage out....framing errors being reported on the other side, etc. Same if I connect a real device and not a protocol analyzer (logic analyzer).

10ms, 100ms sleep is OK. I didn't go lower than 10ms to experiment.

Code for UART is basically from example....

[B]UART Init code:[/B]
void UARTInit(uint32_t baudrate)
{
  LPC_SYSCON->SYSAHBCLKCTRL |= (1<<16); /* Enable IOCON block */
  LPC_IOCON->PIO0_18 &= ~0x07;    /*  UART I/O config */
  LPC_IOCON->PIO0_18 |= 0x01;     /* UART RXD */
  LPC_IOCON->PIO0_19 &= ~0x07;
  LPC_IOCON->PIO0_19 |= 0x01;     /* UART TXD */
  /* Enable UART clock */
  LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12);
  LPC_SYSCON->UARTCLKDIV = 0x1;     /* divided by 1 */
  LPC_USART->LCR = 0x83;             /* 8 bits, no Parity, 1 Stop bit */
  regVal = LPC_SYSCON->UARTCLKDIV;
  Fdiv = ((SystemCoreClock/regVal)/16)/baudrate ;    /*baud rate */
  LPC_USART->DLM = Fdiv / 256;
  LPC_USART->DLL = Fdiv % 256;
  LPC_USART->LCR = 0x03;        /* DLAB = 0 */
  LPC_USART->FCR = 0x07;        /* Enable and reset TX and RX FIFO. */
  /* Read to clear the line status. */
  regVal = LPC_USART->LSR;
  /* Ensure a clean start, no data in either TX or RX FIFO. */
  while (( LPC_USART->LSR & (LSR_THRE|LSR_TEMT)) != (LSR_THRE|LSR_TEMT) );
  while ( LPC_USART->LSR & LSR_RDR )
  {
    regVal = LPC_USART->RBR;    /* Dump data from RX FIFO */
  }
}
 


[B] Sending function:[/B]
void UARTSend(uint8_t *BufferPtr, uint32_t Length)
{
  //while ( !(LPC_USART->LSR & LSR_TEMT) );
  while ( Length != 0 )
  {
      while ( !(LPC_USART->LSR & LSR_THRE) );
      LPC_USART->THR = *BufferPtr;
      BufferPtr++;
      Length--;
  }
  return;
}


This code above seems not to block on while ( !(LPC_USART->LSR & LSR_THRE) ); in subsequent calls to the function when there is no sleep_ms(10); Otherwise, I would not get garbage but I would get data appened one after the other (or strings...).

I also put another while (now commented out) at the beggining to ensure TX FIFO is empty, but same thing happens. So I commented it out.

Also, when I get garbage, my protocol analyzer reports some strange baud rate (high like 33000 bps).

With sleep it works fine - selected baud rate is discovered one. 
I have tested above at 9600, 38400 and 57600 bps. CPU is @ 48MHZ.

Any suggestions?
0 件の賞賛
返信
6 返答(返信)

1,212件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by fjarnjak on Wed Jul 11 04:27:46 MST 2012

Quote: gbm
If you are sending characters continuously, there is no way for the receiver to recognize the real start of a character unless the receiver starts listening before the transmission of the first character starts. If you start the transmitter and then the receiver, the receiver will treat the first high-to-low transition as a start bit. It may be the real start bit or any transition in the middle of a character.

Your problem is NOT LPC-specific. That's how every UART works.



Hm....didn't think about that - I will check.
0 件の賞賛
返信

1,212件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by gbm on Wed Jul 11 04:11:55 MST 2012
If you are sending characters continuously, there is no way for the receiver to recognize the real start of a character unless the receiver starts listening before the transmission of the first character starts. If you start the transmitter and then the receiver, the receiver will treat the first high-to-low transition as a start bit. It may be the real start bit or any transition in the middle of a character.

Your problem is NOT LPC-specific. That's how every UART works.
0 件の賞賛
返信

1,212件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by fjarnjak on Wed Jul 11 03:04:25 MST 2012
Just for test I have made this small loop:

while(1)
{
 while ( !(LPC_USART->LSR & LSR_THRE) );
   LPC_USART->THR = 'A';
}

One would expect a stream of A charachters coming on the TX......but you get garbage.
If you put some sleep inside the outer while(1) loop, then it works fine.
I never experienced this on AVRs for example.....UART is like basic thing....
0 件の賞賛
返信

1,212件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by fjarnjak on Wed Jul 11 01:16:59 MST 2012

Quote: frame
That's pretty normal.

Your send function take care not to mess up characters, but what about your send buffer ?

There are no precautions to stack up send requests, i.e. queueing up your send buffers.
Each subsequent call hits the preceding somewhere in the middle, overwriting your send buffer pointer.

When inserting the delay, you start the next send only after the last one finished, so no problem...



I would not agree.

I am waiting for the bit 5 to be set on the usart LSR register.
As per datasheet:


[I]THRE Transmitter Holding Register Empty. [/I]
[I]THRE is set immediately [/I]
[I]upon detection of an empty USART THR and is cleared on a [/I]
[I]THR write[/I]


And THR is:

Transmit Holding Register. The next character to be
transmitted is written here. (DLAB=0)

The fact that they go to FIFO in the UART controller and char is put into it and THR becomes empty quickly, or the charachter is immediately send on the TX line or whatever should not be a concern for the firmware programmer, because I am feeding it byte by byte whenever THRE is set so I can put a new byte in (THR is empty). Basically it should block until I can safely put next byte in, which means if I am feeding it too quickly it would wait until TX FIFO has at least 1 byte available space (out of 16) so it can, set THRE and then it would accept next byte. No corruption should happen!

Seems other people complained about it - other thread linked above your answer - and that was in 2011 also in July. Was there any official NXP reply onto this?

And a call to the Send() function would not return until all 4 bytes are succesfully send (either to FIFO or to the TX line/pin). Only then in while(1) loop another call to Send() would occur. It's not like I have 2 threads and concurrent access/call to Send() function.

And blocking inside Send() is/should be provided by:

[B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]while[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2] ( !(LPC_USART->LSR & LSR_THRE) );[/SIZE]
0 件の賞賛
返信

1,212件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by frame on Wed Jul 11 00:23:14 MST 2012
That's pretty normal.

Your send function take care not to mess up characters, but what about your send buffer ?

There are no precautions to stack up send requests, i.e. queueing up your send buffers.
Each subsequent call hits the preceding somewhere in the middle, overwriting your send buffer pointer.

When inserting the delay, you start the next send only after the last one finished, so no problem...
0 件の賞賛
返信

1,212件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ex-kayoda on Wed Jul 11 00:13:16 MST 2012

Quote: fjarnjak
Any suggestions?



Try http://knowledgebase.nxp.com/showthread.php?t=2231 :)
0 件の賞賛
返信