Flowcontrol MBED USB-serial <=> PC Missing?

30 Jan 2010

When I began losing characters even on my reliable Ubuntu, I digged into the UART and USB litterature (I'm unfortunately not much of an expert here...) and when I looked at the Serial class as well as the LPC1768 manual I saw no signs of flow-control.

If the communication is only based on UART0 I don't see how the MBED control chip can know if the LPC1768 is ready and vice versa.

What am I missing?

Regards,
Anders

01 Feb 2010 . Edited: 01 Feb 2010

Hi Anders,

Anders Rundgren wrote:
If the communication is only based on UART0 I don't see how the MBED control chip can know if the LPC1768 is ready and vice versa.

That is exactly the case - it is a standard 2 wire UART connection between the target (LPC1768) and the USB interface (mbed interface), so there is no flow control.

If one is sending the other just needs to keep up, as with any 2-wire UART connection (it is the same as if the UART was connected to a standard FTDI 2-wire interface, instead of the mbed interface).

We have looked at providing a virtual serial port via JTAG, but the reality is the basic UART covers the common case very well so it'd be a lot of work for little gain right now.

Simon

01 Feb 2010

Hi Simon,

I fully understand if you don't feel tempted improving this part of MBED but I think you should consider it anyway, for a number of (IMO) valid reasons:

 

# If you run at 921600 and the PC sends a puny 20 byte block and you get an interrupt that takes 0.2ms to serve you are toast.

Conclusion: you are on thin ice if you run at such speeds.

 

# http://mbed.org/handbook/Serial

The purpose of "readable" and "writeable" are rather dubious, they don't do what a newbe would assume

 

# Multitasking PCs may be busy for several milliseconds and then you will lose characters unless you settle for 9600 baud and/or small data blocks.

 

# USB-PC serial implementations in other development boards run reliable at USB speed (you don't even have to set baudrate).

Fully blocking I/O is by far the simplest to write for in a typical master-slave configuration.  Isn't this how mass storage already works?

 

I neither expect a miracle, nor an answer, but since UART0 can be (de)configured as two input pins (like RXHasDATA + TXisRDy)  including interrupt, it seems that you could actually keep the serial API as is but do something else for UART0 underneith, presumably using JTAG.  Well, I would add writeBuffer to exploit USB a bit better as well.  I'm at least prepared to test :-) :-)

Best regards from a slightly difficult customer

Anders

03 Feb 2010

I just wanted to add a caveat.  If the MBED controller chip cannot be reconfigured with respect to the UART-to-UART pins, my suggestion is probably not technically viable.

08 Feb 2010

Anders,

 

I've had good luck using the usb-serial port for debugging my code.  Granted, I am running at 9600 baud and just sending out ascii messages and watching them from minicom on my linux box.  I've done a lot of serial port stuff for work and the like, and I have never found a need for flow control...  A couple thoughts about your post:

1) If you really need 921600 baud, then I'd suggest using the network port and udp packets, or see how the work on USB stack is coming along as those interfaces are better suited for higher bandwidth communications than the serial port.

2) I would agree that readable and writable are a bit odd, and that the serial port library is a bit strange compared to standard ones that I've worked with.  I would much rather have a good standard read() and write() with blocking and non-blocking options... I've also had a lot of problems with printf causing the system to hang when using receive interrupts, so I've had to build my own stuff off of the putc and getc functions...

3)  If your PC code is setup to have a seperate thread that just calls a blocking read and it has decent UARTS w/ some hardware buffer (e.g. 16 bytes) then it should work fine.  Yes, if you have really heavy system loads or super high baud rates it might cause problems, but good OS's typically have software buffers tied into the hardware with interrupts which *should* not overrun...  How is your PC code written, and do you think the missing bytes are due to the uC not sending them right, or the PC not receiving them fast enough???

4) I'm planning on implementing a SLIP like protocol to frame my data bytes to actually send binary datagrams instead of just ascii print outs... It will have a special header and footer byte, and an escape byte in case that header/footer byte shows up in the data itself... Using a system like that plus a simple checksum will provide sufficient software flow control for many applications.

Anyway, just some thoughts to continue to conversation if you're interested...  Good luck finding your missing bytes!

-John

08 Feb 2010

John,

Other development boards with PC<->USB connectors run at megabyte speed without the programmer having to bother with flow-control issues (it is done by the USB driver).

Creating an "alternative" PC<->MBED channel sort of defeats the VERY GOOD intention with MBED (=RAPID and SIMPLE prototype development).

My application may be extreme from a bandwidth point-of-view but feeding a 96MHz processor with 9600 baud doesn't seem like perfect match :-)

Exactly where the problem is I don't know for sure, but my guess is that if the PC is slow, the MBED controller probably stops sending data to it but the MCU has no knowledge of that so the owerflow is happening *inside* of MBED which is outside of what mere mortals can deal with except by carefully timing everything, hold your thumbs and hope that it doesn't crash.

