Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[ARM] Problem with long strings in UART

Status
Not open for further replies.

vikky

Full Member level 3
Full Member level 3
Joined
Oct 18, 2007
Messages
150
Helped
4
Reputation
8
Reaction score
3
Trophy points
1,298
Activity points
2,664
Hi all,

I am using a UART library to send and receive data.While i use shorter strings to capture the input data in the receive pin,the function works well.The UART Buffer is displaying the correct data.To be exact if receive more than 16 bytes of data the buffer gets corrupted and sometimes it behaves well and sometimes it misses the first character and last 5 characters.I am tring to send 20 bytes of data to the UART of LPC1227 through my PC.Kindly advice.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
#define BUFSIZE  100
volatile uint8_t  UARTBuffer0[100];
 
I am giving below the UART portion of the code.
 
/*****************************************************************************
** Function name:       UART_IRQHandler
**
** Descriptions:        UART interrupt handler
**
** parameters:          None
** Returned value:      None
**
*****************************************************************************/
void UART0_IRQHandler(void)
{
  uint8_t k,IIRValue, LSRValue;
  uint8_t Dummy = Dummy;
 
  IIRValue = LPC_UART0->IIR;
 
  IIRValue >>= 1;           /* skip pending bit in IIR */
  IIRValue &= 0x07;         /* check bit 1~3, interrupt identification */
  if (IIRValue == IIR_RLS)      /* Receive Line Status */
  {
    LSRValue = LPC_UART0->LSR;
    /* Receive Line Status */
    if (LSRValue & (LSR_OE | LSR_PE | LSR_FE | LSR_RXFE | LSR_BI))
    {
      /* There are errors or break interrupt */
      /* Read LSR will clear the interrupt */
      UARTStatus0 = LSRValue;
      Dummy = LPC_UART0->RBR;   /* Dummy read on RX to clear
                                interrupt, then bail out */
      return;
    }
    if (LSRValue & LSR_RDR) /* Receive Data Ready */
    {
      /* If no error on RLS, normal ready, save into the data buffer. */
      /* Note: read RBR will clear the interrupt */
      UARTBuffer0[UARTCount0++] = LPC_UART0->RBR;
      if (UARTCount0 == BUFSIZE)
      {
        UARTCount0 = 0;     /* buffer overflow */
 
      }
    }
  }
  else if (IIRValue == IIR_RDA) /* Receive Data Available */
  {
    /* Receive Data Available */
    UARTBuffer0[UARTCount0++] = LPC_UART0->RBR;
    if (UARTCount0 == BUFSIZE)
    {
      UARTCount0 = 0;       /* buffer overflow */
    }
  }
  else if (IIRValue == IIR_CTI) /* Character timeout indicator */
  {
    /* Character Time-out indicator */
    UARTStatus0 |= 0x100;       /* Bit 9 as the CTI error */
  }
  else if (IIRValue == IIR_THRE)    /* THRE, transmit holding register empty */
  {
    /* THRE interrupt */
    LSRValue = LPC_UART0->LSR;      /* Check status in the LSR to see if
                                valid data in U0THR or not */
    if (LSRValue & LSR_THRE)
    {
      UARTTxEmpty0 = 1;
    }
    else
    {
      UARTTxEmpty0 = 0;
    }
  }
  return;
}
 
/*****************************************************************************
** Function name:       UART_IRQHandler
**
** Descriptions:        UART interrupt handler
**
** parameters:          None
** Returned value:      None
**
*****************************************************************************/
void UART1_IRQHandler(void)
{
  uint8_t IIRValue, LSRValue;
  uint8_t Dummy = Dummy;
 
  IIRValue = LPC_UART1->IIR;
 
  IIRValue >>= 1;           /* skip pending bit in IIR */
  IIRValue &= 0x07;         /* check bit 1~3, interrupt identification */
  if (IIRValue == IIR_RLS)      /* Receive Line Status */
  {
    LSRValue = LPC_UART1->LSR;
    /* Receive Line Status */
    if (LSRValue & (LSR_OE | LSR_PE | LSR_FE | LSR_RXFE | LSR_BI))
    {
      /* There are errors or break interrupt */
      /* Read LSR will clear the interrupt */
      UARTStatus1 = LSRValue;
      Dummy = LPC_UART1->RBR;   /* Dummy read on RX to clear
                                interrupt, then bail out */
      return;
    }
    if (LSRValue & LSR_RDR) /* Receive Data Ready */
    {
      /* If no error on RLS, normal ready, save into the data buffer. */
      /* Note: read RBR will clear the interrupt */
      UARTBuffer1[UARTCount1++] = LPC_UART1->RBR;
      if (UARTCount1 == BUFSIZE)
      {
        UARTCount1 = 0;     /* buffer overflow */
      }
    }
  }
  else if (IIRValue == IIR_RDA) /* Receive Data Available */
  {
    /* Receive Data Available */
    UARTBuffer1[UARTCount1++] = LPC_UART1->RBR;
    if (UARTCount1 == BUFSIZE)
    {
      UARTCount1 = 0;       /* buffer overflow */
    }
  }
  else if (IIRValue == IIR_CTI) /* Character timeout indicator */
  {
    /* Character Time-out indicator */
    UARTStatus1 |= 0x100;       /* Bit 9 as the CTI error */
  }
  else if (IIRValue == IIR_THRE)    /* THRE, transmit holding register empty */
  {
    /* THRE interrupt */
    LSRValue = LPC_UART1->LSR;      /* Check status in the LSR to see if
                                valid data in U0THR or not */
    if (LSRValue & LSR_THRE)
    {
      UARTTxEmpty1 = 1;
    }
    else
    {
      UARTTxEmpty1 = 0;
    }
  }
  return;
}
 
