CP2102 Latency - Page 1
Forum section: electronics / projects

author: AndBondStyle
author_rank: Newbie
timestamp: June 15, 2023, 08:46:07 pm
content: Hi everyone. I'm trying to optimize UART communication between linux PC and ESP32 devkit, which is performed via classic CP2102 chip. I have a logic analyzer connected both to USB and UART lines to debug latency issues. Below you can find a PulseView (sigrok?) session dump and a screenshot with my explanation of what's going on. My question is:why CP2102 waits for an additional ~500us (P4) before sending incoming UART data to USB?Any ideas how to force it to flush immediately?

author: ataradov
author_rank: Super Contributor
timestamp: June 15, 2023, 09:20:33 pm
content: The delay is likely it is waiting for additional bytes. Sending USB data for each received byte would reduce sustained bandwidth, so it tries to accumulate as many bytes as it can before flushing it out.A better algorithm would send the first byte immediately, and while USB is doing its thing, it would accumulate the following bytes. But it does not look like they are doing this.There is some CP21xx configuration utility, but I don't remember it having any delays there. It is mostly VID/PID/serial number.If you have control over the data, I would try to pad it to 64 bytes (or whatever the CDC data endpoint size they use). It will be forced to flush the data immediately.

author: PCB.Wiz
author_rank: Super Contributor
timestamp: June 15, 2023, 09:38:42 pm
content: Quote from: AndBondStyle on June 15, 2023, 08:46:07 pmYou will always somewhat battle the USB clumping effects.I did some UARTS tests for a two-byte echo, as an experiment for rapid real time polling of simple sensors, on a RS485 like half duplex.This waits for a reply, before it sends the next poll, so it times the USB latencies. I uses 2MBd to make the UART times not significant.This is tough on USB, as the payloads are very small and yet we want fastest possible next packet times.I found that USB ports on my Samsung laptop are quite different in timing, even when talking to FS-USB UARTs ?!I'm guessing that's some motherboard hub effect. Another pitfall to watch out for...The HS-USB partsshouldall be better because of the 125us microframe, but strangely, FTDI limit to 1ms in their drivers ?!Tests were with FreeBASIC and the PL2303gc drivers have a quirk where they can return nothing, so for them I addedpatch code like thisb = Input(2,cCom) ' read 2 - does this wait ?, seems to wait ? - PL2303 fails to read 2While Len(b) < 2 ' PL2302gC reads one ?!b = b+Input(1,cCom) ' fixup can be thousands, as PL2303GC can return nothing at all !!mFixUp = mFixUp + 1WendSummary : this shows the CP2102N is 'not great' at fast turnaround, and the CH9102 / CH347 are better choices.Avoid the seemingly fast FTDI parts.On my tests I was surprised the FS-USB CH9102 managed slightly more packets than the HS-USB CH347, but I would suggest always testing both parts.~~~~~~~~~~~~~~~~~~ Better USB port results (USB 3 supporting ? ) ~~~~~~~~~~~~~~~~' XR21B1420 Sending Chars : 5002 TX.RX Done,eCount 5000 eLoops 2500 mCount 2500 mFixUp 0' SW delay = 0.5426966454833746 Packet average time = 0.0002169918614487703' Waiting Chars A = 2 Waiting Chars B = 0 Post RX Done, LOC(cCom) 0 RxCount 2 RxLoops 1' CH9102 Sending Chars : 5002 TX.RX Done,eCount 5000 eLoops 2500 mCount 2500 mFixUp 0' SW delay = 0.4118906036019325 Packet average time = 0.0001646903652946551' Waiting Chars A = 2 Waiting Chars B = 0 Post RX Done, LOC(cCom) 0 RxCount 2 RxLoops 1' CH347 Sending Chars : 5002 TX.RX Done,eCount 5000 eLoops 2500 mCount 2500 mFixUp 0' SW delay = 5.073910656385124 Packet average time = 0.00202875276144947 << still slower than CH9102' Waiting Chars A = 2 Waiting Chars B = 0 Post RX Done, LOC(cCom) 0 RxCount 2 RxLoops 1'PL2303 Sending Chars : 5002 TX.RX Done,eCount 5000 eLoops 2500 mCount 2500 mFixUp 604 << much faster but stil needs fixups' SW delay = 0.4224882982671261 Packet average time = 0.0001689277482075674' Waiting Chars A = 2 Waiting Chars B = 0 Post RX Done, LOC(cCom) 0 RxCount 2 RxLoops 1' FT232H stays at 1.00ms as it has timer set to 1ms ??''CP2102N Sending Chars : 5002 TX.RX Done,eCount 5000 eLoops 2500 mCount 2500 mFixUp 0' SW delay = 2.304060092195869 Packet average time = 0.0009212555346644816 << onlyslightly faster' Waiting Chars A = 2 Waiting Chars B = 0 Post RX Done, LOC(cCom) 0 RxCount 2 RxLoops 1~~~~~~~~~~~~~~~~~~ 'Slow' USB port results ~~~~~~~~~~~~~~~~~~~~~~~~~' PL2303GC Sending Chars : 5002 TX.RX Done,eCount 5000 eLoops 2500 mCount 2500 mFixUp 252475 << PASS FIXUP' SW delay = 4.453083822503686 Packet average time = 0.001780521320473285' Waiting Chars A = 2 Waiting Chars B = 0 Post RX Done, LOC(cCom) 0 RxCount 2 RxLoops 1'' CH9102 Sending Chars : 5002 TX.RX Done,eCount 5000 eLoops 2500 mCount 2500 mFixUp 0 << PASS' SW delay = 2.5202183900401 Packet average time = 0.001007684282303119' Waiting Chars A = 2 Waiting Chars B = 0 Post RX Done, LOC(cCom) 0 RxCount 2 RxLoops 1'' 2102N Sending Chars : 5002 TX.RX Done,eCount 5000 eLoops 2500 mCount 2500 mFixUp 0 << PASS' SW delay = 3.296353168785572 Packet average time = 0.001318014061889473' Waiting Chars A = 2 Waiting Chars B = 0 Post RX Done, LOC(cCom) 0 RxCount 2 RxLoops 1' CH347 Sending Chars : 5002 TX.RX Done,eCount 5000 eLoops 2500 mCount 2500 mFixUp 0 << PASS' SW delay = 5.560949970036745 Packet average time = 0.002223490591777987' Waiting Chars A = 2 Waiting Chars B = 0 Post RX Done, LOC(cCom) 0 RxCount 2 RxLoops 1' CH347 FIFO off Sending Chars : 5002 TX.RX Done,eCount 5000 eLoops 2500 mCount 2500 mFixUp 0' SW delay = 5.319267685525119 Packet average time = 0.002126856331677377' Waiting Chars A = 2 Waiting Chars B = 0 Post RX Done, LOC(cCom) 0 RxCount 2 RxLoops 1' FT232H default' SW delay = 39.98649911675602 Packet average time = 0.01598820436495643 Waiting Chars = 0' Post RX Done, LOC(cCom) 0 RxCount 2 RxLoops 1' Ahh.. change latency timer under driver.advanced from 16ms to min 1ms' Sending Chars : 5002 TX.RX Done,eCount 5000 eLoops 2500 mCount 2500 mFixUp 0' SW delay = 2.516928613185883 Packet average time = 0.001006368897715267 << NOW A PASS' Waiting Chars A = 2 Waiting Chars B = 0 Post RX Done, LOC(cCom) 0 RxCount 2 RxLoops 1

