Prolific PL2303 serial port to 250000bps - linux

I need to run my /dev/ttyUSB0 (prolific pl2303 USB-RS232 converter) at 250kbps using c. Everywhere I looked everyone said that the nearest achievable speed is 230400 bps (http://lxr.linux.no/#linux+v3.9.5/drivers/usb/serial/pl2303.c and a few lines later (line 325) "NOTE: Only the values defined in baud_sup are supported !").
But I'm 100% sure that it can be done, because on windows (using c# default SerialPort component) I can just set 250000 as the baudrate, and it wil happily put out data at that speed (measured with an oscilloscope, so it's not switching to the nearest available or to 9600 as described in the linux driver at line 325!).
Does anyone know a way to set tat custom baudrate in linux?
And before you ask, I have developed a device that communicates at 250kbps, that speed is needed and is the highest I can get without errors, so no I can't change it.

It's a problem in the linux driver. From line 333 to line 348, the driver forces a baudrate. Removing that code, the baudrate gets calculated with the formula 12 * 1000 * 1000 * 32 / baud, and that gives an error of 0% at 250kbps, perfectly in line with what I get on windows. I'm looking forward to improve the official driver.

Related

Delays in serial communication with pyserial

I'm seeing ~15ms of overhead when communicating with a microcontroller over RS-485 with a USB-to-serial converter, is there any way to minimize this overhead?
I have some debug and data collection python3.10 scripts that connect to a microcontroller via either USB or half-duplex RS-485 serial. I'm using PySerial in both cases and I am either passing it the address for the USB-to-serial converter to the controller directly (running on MacOS). Today I logged how long a command and response takes to execute at different RS485 baud rates (median of 1000 command/response cycles, min time is similar):
9600 baud - 32 ms
38400 baud - 16 ms
115200 baud - 16 ms
230400 baud - 16 ms
500000 baud - 16 ms
USB - 1 ms
I have scoped the signal # 115200 baud and the command + response takes 3ms max, so I while I would like this micro to burn in a pit I don’t think I can blame this particular problem on it. Since all my code is shared between the serial and usb tests, I'm left to believe that the majority of the overhead is coming from pyserial or my d-tech usb-to-serial converter.
From what I’ve seen a large number of the usb-to-serial adapters use the same FTDI chipset, so I’m not sure if I would actually get any improved performance by blindly choosing another converter. If someone knows better here please chime in.

usb bulk transfer timeout under Linux while it works under Windows

[Edit: I found the reason, see below]
The problem:
I created a "driver" for a device in Windows using Python (PyUSB and libusb-win32). While this software works seamlessly on multiple PCs under Windows, using my Linux (Kubuntu 18.10) test laptop, a sequence of bulk writes of length 512 bytes each times out after the second 512 byte bulk transfer.
Interesting: I also tried the same using VirtualBox. And it turns out using a Windows guest via VirtualBox on the same Linux host, the same error still occurs. So it is not because of
The question:
What can happen under Linux does not happen under Windows that causes a timeout [Errno 110]?
More information, in case it helps:
Under Windows, Wireshark shows timing differences between two of the bulk writes of 6 ms for the first one and 5 ms for every following, while under Linux the delta is only round about 3 ms, which are mostly resulting from a sleep operation (relevant Python source code is attached). Doubling that time does nothing.
dmesg shows messages like 'bulk endpoint ## has invalid maxpacket 64', where ## is 0x01, 0x08 and 0x81.
The device only has one configuration.
The test laptop has only USB 3.0 connectors, where the Windows PCs have both USB 3.0 and 2.0. I tested all.
Wireshark shows the device answering with another (empty) bulk on every bulk write under Linux, while it does not show that under Windows. As far as I understand, that is because USBPcap cannot capture handshakes under Windows. But I am not shure with that, because I do not know if this type of response would really be classified as "URB_BULK out".
I tried libusb0, libusb1 and OpenUSB as backends under Linux, without success.
The bulk transfer in question is the transfer of FPGA firmware to the device.
I am able to communicate with the device before the multiple-512 byte-chunk bulk operation on the same endpoints using only a few bytes. The code that then causes the timeout is the following one in the second iteration of this for loop:
for chunk in chunks: # chunks: array of bytearrays with 512 bytes each
self.write(0x01,chunk)
time.sleep(0.003)
[Edit] The reason I found out that this only occurs on my test laptop using xhci, not on a second Linux test machine using ehci. So this might be caused by xhci. I do not yet have a workaround, but this at least gives an explanation.
It turns out that the device requested less bytes per packet, the desired amount of bytes (64) could be found in dmesg as already written in the question. Since xhci doesn't support that officially, Linux decided to ignore that request. Windows seemingly went with it and split larger packets up in the requested packet size. So the solution was to manually split the data to packets of 64 byte size before transferring it.