/*****************************************************************************
** Function name:       ModemInit
**
** Descriptions:        Initialize UART0 port as modem, setup pin select.
**
** parameters:          location
** Returned value:      None
**
*****************************************************************************/
void ModemInit( uint32_t location )
{
  if ( location == 0 )
  {
    LPC_IOCON->PIO0_3 &= ~0x07;    /* UART I/O config */
    LPC_IOCON->PIO0_3 |= 0x02;     /* UART DTR output */
    LPC_IOCON->PIO0_7 &= ~0x07;
    LPC_IOCON->PIO0_7 |= 0x02;     /* UART CTS input */
    LPC_IOCON->PIO0_0 &= ~0x07;
    LPC_IOCON->PIO0_0 |= 0x02;     /* UART RTS output */
    LPC_IOCON->PIO0_4 &= ~0x07;
    LPC_IOCON->PIO0_4 |= 0x02;     /* UART DSR input */
    LPC_IOCON->PIO0_5 &= ~0x07;
    LPC_IOCON->PIO0_5 |= 0x02;     /* UART DCD input */
    LPC_IOCON->PIO0_6 &= ~0x07;
    LPC_IOCON->PIO0_6 |= 0x02;     /* UART RI input */
  }
  else if ( location == 1 )
  {
    LPC_IOCON->PIO2_3 &= ~0x07;    /* UART I/O config */
    LPC_IOCON->PIO2_3 |= 0x04;     /* UART DTR output */
    LPC_IOCON->PIO2_4 &= ~0x07;
    LPC_IOCON->PIO2_4 |= 0x04;     /* UART CTS input */
    LPC_IOCON->PIO2_0 &= ~0x07;
    LPC_IOCON->PIO2_0 |= 0x04;     /* UART RTS output */
    LPC_IOCON->PIO2_7 &= ~0x07;
    LPC_IOCON->PIO2_7 |= 0x04;     /* UART DSR input */
    LPC_IOCON->PIO2_6 &= ~0x07;
    LPC_IOCON->PIO2_6 |= 0x04;     /* UART DCD input */
    LPC_IOCON->PIO2_5 &= ~0x07;
    LPC_IOCON->PIO2_5 |= 0x04;     /* UART RI input */
  }
  LPC_UART0->MCR = 0xC0;          /* Enable Auto RTS and Auto CTS. */
  return;
}
 