Anders

08 Feb 2010

Anders,

I did some testing here on my end w/ a typical MBED -> USB -> PC setup.  I put together an app to send bytes from the MBED at (115200 * 8) = 921600 baud and receive them on the PC (in python using pyserial).  I send bursts of 10,000 packets with one second in between.  One packet consists of the following 7 bytes:

<MARKER BYTE> <4 BYTE TIME STAMP> <CHECKSUM BYTE> <MARKER BYTE>

It is possible that if the marker byte appears in the data of the time stamp, it will be escaped so as not to confuse the actual marker byte start/stop packet framing...

Anyway, I too get some checksum errors when transmitting at 921600 baud.  They seem to come in short bursts, but the system just drops those bad checksum packets and recovers shortly after.  I've been able to send over 50k packets without any dropped packets though... Interestingly, even at 115200 it seems like it is possible to get a few bad packets as well.

This probably isn't the best test to really debug what the problem is here.  As I just wrote my framing packet code today, it likely has some errors and non-handled exceptions.  Here is my idea for now to figure out where the problem may be:

Write a debug program that sends a known byte series and expectes that same series to be echo'd back. a good example is from this app: SerialBuffered and then try:

1) Write a PC program that simply echo's bytes back on the /dev/ttyACM0 and run the test at various baud rates

2) Try the same thing but using a very short jumper between local hardware uart RX/TX pins

Here are my theories on how these experiements might work out:

A) If the test succeeds on both #1 and #2, then there isn't really a problem! Magic! :)

B) If the test fails on both #1 and #2, but only at some (e.g. higher) baud rates then the problem should be something with the LCP1768 not supporting that baud rate due to the clock rate and divisor (refer to manual), how the serial putc has been implemented (not making use of the hardware DMA), or at least a problem specific to the MBED chip itself and not your PC.

C) If the test fails on only #1, but secceeds on #2, then the problem points to the USB->Serial link or to the PC.  The secret serial->USB chip on the bottom of the MBED maybe doesn't support those higher rates.  The driver for the PC's Virtual Com port maybe doesn't support higher rates or has some interrupt servicing issues like you considered.  The PC code should be written in native C and not in python ;p heh...   Finally maybe there is just too much noise somewhere, between the LCP1768 and the secret chip, or from the USB connectors, etc...

Just some ideas, but I haven't written the test code yet... Lemme know if you get around to this before me, as I will likely need to use higher baud rates some day and would prefer closer to 100% link quality as opposed to the ~90% or so that I got in a handfull of very rough tests...

-john

08 Feb 2010

Hi John,

I have also played a lot with test programs so it is a good idea!

When sent data from the PC to MBED I had no problems, except for a (corfirmed) baudrate-setting-bug in library for higher baudrates.

However, when I added an "innocent-looking" wait(0.1) to simulate something processor-intensive between each readc() on the MBED side, data became corrupted.  IMO, this is because the LPC1768 has no way of telling the USB-side that it is busy.  Actually, it is the rather otherway round; readc() should inform the USB-side that it is ready and waiting.

I'm pretty sure that program #1 will run flawlessly since the buffer will only be a single byte.

Regarding the other direction, I'm not certain what happends but IMO the fundamental issue is in the MBED design which currently does not support flow-control in its internal UART<->UART communication.

I'm considering creating a half-duplex framework that only sends 1-16 bytes (keep that FIFO happy...) and then waits for an ACK but that will slow down communication.

You can mail me on anders.rundgren@telia.com in case you do a break-through!

Anders

11 Aug 2010

Anders,

Your other option is to use DMA on the UART. I've written a write (mem 2 peripheral) and read (peripheral 2 mem) dma class and tested it with a uart. It's part of Hugo's FreeRTOS port at http://github.com/hugovincent/mbed-freertos.

You can define receive and transmit fifos of any arbitrary length. I haven't yet implemented any data interrupts (fifo full, data ready etc) as Hugo and I have greater plans for task interrupts

Robert

12 Aug 2010 . Edited: 12 Aug 2010

 

user avatar Robert Turner wrote:
Your other option is to use DMA on the UART. I've written a write (mem 2 peripheral) and read (peripheral 2 mem) dma class and tested it with a uart. It's part of Hugo's FreeRTOS port at http://github.com/hugovincent/mbed-freertos.

Unfortunately the root of the problem is in the use of an UART in the mbed "secret chip".  Other drawbacks with this UART-to-UART bridge is that you need to set baudrates in both the host and in mbed.  Other development boards featuring USB-serial always run at USB speed and have flowcontrol transparently performed at the USB level.  It is solvable without a hardware revision but only ARM can fix it so I guess I have to corrupt my program with arbitrary delays or turn to another device.  I have yet to find something as neat as mbed.   For now I use mbed to port OpenSSL crypto which is going to run on any ARM device so I do have some good use of it anyway.

Anders