How to get a UART communication at 12 Mbps in linux (Raspbian)?

I am currently working on a Raspberry pi (Jessie Stretch), the issue is that I want to connect two FTDI FT2232H serially at 12 Mbps, but because 12Mbps is not a standard speed Raspbian does not allow me to add that baud rate. I would like to know if someone has transmitted at that speed or if someone knows how to achieve the Bit rate of 12 Mbps with the maximum baud rate in Raspbian (4,000,000) .
PS: I changed the UART clock to 64,000,000, modified the "termbits.h" library and created termios structures, but nothing worked.
Thanks.
The data sheet for the FT2232H does advertise it supports 12 Mbaud (not 12Mbps). But it looks like it comes in different modules with support for RS232, RS422, and RS485. The most typical being RS232.
I've never heard of anyone operating a RS232 connection at 120000000 baud. The typical maximum that almost everything supports is 115200. The highest I've seen is 921600. Typical RS232 cables started running into interference issues at the higher baud rates.
I suspect the 12Mbaud spec is for RS422/RS485 operation which requires different cabling and is designed for higher speeds.
If you're using an FT2232H with RS232, the speeds you're looking for are likely unrealistic. If you're using it with RS422/RS485 you can probably get there, but it will be a much more specialized endeavor. It does look like Linux does support RS485. But there's not nearly as much documentation out there as for RS232.
Can you provide any more information about the USB adapters you're using?

How to modify timing in readyRead of QextSeriaport [duplicate]

I'm implementing a protocol over serial ports on Linux. The protocol is based on a request answer scheme so the throughput is limited by the time it takes to send a packet to a device and get an answer. The devices are mostly arm based and run Linux >= 3.0. I'm having troubles reducing the round trip time below 10ms (115200 baud, 8 data bit, no parity, 7 byte per message).
What IO interfaces will give me the lowest latency: select, poll, epoll or polling by hand with ioctl? Does blocking or non blocking IO impact latency?
I tried setting the low_latency flag with setserial. But it seemed like it had no effect.
Are there any other things I can try to reduce latency? Since I control all devices it would even be possible to patch the kernel, but its preferred not to.
---- Edit ----
The serial controller uses is an 16550A.
Request / answer schemes tends to be inefficient, and it shows up quickly on serial port. If you are interested in throughtput, look at windowed protocol, like kermit file sending protocol.
Now if you want to stick with your protocol and reduce latency, select, poll, read will all give you roughly the same latency, because as Andy Ross indicated, the real latency is in the hardware FIFO handling.
If you are lucky, you can tweak the driver behaviour without patching, but you still need to look at the driver code. However, having the ARM handle a 10 kHz interrupt rate will certainly not be good for the overall system performance...
Another options is to pad your packet so that you hit the FIFO threshold every time. It will also confirm that if it is or not a FIFO threshold problem.
10 msec # 115200 is enough to transmit 100 bytes (assuming 8N1), so what you are seeing is probably because the low_latency flag is not set. Try
setserial /dev/<tty_name> low_latency
It will set the low_latency flag, which is used by the kernel when moving data up in the tty layer:
void tty_flip_buffer_push(struct tty_struct *tty)
{
unsigned long flags;
spin_lock_irqsave(&tty->buf.lock, flags);
if (tty->buf.tail != NULL)
tty->buf.tail->commit = tty->buf.tail->used;
spin_unlock_irqrestore(&tty->buf.lock, flags);
if (tty->low_latency)
flush_to_ldisc(&tty->buf.work);
else
schedule_work(&tty->buf.work);
}
The schedule_work call might be responsible for the 10 msec latency you observe.
Having talked to to some more engineers about the topic I came to the conclusion that this problem is not solvable in user space. Since we need to cross the bridge into kernel land, we plan to implement an kernel module which talks our protocol and gives us latencies < 1ms.
--- edit ---
Turns out I was completely wrong. All that was necessary was to increase the kernel tick rate. The default 100 ticks added the 10ms delay. 1000Hz and a negative nice value for the serial process gives me the time behavior I wanted to reach.
Serial ports on linux are "wrapped" into unix-style terminal constructs, which hits you with 1 tick lag, i.e. 10ms. Try if stty -F /dev/ttySx raw low_latency helps, no guarantees though.
On a PC, you can go hardcore and talk to standard serial ports directly, issue setserial /dev/ttySx uart none to unbind linux driver from serial port hw and control the port via inb/outb to port registers. I've tried that, it works great.
The downside is you don't get interrupts when data arrives and you have to poll the register. often.
You should be able to do same on the arm device side, may be much harder on exotic serial port hw.
Here's what setserial does to set low latency on a file descriptor of a port:
ioctl(fd, TIOCGSERIAL, &serial);
serial.flags |= ASYNC_LOW_LATENCY;
ioctl(fd, TIOCSSERIAL, &serial);
In short: Use a USB adapter and ASYNC_LOW_LATENCY.
I've used a FT232RL based USB adapter on Modbus at 115.2 kbs.
I get about 5 transactions (to 4 devices) in about 20 mS total with ASYNC_LOW_LATENCY. This includes two transactions to a slow-poke device (4 mS response time).
Without ASYNC_LOW_LATENCY the total time is about 60 mS.
With FTDI USB adapters ASYNC_LOW_LATENCY sets the inter-character timer on the chip itself to 1 mS (instead of the default 16 mS).
I'm currently using a home-brewed USB adapter and I can set the latency for the adapter itself to whatever value I want. Setting it at 200 µS shaves another mS off that 20 mS.
None of those system calls have an effect on latency. If you want to read and write one byte as fast as possible from userspace, you really aren't going to do better than a simple read()/write() pair. Try replacing the serial stream with a socket from another userspace process and see if the latencies improve. If they don't, then your problems are CPU speed and hardware limitations.
Are you sure your hardware can do this at all? It's not uncommon to find UARTs with a buffer design that introduces many bytes worth of latency.
At those line speeds you should not be seeing latencies that large, regardless of how you check for readiness.
You need to make sure the serial port is in raw mode (so you do "noncanonical reads") and that VMIN and VTIME are set correctly. You want to make sure that VTIME is zero so that an inter-character timer never kicks in. I would probably start with setting VMIN to 1 and tune from there.
The syscall overhead is nothing compared to the time on the wire, so select() vs. poll(), etc. is unlikely to make a difference.