/*****************************************************************************
** Function name:       SetupUART_Location
**
** Descriptions:        Setup UART0 location
**
** parameters:          port number, location
** Returned value:      None
**
*****************************************************************************/
void SetupUART_Location(uint32_t portNum, uint32_t location)
{
  if ( portNum == 0 )
  {
    if ( location == 0 )
    {
      LPC_IOCON->PIO0_1 &= ~0x07;    /* UART0 I/O config */
      LPC_IOCON->PIO0_1 |= 0x02;     /* UART0 RXD LOC0 */
      LPC_IOCON->PIO0_2 &= ~0x07;
      LPC_IOCON->PIO0_2 |= 0x02;     /* UART0 TXD LOC0 */
    }
    else if ( location == 1 )
    {
      LPC_IOCON->PIO2_1 &= ~0x07;    /* UART0 I/O config */
      LPC_IOCON->PIO2_1 |= 0x04;     /* UART0 RXD LOC1 */
      LPC_IOCON->PIO2_2 &= ~0x07;
      LPC_IOCON->PIO2_2 |= 0x04;     /* UART0 TXD LOC1 */
    }
  }
  else if ( portNum == 1 )
  {
    if ( location == 0 )
    {
      LPC_IOCON->PIO0_8 &= ~0x07;    /* UART1 I/O config */
      LPC_IOCON->PIO0_8 |= 0x02;     /* UART1 RXD LOC0 */
      LPC_IOCON->PIO0_9 &= ~0x07;
      LPC_IOCON->PIO0_9 |= 0x02;     /* UART1 TXD LOC0 */
    }
    else if ( location == 1 )
    {
      LPC_IOCON->PIO2_11 &= ~0x07;    /* UART1 I/O config */
      LPC_IOCON->PIO2_11 |= 0x05;     /* UART RXD LOC1 */
      LPC_IOCON->PIO2_10 &= ~0x07;
      LPC_IOCON->PIO2_10 |= 0x05;     /* UART TXD LOC1 */
    }
    else
    {
      LPC_IOCON->PIO2_12 &= ~0x07;    /* UART1 I/O config */
      LPC_IOCON->PIO2_12 |= 0x03;     /* UART RXD LOC1 */
      LPC_IOCON->PIO2_13 &= ~0x07;
      LPC_IOCON->PIO2_13 |= 0x03;     /* UART TXD LOC1 */
    }
  }
  else
  {
    while ( 1 );
  }
  return;
}
 
/*****************************************************************************
** Function name:       UARTInit
**
** Descriptions:        Initialize UARTx port, setup pin select,
**                      clock, parity, stop bits, FIFO, etc.
**
** parameters:          UART port number, baudrate
** Returned value:      None
**
*****************************************************************************/
void UARTInit(uint32_t portNum, uint32_t baudrate)
{
  uint32_t i, Fdiv;
  uint32_t regVal;
 
  if ( portNum == 0 )
  {
    UARTTxEmpty0 = 1;
    UARTCount0 = 0;
    for ( i = 0; i < BUFSIZE; i++ )
    {
      UARTBuffer0[i] = 0;
 
    }
    NVIC_DisableIRQ(UART0_IRQn);
 
    SetupUART_Location( portNum, 0 );   /* default is location 0 */
 
    /* Enable UART 0 clock */
    LPC_SYSCON->PRESETCTRL |= (0x1<<2);
    LPC_SYSCON->SYSAHBCLKCTRL |= (0x1<<12);
    LPC_SYSCON->UART0CLKDIV = 0x1;     /* divided by 1 */
 
    LPC_UART0->LCR = 0x83;             /* 8 bits, no Parity, 1 Stop bit */
    regVal = LPC_SYSCON->UART0CLKDIV;
    Fdiv = ((SystemCoreClock/regVal)/16)/baudrate ; /*baud rate */
 
    LPC_UART0->DLM = Fdiv / 256;
    LPC_UART0->DLL = Fdiv % 256;
    LPC_UART0->LCR = 0x03;      /* DLAB = 0 */
    LPC_UART0->FDR = 0x10;      /* set to default value: 0x10 */
    LPC_UART0->FCR = 0x07;      /* Enable and reset TX and RX FIFO. */
 
    /* Read to clear the line status. */
    regVal = LPC_UART0->LSR;
 
    /* Ensure a clean start, no data in either TX or RX FIFO. */
    while ( (LPC_UART0->LSR & (LSR_THRE|LSR_TEMT)) != (LSR_THRE|LSR_TEMT) );
    while ( LPC_UART0->LSR & LSR_RDR )
    {
      regVal = LPC_UART0->RBR;  /* Dump data from RX FIFO */
    }
 
    /* Enable the UART Interrupt */
    NVIC_EnableIRQ(UART0_IRQn);
 
#if TX_INTERRUPT
    LPC_UART0->IER = IER_RBR | IER_THRE | IER_RLS;  /* Enable UART interrupt */
#else
    LPC_UART0->IER = IER_RBR | IER_RLS; /* Enable UART interrupt */
#endif
  }
  else
  {
    UARTTxEmpty1 = 1;
    UARTCount1 = 0;
    for ( i = 0; i < BUFSIZE; i++ )
    {
      UARTBuffer1[i] = 0;
    }
    NVIC_DisableIRQ(UART1_IRQn);
 
    SetupUART_Location( portNum, 0 );   /* default is location 0 */
 
    /* Enable UART 1 clock */
    LPC_SYSCON->PRESETCTRL |= (0x1<<3);
    LPC_SYSCON->SYSAHBCLKCTRL |= (0x1<<13);
    LPC_SYSCON->UART1CLKDIV = 0x1;     /* divided by 1 */
 
    LPC_UART1->LCR = 0x83;             /* 8 bits, no Parity, 1 Stop bit */
    regVal = LPC_SYSCON->UART1CLKDIV;
    Fdiv = ((SystemCoreClock/regVal)/16)/baudrate ; /*baud rate */
 
    LPC_UART1->DLM = Fdiv / 256;
    LPC_UART1->DLL = Fdiv % 256;
    LPC_UART1->LCR = 0x03;      /* DLAB = 0 */
    LPC_UART1->FDR = 0x10;      /* set to default value: 0x10 */
    LPC_UART1->FCR = 0x07;      /* Enable and reset TX and RX FIFO. */
 
    /* Read to clear the line status. */
    regVal = LPC_UART1->LSR;
 
    /* Ensure a clean start, no data in either TX or RX FIFO. */
    while ( (LPC_UART1->LSR & (LSR_THRE|LSR_TEMT)) != (LSR_THRE|LSR_TEMT) );
    while ( LPC_UART1->LSR & LSR_RDR )
    {
      regVal = LPC_UART1->RBR;  /* Dump data from RX FIFO */
    }
 
    /* Enable the UART Interrupt */
    NVIC_EnableIRQ(UART1_IRQn);
 
#if TX_INTERRUPT
    LPC_UART1->IER = IER_RBR | IER_THRE | IER_RLS;  /* Enable UART interrupt */
#else
    LPC_UART1->IER = IER_RBR | IER_RLS; /* Enable UART interrupt */
#endif
  }
  return;
}
 