author: ataradov
author_rank: Super Contributor
timestamp: June 15, 2023, 09:56:01 pm
content: 1 ms frames in FS are not an issue because the host may schedule multiple transfers per frame. It actually should schedule multiple transfers if it wants to get more than 64 kbytes/s.It is not a problem at all to get over 1 MB/s sustained transfer over FS with CDC. But there is not a whole lot you can do with inefficiency of a lot of small frames.Sending in chunks of the endpoint size is a hack, and not always possible to get reliably, but when it works, it works quite well. Except in cases where buggy USB stacks don't sent ZLP after the last chunk, leaving it in the OS buffer limbo.And yeah, waiting for ZLP on the aligned transfer would just transfer the delay to the OS, so probably won't work for standalone 64-byte transfers.

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 15, 2023, 10:03:02 pm
content: Some FTDI chips have a SIWU pin that allows flushing the FIFO immediately, like the FT232H and FT2232H, but I'm not sure this is supported in the UART mode.I've used it in parallel FIFO modes, and that works well.I'm not aware of any of the CPxxxx chips having such a feature.

author: AndBondStyle
author_rank: Newbie
timestamp: June 17, 2023, 12:08:49 am
content: Thanks everyone for your suggestions!Meanwhile, I found a doc with some insights about inner workings of CP2102 USB protocol:https://www.silabs.com/documents/public/application-notes/AN571.pdfThere is some interesting stuff, including various flow control settings which I weren't aware of.Current theories I want to test, regarding some way to force CP2102 to flush:1. Try to utilize CTS pin in MCU firmware2. Try to send "UART break" signal at the end of each messageAnd obviously I need to dig deeper into USB configuration registers. It will probably involve writing a custom USB driver (via libusb or something). It's quite a new experience for me, but I'll tryWill post an update in a few days.

author: PCB.Wiz
author_rank: Super Contributor
timestamp: June 17, 2023, 12:22:25 am
content: Quote from: AndBondStyle on June 17, 2023, 12:08:49 amDo youhaveto use CP2102N ?If you are locked into that part, but do have control over the software, you could arrange more buffering to reduce the turn around effects, and/or bump the baud rate to educe the overall times.The total CP2102N delay is already under 25% of your total transactions, and change of baud is relatively easy.

