serialext
- UART API
There is no dedicated module for the UART API, as PyFtdi acts as a backend of the well-known pyserial module.
The pyserial backend module is implemented as the serialext.protocol_ftdi module. It is not documented here as no direct call to this module is required, as the UART client should use the regular pyserial API.
Usage
To enable PyFtdi as a pyserial backend, use the following import:
import pyftdi.serialext
Then use
pyftdi.serialext.serial_for_url(url, **options)
to open a pyserial serial port instance.
Quickstart
# Enable pyserial extensions
import pyftdi.serialext
# Open a serial port on the second FTDI device interface (IF/2) @ 3Mbaud
port = pyftdi.serialext.serial_for_url('ftdi://ftdi:2232h/2', baudrate=3000000)
# Send bytes
port.write(b'Hello World')
# Receive bytes
data = port.read(1024)
GPIO access
UART mode, the primary function of FTDI *232* devices, is somewhat limited when it comes to GPIO management, as opposed to alternative mode such as I2C, SPI and JTAG. It is not possible to assign the unused pins of an UART mode to arbitrary GPIO functions.
All the 8 lower pins of an UART port are dedicated to the UART function, although most of them are seldomely used, as dedicated to manage a modem or a legacy DCE device. Upper pins (b7..b15), on devices that have ones, cannot be driven while UART port is enabled.
It is nevertheless possible to have limited access to the lower pins as GPIO, with many limitations:
the GPIO direction of each pin is hardcoded and cannot be changed
GPIO pins cannot be addressed atomically: it is possible to read the state of an input GPIO, or to change the state of an output GPIO, one after another. This means than obtaining the state of several input GPIOs or changing the state of several output GPIO at once is not possible.
some pins cannot be used as GPIO is hardware flow control is enabled. Keep in mind However that HW flow control with FTDI is not reliable, see the Hardware flow control section.
Accessing those GPIO pins is done through the UART extended pins, using their UART assigned name, as PySerial port attributes. See the table below:
Bit |
UART |
Direction |
API |
---|---|---|---|
b0 |
TX |
Out |
|
b1 |
RX |
In |
|
b2 |
RTS |
Out |
|
b3 |
CTS |
In |
|
b4 |
DTR |
Out |
|
b5 |
DSR |
In |
|
b6 |
DCD |
In |
|
b7 |
RI |
In |
|
CBUS support
Some FTDI devices (FT232R, FT232H, FT230X, FT231X) support additional CBUS pins, which can be used as regular GPIOs pins. See CBUS GPIO for details.
Mini serial terminal
pyterm.py
is a simple serial terminal that can be used to test the serial
port feature. See the Tools chapter to locate this tool.
Usage: pyterm.py [-h] [-f] [-b BAUDRATE] [-w] [-e] [-r] [-l] [-s] [-P VIDPID]
[-V VIRTUAL] [-v] [-d]
[device]
Simple Python serial terminal
positional arguments:
device serial port device name (default: ftdi:///1)
optional arguments:
-h, --help show this help message and exit
-f, --fullmode use full terminal mode, exit with [Ctrl]+B
-b BAUDRATE, --baudrate BAUDRATE
serial port baudrate (default: 115200)
-w, --hwflow hardware flow control
-e, --localecho local echo mode (print all typed chars)
-r, --crlf prefix LF with CR char, use twice to replace all LF
with CR chars
-l, --loopback loopback mode (send back all received chars)
-s, --silent silent mode
-P VIDPID, --vidpid VIDPID
specify a custom VID:PID device ID, may be repeated
-V VIRTUAL, --virtual VIRTUAL
use a virtual device, specified as YaML
-v, --verbose increase verbosity
-d, --debug enable debug mode
If the PyFtdi module is not yet installed and pyterm.py
is run from the
archive directory, PYTHONPATH
should be defined to the current directory:
PYTHONPATH=$PWD pyftdi/bin/pyterm.py ftdi:///?
The above command lists all the available FTDI device ports. To avoid conflicts
with some shells such as zsh, escape the ? char as ftdi:///\?
.
To start up a serial terminal session, specify the FTDI port to use, for example:
# detect all FTDI connected devices
PYTHONPATH=. python3 pyftdi/bin/ftdi_urls.py
# use the first interface of the first FT2232H as a serial port
PYTHONPATH=$PWD pyftdi/bin/pyterm.py ftdi://ftdi:2232/1
Limitations
Although the FTDI H series are in theory capable of 12 MBps baudrate, baudrates above 6 Mbps are barely usable.
See the following table for details.
Requ. bps |
HW capability |
9-bit time |
Real bps |
Duty cycle |
Stable |
---|---|---|---|---|---|
115.2 Kbps |
115.2 Kbps |
78.08 µs |
115.26 Kbps |
49.9% |
Yes |
460.8 Kbps |
461.54 Kbps |
19.49 µs |
461.77 Kbps |
49.9% |
Yes |
1 Mbps |
1 Mbps |
8.98 µs |
1.002 Mbps |
49.5% |
Yes |
4 Mbps |
4 Mbps |
2.24 µs |
4.018 Mbps |
48% |
Yes |
5 Mbps |
5.052 Mbps |
1.78 µs |
5.056 Mbps |
50% |
Yes |
6 Mbps |
6 Mbps |
1.49 µs |
6.040 Mbps |
48.5% |
Yes |
7 Mbps |
6.857 Mbps |
1.11 µs |
8.108 Mbps |
44% |
No |
8 Mbps |
8 Mbps |
1.11 µs |
8.108 Mbps |
44%-48% |
No |
8.8 Mbps |
8.727 Mbps |
1.13 µs |
7.964 Mbps |
44% |
No |
9.6 Mbps |
9.6 Mbps |
1.12 µs |
8.036 Mbps |
48% |
No |
10.5 Mbps |
10.667 Mbps |
1.11 µs |
8.108 Mbps |
44% |
No |
12 Mbps |
12 Mbps |
0.75 µs |
12 Mbps |
43% |
Yes |
9-bit time is the measured time @ FTDI output pins for a 8-bit character (start bit + 8 bit data)
Duty cycle is the ratio between a low-bit duration and a high-bit duration, a good UART should exhibit the same duration for low bits and high bits, i.e. a duty cycle close to 50%.
Stability reports whether subsequent runs, with the very same HW settings, produce the same timings.
Achieving a reliable connection over 6 Mbps has proven difficult, if not impossible: Any baudrate greater than 6 Mbps (except the upper 12 Mbps limit) results into an actual baudrate of about 8 Mbps, and suffer from clock fluterring [7.95 .. 8.1Mbps].
Hardware flow control
Moreover, as the hardware flow control of the FTDI device is not a true HW flow control. Quoting FTDI application note:
If CTS# is logic 1 it is indicating the external device cannot accept more data. the FTxxx will stop transmitting within 0~3 characters, depending on what is in the buffer. This potential 3 character overrun does occasionally present problems. Customers shoud be made aware the FTxxx is a USB device and not a “normal” RS232 device as seen on a PC. As such the device operates on a packet basis as opposed to a byte basis.