/*****************************************************************************
** Function name:       UARTSend
**
** Descriptions:        Send a block of data to the UART 0 port based
**                      on the data length
**
** parameters:          portNum, buffer pointer, and data length
** Returned value:      None
**
*****************************************************************************/
void UARTSend(uint32_t portNum, uint8_t *BufferPtr, uint32_t Length)
{
 
  while ( Length != 0 )
  {
    if ( portNum == 0 )
    {
      /* THRE status, contain valid data */
#if !TX_INTERRUPT
      while ( !(LPC_UART0->LSR & LSR_THRE) );
      LPC_UART0->THR = *BufferPtr;
#else
      /* Below flag is set inside the interrupt handler when THRE occurs. */
      while ( !(UARTTxEmpty0 & 0x01) );
      LPC_UART0->THR = *BufferPtr;
      UARTTxEmpty0 = 0; /* not empty in the THR until it shifts out */
#endif
    }
    else
    {
      /* THRE status, contain valid data */
#if !TX_INTERRUPT
      while ( !(LPC_UART1->LSR & LSR_THRE) );
      LPC_UART1->THR = *BufferPtr;
#else
      /* Below flag is set inside the interrupt handler when THRE occurs. */
      while ( !(UARTTxEmpty1 & 0x01) );
      LPC_UART1->THR = *BufferPtr;
      UARTTxEmpty1 = 0; /* not empty in the THR until it shifts out */
#endif
    }
    BufferPtr++;
    Length--;
  }
  return;
}
 
int main (void)
    {
 
        while(!)
{
      if ( UARTCount0 != 0 )
              {
                        LPC_UART0->IER = IER_THRE | IER_RLS;
                        UARTSend( 0, UARTBuffer0 ,20);
                        LPC_UART0->IER = IER_THRE | IER_RLS | IER_RBR;
              }
}
}

 

just a suggestion

check that the PC serial comms buffer is set to no buffering.
you code may be ok.

also you will need software or hardware hand shake.
 

Thanks for your suggestion but the same program is working fine if i send only 16 bytes of data.The problem starts only when i send more than 16 bytes of data to the UART.

- - - Updated - - -

There seems to be some problem in the below given line.UARTBuffer is not receiving the whole data from RBR register.

Code:
UARTBuffer0[UARTCount0++] = LPC_UART0->RBR
 

I don't know what UARTSend exactly does, but it seems to ignore the number of bytes present in the buffer, always sending 20 characters including possible garbage. The shown buffer usage is only reasonable if UARTSend copies the data in "no time" to a send buffer, otherwise it's most likely causing receiver data loss.

Is UARTCount0 reset after sending the data? Where?

The mostly used ring buffer solution with two "nextin" and "nextout" pointers is much more flexible in this regard.
 
  • Like
Reactions: vikky

    vikky

    Points: 2
    Helpful Answer Positive Rating
