UART is dropping bytes :(

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

User avatar
russian
Posts: 368
Joined: Mon Oct 29, 2012 3:17 am
Has thanked: 16 times
Been thanked: 14 times

UART is dropping bytes :(

Post by russian »

I am having more issues with UART driver - it looks like some bytes are being dropped either on read or on write :(

I've implemented a simple loopback thread in my firmware:

Code: Select all

   while (TRUE) {
      short c = (short) chSequentialStreamGet(chp);
      consolePutChar((uint8_t) c);
}


I've written a tiny testing tool which sends, reads and compares bytes over serial TwoWayTester.java

I've validated my USB-TTL devices and the testing tool by looping two USB-TTL devices - what I read is ALWAYS what I send.
I am also ALWAYS reading what I've send if I am using Chibi build-in serial-over-usb driver, so I am pretty sure the problem is around the UART driver.

I've tried increasing the buffer the way it helped the simulator - viewtopic.php?f=2&t=1750 - but it did not help.

I am using 2.6.3 with seial_llc.c from 2.6 branch trunk to address viewtopic.php?f=16&t=1976

If needed I can improve my test code in order to figure out if the bytes are lost on read or on write. I will probably try the same test code with older releases because I kind of think some version in the past was pretty reliable in terms on UART.
skute
Posts: 64
Joined: Wed Aug 29, 2012 10:17 pm

Re: UART is dropping bytes :(

Post by skute »

I would suggest first checking the flags which get set on an error (overrun for example) by the serial driver. This could help narrow down the problem.

Also, the serial driver is byte by byte interrupt driven, if you know the data length that you are receiving it might be better to use the uart driver which uses DMA for the transfers.
User avatar
russian
Posts: 368
Joined: Mon Oct 29, 2012 3:17 am
Has thanked: 16 times
Been thanked: 14 times

Re: UART is dropping bytes :(

Post by russian »

Interesting, I cannot reproduce this issue with the demo projects. So, it's somehow related to my code. I see a lot of binary search in front of me :)

Where do I look for the flags? Somewhere within USART_TypeDef?
skute
Posts: 64
Joined: Wed Aug 29, 2012 10:17 pm

Re: UART is dropping bytes :(

Post by skute »

There is a similar topic which talks about the flags here: http://forum.chibios.org/phpbb/viewtopic.php?f=2&t=810
User avatar
russian
Posts: 368
Joined: Mon Oct 29, 2012 3:17 am
Has thanked: 16 times
Been thanked: 14 times

Re: UART is dropping bytes :(

Post by russian »

Is it appropriate to check for flags within the same loop as the 'chSequentialStreamGet'?

Like

Code: Select all


   EventListener el1;
      chEvtRegisterMask((EventSource *) chnGetEventSource(EFI_CONSOLE_UART_DEVICE), &el1, 1);

   while (TRUE) {
      short c = (short) chSequentialStreamGet(chp);

         uint32_t flags;
         chSysLock();
         flags = chEvtGetAndClearFlagsI(&el1);
         chSysUnlock();

         if(flags & SD_OVERRUN_ERROR) {
            firmwareError("serial overrun");
         }

             consolePutChar((uint8_t) c);
}


?

And yes, this check reports serial overrun if I compile with gcc. And not if I compile with IAR. Probably different amount of debug code and different performance, so it simply cannot keep up with the RX event flow?
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: UART is dropping bytes :(

Post by Giovanni »

Usually you get and clear the flags once after receiving an event notification.

Giovanni
skute
Posts: 64
Joined: Wed Aug 29, 2012 10:17 pm

Re: UART is dropping bytes :(

Post by skute »

There is another uart echo example here: http://forum.chibios.org/phpbb/viewtopic.php?f=4&t=1964. For my usage I had to modify the serial driver to use a circular dma buffer for rx with a timer capture/compare timeout to avoid losing characters (http://www.st.com/st-web-ui/static/active/en/resource/technical/document/application_note/CD00256689.pdf).
User avatar
russian
Posts: 368
Joined: Mon Oct 29, 2012 3:17 am
Has thanked: 16 times
Been thanked: 14 times

Re: UART is dropping bytes :(

Post by russian »

By disabling different sections of the code and playing with serial buffer size I came to the conclusion that I am causing the issue by spending (wasting?) too much CPU - a piece of code like

Code: Select all

while(TRUE) {
  chThdSleepMilliseconds(5);
}
would be enough to dramatically increase the chances of UART overrun. It looks like I was really overestimating the amount of CPU power available even in M4F.

While the ChibiOS demo application gets

Code: Select all

--- Test Case 11.4 (Benchmark, context switch)
--- Score : 2 509 608 ctxswc/S
--- Result: SUCCESS


I am currently getting only

Code: Select all

----------------------------------------------------------------------------
--- Test Case 1.4 (Benchmark, context switch)
--- Score : 471 536 ctxswc/S
--- Result: SUCCESS

I am still working on isolating which particular functionality in my code base is eating most of the performance.

An interesting observation so far is that #define CH_DBG_SYSTEM_STATE_CHECK TRUE alone drops the context switch benchmark by 40%:
default ChibiOS Demo with #define CH_DBG_SYSTEM_STATE_CHECK TRUE:

Code: Select all

--- Test Case 11.4 (Benchmark, context switch)
--- Score : 1 562 592 ctxswc/S
--- Result: SUCCESS


Which is probably related to the fact that dbg_check_enter_isr() does a full-scale lock/unlock to guard dbg_isr_cnt increment/decrement. Is it because

Code: Select all

dbg_isr_cnt++
is not atomic on some/all compilers, or is it because we need the check and increment to be atomic in

Code: Select all

void dbg_check_enter_isr(void) {
  port_lock_from_isr();
  if ((dbg_isr_cnt < 0) || (dbg_lock_cnt != 0))
    chDbgPanic("SV#8");
  dbg_isr_cnt++;
  port_unlock_from_isr();
}
?
User avatar
russian
Posts: 368
Joined: Mon Oct 29, 2012 3:17 am
Has thanked: 16 times
Been thanked: 14 times

Re: UART is dropping bytes :(

Post by russian »

I see, increment is not atomic in ARM.

How about

Code: Select all

inline void safe_increment(uint32_t *addr)
{
  uint32_t new_value;
  do
  {
    new_value = LDREXW(addr) + 1;
  } while(STREXW(new_value, addr));
}
?
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: UART is dropping bytes :(

Post by Giovanni »

The operation need to be atomic, this is why there are the lock and unlock. Note that the system checker adds a lot of code to the kernel, not just in that point, this is why the scores are lower when you enable it.

Giovanni
Post Reply