author: AndBondStyle
author_rank: Newbie
timestamp: June 17, 2023, 06:23:12 pm
content: Quote from: ataradov on June 15, 2023, 09:20:33 pmTried padding it to 64 and to 100 bytes, no effect. Looks like the data is being flushed at regular time intervals, regardless of how many bytes it has in queue.Quote from: PCB.Wiz on June 17, 2023, 12:22:25 amNotreally, but there are some reasons. First of all, CP2102 (without the "N", however) is usually what comes included in ESP32 devkit boards. If I decide to open source my project, it's always nice to use off-the-shelf parts as it's easier for others to replicate. You can ask a slightly different question, like "why not to use a USB-SPI chip". For me UART is ideal because you can both flash firmware (fully hands-free btw, using RTS and DTR pins to reset the ESP and put it into boot mode) and communicate with MCU. And the last thing, I just want to figure out what I'm doing wrong. Of course, if I fail to make any progress, I will probably drop that and move on. But not yetQuote from: PCB.Wiz on June 17, 2023, 12:22:25 amMy bad that I didn't specify it more clearly, but I'm using a CP2102 without the "N" right now, so max speed is 1mbps (921600 to be exact). Also, message sizes that I'm using for tests, don't really represent the data I'll be using in the real project. Messages will be much smaller, around 16 bytes for request [~140us] and 32 for response [~280us], which will make the CP2102 delay not 25% but more like 40% of total transaction time.

author: PCB.Wiz
author_rank: Super Contributor
timestamp: June 17, 2023, 09:11:13 pm
content: Quote from: AndBondStyle on June 17, 2023, 06:23:12 pmAliexpress have kits with titles likeESP32 Development Board CP2104 CH9102where they give users a choice, and many list only CH9102, so you could buy a CH9102 variant and then compare the results.That gives a very useful second reference point, where just the USB-UART changes, and you should see numbers similar to my 2Mbd 2 byte payload tests above.

author: spostma
author_rank: Regular Contributor
timestamp: June 18, 2023, 07:40:45 pm
content: most USB-serial chips, including CP2102 and CP2019, have event character support.This is a flag character then, when received, will cause all received data to be transmitted in the next USB frame without waiting for a timeout period.For ascii protocols, set it to 0x13 (CR) or 0x0A (LF).On the PC side, you also will receive an OnEvent signal.

author: AndBondStyle
author_rank: Newbie
timestamp: June 18, 2023, 09:11:08 pm
content: Quote from: PCB.Wiz on June 17, 2023, 09:11:13 pmYes, this could actually be the best solution for me, thank you. Already ordered some kits to test (hopefully) later this week.Quote from: spostma on June 18, 2023, 07:40:45 pmThis makes sense for newline characters, but I always thought this is handled on OS or driver level. Did you find any mentions of this behavior in datasheets?

author: spostma
author_rank: Regular Contributor
timestamp: June 19, 2023, 03:31:49 pm
content: more info on event characters from FTDI (I think also valid for Silicon Labs):https://www.ftdicommunity.com/index.php?topic=57.0

author: PCB.Wiz
author_rank: Super Contributor
timestamp: June 20, 2023, 12:00:07 am
content: Quote from: spostma on June 19, 2023, 03:31:49 pmI've never used those, but it seems to not be available under VCP usage, only custom drivers.Likewise CP2102N seems to be custom only ?QuoteNothing for that shows up under the VCP driver.

author: ataradov
author_rank: Super Contributor
timestamp: June 20, 2023, 12:17:56 am
content: CDC ACM (VCP) does not have any standard for adjustment of any of this.But this would not stop CDC ACM device from having vendor-specific commands to do the adjustments. This does not need to be a part of the driver, the standard driver would work. But you would need a custom tool to issue those commands.

author: PCB.Wiz
author_rank: Super Contributor
timestamp: June 20, 2023, 12:38:59 am
content: Based on the CP2102N comments' the receive buffer waits up to 2 ms or 128 character times, whichever is fewer, 'I revisited the tests with a change to 4MBd up from 2MBd2MBd Packet average time = 0.0009212555346644816try 4Mbd' Packet average time = 0.0005585749926673369' Packet average time = 0.0005621098906177132So it is quite a gain to use the higher baud to lower the timer setting. That may help the OP,providedthey have the 'new' CP2102N-A02, and can set the baud at ESP23 to 4MBdI also rechecked CH9102 at higher baud, with a fractional gain' CH9102' 2MBd Packet average time = 0.0001646903652946551' 4MBd improves Packet average time = 0.0001456637504469247' 6Mbd very small gain, Packet average time = 0.0001390995565758663

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 20, 2023, 12:48:36 am
content: That's good to know.Now as a general thought, if you have an application for which latency really matters, usually going for either a fully custom approach or a FTDI in parallel FIFO mode is a saner choice, using a USB-to-UART chip is going to be a headache requiring various tricks and relying on features that are not fully documented and may change from one version to the next. YMMV.