Not all USB-UART adapters are the same!

I have three USB-UART adapters, the first is a PL2303 from “Prolific Technology”, the second one is a CH340 from “QinHeng Electronics” and the other is a CP2102 from “Silicon Labs” and I tried to use them in a project involving non-standard baud-rate (1600 bps) on the serial bus.

The PL2303 and the CH340 are capable of non-standard baud-rate talking as long as a fixed parity setting (ODD, EVEN, NONE, MARK or SPACE) is used.

The CP2102 is not capable of non-standard baud-rate communication at all.

I checked with a logic analyzer and some python lines, here are the results.

The test code

import time
import serial

ser = serial.Serial(
    port='/dev/ttyUSB0',
    baudrate=1200, # 1200 or 1600
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=None
)

while True:

    ser.write(b'\x01\x02\x03\x04\x05\xFF\x00')
    time.sleep(2)

Silicon Labs CP2102 test restults

CP2102 @ 1200 bps (standard) – OK
CP2102 @ 1600 bps (non-standard) – BAD DATA

Prolific Technology PL2303 test results

PL2303 @ 1200 bps (standard) – OK
PL2303 @ 1600 bps (non-standard) – OK

QinHeng Electronics CH340 test results

CH340 @ 1200 bps (standard) – OK
CH340 @ 1600 bps (non-standard) – OK

How about 9-Bit framing also know as Multi-Drop Bus (MDB)?

Neither device is capable of talking on a Multi-Drop Bus.

Serial communication with 9-Bit framing (9-Bit protocol, 9 bit mode) is mainly used to identify the address byte within messages running on a RS-485/RS-232 multi-drop network.

On this type of network one “master” controls one or many “slaves”, the 9th bit is used to distinguish the address from the data.

This type of protocol is not a POSIX-standard, but some devices supports the Mark/Space Parity (CMSPAR) and can use the “Parity Bit” to emulate the 9th data bit.

Acting as TX device, the UART parity settings needs to be set accordly with the type of byte to send: sending an address the parity needs to be set to “MARK” (logic 1), for the data parts the parity needs to be set to “SPACE” (logic 0).

Changing MARK to SPACE parity settings on the fly (reconfigure the UART without closing and reopening the port) is supported by PySerial, but my devices are not behaving as expected.

Acting as RX device, the value of the 9th bit can be recovered observing the parity-error. For example: settings the UART with SPACE parity, we should receive a parity-error when an “address” is received.

Unfortunately, this does not work with any of my devices via PySerial library.