Now i understand that LPC 1227 has only 16 byte receive and transmit FIFO.Can anyone please suggest how to receive or send data longer than that.Thank you.

- - - Updated - - -

Hi FvM,

I am mentioning 20 characters only when i know in that loop i am supposed to receive only 20 characters.The character i receive is fixed for each loop and yes i am clearing UARTCount0 after each time i receive and copy the data from the UARTBuffer0.Usually i copy the value i receive from UARTBuffer0 immediately but this time i am sending UARTBuffer0 in the raw form just to check what data is getting receive from RBR (Receive) register.And Yes I am clearing UARTCount0 after coming out of the loop whichi forgot to copy paste in the code here.

But what i cannot understand is that the existing program works fine on some occasions.It works fine on all occasions when input string is less than 16 bytes. Thank you.
 
Last edited:

Some have said the FIFO empty status for interrupt control is too late and therefore useless then created their own counter. You want an almost empty and almost full for ideal FIFO flow control. They just wanted to emulate a typical 16 byte buffered UART. I suggest you implement either a hand shake method, timer method or a software counter. Setting up a DMA process may be a bite much.

Or use the send N-1 method explained here.

https://ardweenet.blogspot.com.au/2012/12/nxp-wtf.html


Contact ArM tech support, they must have a better solution!
 

Some have said the FIFO empty status for interrupt control is too late and therefore useless then created their own counter. You want an almost empty and almost full for ideal FIFO flow control. They just wanted to emulate a typical 16 byte buffered UART. I suggest you implement either a hand shake method, timer method or a software counter. Setting up a DMA process may be a bite much.

Or use the send N-1 method explained here.

https://ardweenet.blogspot.com.au/2012/12/nxp-wtf.html


Contact ArM tech support, they must have a better solution!

Hi Sunnyskyguy,
Thanks for your response.
Your document made an interesting read.But the function UART0_IRQHandler function written by me is given by NXP.I could never understand why they have given me a code which doesnt work in all circumstances.

In your code does the txBufferRead has the received data?thats what i could understand.
 

Hi FvM,

Your idea almost worked.I copied the contents into another buffer immediately.
Code:
 UARTBuffer0[UARTCount0++] = LPC_UART0->RBR;
memcpy((const char *)BBuffer0,(const char *)UARTBuffer0,UARTCount0);

But still first character is getting lost occasionally and i get some valid data and some invalid data during the first read.In the subsequent read it works 70% of time.in rest 30% first character gets missed.Please advise.Thank you.
 

also you will need software or hardware hand shake.

THINKER_KAM_MAN was right you need some sort of hand shaking. You can have hardware handshaking (prefered) or software handshaking. If you chose software handshaking (xon-xoff) you will need to disable or reduce in size the UART| buffer in your PC.
 

I don't know the UART you are using, but to me it looks like the driveers you use are testing the wrong flags from the UART. There may also be a problem if you use reentrant ISR code or clear flags from both the ISR and the background. Since you are loosing the first byte received, the flag testing can be suspect. I've even seen drivers turn the UART on and off during data retrival, that may be a pain.
 
  • Like
Reactions: vikky

    vikky

    Points: 2
    Helpful Answer Positive Rating
The method to use UART are two methods,query and interrupt. The interrupt method has more performance improvement with you. Or you can use the low performance with query the RxFIFO status. The hardware UART controller usually has many registers to operate.It has RxFIFO and TxFIFO usually,but has the limitation numbers. Such as,if the MCU you are using is 8bit,then the registers are all 8-bit. Pay attention with the limited length of FIFO. When your data is greater than the limitation,you should split it into many parts,send then part by part to solve your length string problem.
Have a fun,baby!
 
  • Like
Reactions: vikky

    vikky

    Points: 2
    Helpful Answer Positive Rating
But i did use Interrupt method and the code works 70% of the time.but some tweaking is necessary is what is needed is what i could understand.Can you please go through my code and tell me what is missing.Thank you.
 

If your interrupt routine is working, the least problem you should have is the recognizing the first byte.
Since you have problems with the FIFO size, I would think that your interrupt is not activated before a number of bytes is received in the buffer, or that the ISR does not empty the FIFO when activated.
Try to set the interrupt to 1 byte in the buffer, if possible.

Another problem may be the latency time of the ISR startup, related to your baud rate. Try to reduce the baudrate and see if things change. If it gets better you'll know that time is a factor i this problem.

If you echo the received bytes, you can see the response time with a 2 channel scope, comparing the bit streams.
 
  • Like
Reactions: vikky

    vikky

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top