USB-Serial communication giving strange output

I'm trying to get data from a mercury analyzer (Seefelder-Messtechnik Hg Analyzer 3000) that gives output to a 9-pin R232 serial port to my OSX 10.10 laptop.
I've followed the steps described here to install the PL-2303 driver:
http://pbxbook.com/other/mac-tty.html
The device manual (http://www.seefelder-messtechnik.com/V71-3-02-21e.pdf) lists the communication protocol as "9600 Baud, 8 data bit, 1 stop bit, no log,
no parities".
I attempt to read from the device by using the 'screen' command:
screen /dev/tty.usbserial 9600
The result is a string of seemingly non-sensical characters that print to the screen in a regular interval:
�8b4����b��8b48bs��8G�8b�8���8������8����< 8�8��b��KW��\b����8b����b� �b�b����KW�K �8b��\G�� �<���8�8b�"��΁�[؁��؉���bG�3�ˁ�G��\K��[W�pb�8��΁8ʱ�\pa���ʁ�c t��8�h¡�38b�8�q�؁����\�8���bS�8b8�8�q���X��8��<��£8���2�8�����ؖ�ؖ�ؖ�8bS��\�܉�ؖ����[S�8��s���fq�8�����������8fq����������S�܊��b���b�؉����\���S��K���ݎ����S��b��b��S����S�\������KS��S�؊��\S�1S�\b�S�؉�\�ذ����KS�\����S����bS�؉�����1S�؊��[؂����ز������؉\�؂��ز��\����i���$\�$���\��8���$��\�\����܂�زXk�B��7��\k�\X�<��8Xkz��Yj��L�������H�\���]j�،k:��Yj�؈��
I've also tried using 'minicom' rather than screen, and get a different ("?]???ܰ??Yk??2"), but also non-sensical result. I saw that there was another SO query similar to mine that remains unsolved: weird characters displayed during serial communication OSX
Any tips? It looks to me that I'm not interpreting the output correctly, but I don't know what to try next.
The solution was to read from the machine at a higher baud rate (~57600), despite what the manual and online reference said. Reading at 57600 baud made the result plain-text and usable. Thanks for your ideas!
I've followed the steps described here to install the PL-2303 driver
I've also had occasional electrical ground problems with Prolific USB-RS232 adapters. Problem would manifest as garbled data that looked similar to a baud rate issue or what you posted.
You can check if it's a ground issue by measuring for continuity between the ground pin (pin #5) on the DE-9 (aka DB-9) side of the Prolific adapter and the ground pin of the USB side (pin #4, "far left", of the A connector). You'll probably measure infinite resistance with a multimeter. Try the same with a FTDI USB-RS232 adapter, and instead I get a dead short between the ground pins as expected.
Be sure to plug the instrument's and PC's power supplies into the same power strip.
As a last resort try grounding the instrument's chassis/case with the PC using copper wire

Resources