ftdi-ft232h
The ftdi-ft232h driver runs an FTDI FT232H USB adapter in its Multi-Protocol
Synchronous Serial Engine (MPSSE) mode. One adapter gives you an SPI controller
and up to 16 GPIO pins at the same time. Any channel, on any of the three chips, can
run as a UART instead (see UART channels).
| Property | Value |
|---|---|
kind | ftdi-ft232h |
| Interfaces | spi, gpio, relay, uart, tty |
location | usb:<vid>:<pid>[:<serial>|@<usb_path>] |
Example
mpsse:
kind: ftdi-ft232h
name: "FTDI FT232H"
description: "MPSSE adapter for SPI + GPIO bring-up"
location: usb:0403:6014:FT4ABC123
interfaces:
- type: spi
channel: 0
- type: gpio
channel: 0
config:
pins:
- { pin: 4, name: GPIOL0, direction: output, initial: low }
- { pin: 5, name: GPIOL1, direction: input }
- { pin: 12, name: reset_n, direction: output, active_level: low, initial: low }
- { pin: 13, name: shared_irq, direction: output, drive_mode: open_drain, initial: high }
- { pin: 14, name: boot_sense, direction: input }
Location
The location identifies the adapter by its USB vendor and product ID, written as four hex digits each:
| Form | Matches |
|---|---|
usb:0403:6014 | The first FT232H the bench finds. |
usb:0403:6014:FT4ABC123 | The FT232H with serial number FT4ABC123. |
usb:0403:6010@1-2.1 | The FT2232H at USB port 1-2.1. |
Use the serial-number form whenever the adapter has one. It keeps pointing at
the same adapter when you add a second one or move it to another USB port.
mimick peripheral list shows the location of every FT232H the bench detects.
If you attach more than one FT232H, give each one a serial number. Without one, the bench opens the first FT232H it finds. If a chip has no serial number, use the USB port form to tell it from the others.
The FT232H has a single MPSSE channel, so every interface uses channel 0.
UART channels
Declare a channel as uart to run it as a serial port. You can do this on any
channel of any of the three chips, including FT4232H channels C and D. A UART
channel can't also run spi, i2c, or gpio, but the other channels of the
same chip can. The bench opens the chip directly, so no /dev/ttyUSB* device
appears.
ft2232h:
kind: ftdi-ft232h
name: "Dual UART"
location: usb:0403:6010@1-2.1
interfaces:
- type: uart
channel: 0
config: { baud_rate: 115200 }
- type: tty
channel: 0
backed_by: { type: uart, channel: 0 }
- type: uart
channel: 1
config: { baud_rate: 115200, latency_ms: 1, initial_dtr: released }
The uart config takes the same baud_rate, data_bits, parity,
stop_bits, and flow_control keys as linux-tty.
The chip supports 7 or 8 data bits. It also takes:
| Key | Default | Meaning |
|---|---|---|
latency_ms | 1 | How long the chip holds a partial packet before it reaches the bench, from 1 to 255. |
initial_dtr, initial_rts | released | asserted or released. Applied on every open, before the first byte moves. |
log_delimiter, log_delimiter_hex | \n with a tty, none without | Text or hex bytes that end a row of the data recorder, such as "\r\n" or "7e". Set one, not both. |
queued_writes | true with a tty on the channel, else false | true returns a console or exec write once it is queued. false returns after the chip took it. |
queue_depth | 64 | How many writes can wait. Used only when queued_writes is true. Must be above 0. |
The data recorder logs every byte the channel receives or sends. A row ends at
the delimiter, after 2 ms with no new bytes, or at 4 KiB, whichever comes
first. A row that arrives with a framing, parity, overrun or break error
carries it as uart.flags.
A full queue makes the next write wait for room instead of losing it. uart write always reports the chip's own result.
A low latency_ms keeps each request and response fast. Set initial_dtr or
initial_rts to asserted if your board holds its MCU in reset or in its
bootloader while a line is asserted.
You can change the baud rate, data bits, parity, stop bits, and flow control on
an open port without reopening it. A tty interface must use backed_by with
the uart of the same channel.
A MIMICK HWI v2 board is built on an FT2232H too. Declare it as
mimick-hwi instead, which
serves its DUT console with the same uart keys.
Multi-channel chips
The FT2232H (0403:6010) has channels A and B, and the FT4232H (0403:6011)
has A to D. Set channel on an interface to 0 for A, 1 for B, 2 for C,
and 3 for D. SPI, I2C, and GPIO run on the channels with an MPSSE engine: A
and B on both chips. The bench rejects the file if you name a channel the chip
doesn't have, or use one of those protocols on FT4232H channel C or D.
Declare every channel of a chip under the one peripheral that owns its location. Each channel works on its own, so a long SPI transfer on channel A doesn't hold up channel B.
A board whose EEPROM is blank has no serial number. Address it by the USB port
instead, with usb:<vid>:<pid>@<usb_path>, as in the example below.
hwi:
kind: ftdi-ft232h
location: usb:0403:6010@1-2.1
interfaces:
- type: spi
channel: 0
- type: gpio
channel: 1
config:
pins:
- { pin: 4, name: boot, direction: output, initial: low }
If you unplug the chip, every channel of it goes absent, and plugging it back in
restores them. A relay interface drives the peripheral's one gpio interface,
so you can't combine relay with gpio on more than one channel.
SPI
The spi interface takes no settings in the file. It runs in SPI mode 0 at
1 MHz.
Declaring spi claims pins 0 through 3 (SCK, MOSI, MISO, and CS), so those pins
aren't available to the gpio interface.
mimick spi mpsse.spi0 transfer badf00d
GPIO
The gpio interface takes a pins list. Each entry configures one pin.
| Key | Required | Default | Allowed values |
|---|---|---|---|
pin | Yes | 0 to 15 (see Pin numbers) | |
direction | Yes | input or output | |
name | No | Chip name | Any label. The CLI accepts it in place of the number. |
initial | No | low | high or low. Outputs only. |
active_level | No | high | high or low. Outputs only. |
drive_mode | No | push_pull | push_pull, open_drain, or open_source. Outputs only. |
Each pin appears at most once. Setting initial, active_level, or
drive_mode on an input is an error.
initial is a logical level, applied through active_level and drive_mode.
In the example, reset_n starts deasserted, so the pin drives high. shared_irq
starts released, so the pin floats at high impedance.
Pin numbers
pin is the MPSSE bit index, not the package pin on the datasheet. The package
pins below are the FT232H's, and other chips report 0. On channel B the names
start with BDBUS instead of ADBUS. The FT4232H has only pins 0 to 7 on each
channel:
pin | Signal | Package pin |
|---|---|---|
| 0 to 3 | ADBUS0 to ADBUS3 (SCK, MOSI, MISO, CS with SPI) | 13 to 16 |
| 4 to 7 | GPIOL0 to GPIOL3 | 17 to 20 |
| 8 | GPIOH0 | 21 |
| 9 to 15 | GPIOH1 to GPIOH7 | 25 to 31 |
mimick gpio list shows all three for every pin.
Open-drain and open-source outputs
The FT232H has no native open-drain output, so the bench releases the pin to an
input for the level it doesn't drive. A released pin is pulled toward VCCIO by a
weak internal resistor (about 75 kΩ), except pin 15, which pulls down to ground.
Fit an external pull-up for open_drain or a pull-down for open_source, sized
for your bus.
Reading a released pin samples the line, so it can differ from the level you last wrote. That tells you whether something else is holding the line.
Relay channels over pins
A relay interface presents output pins as on/off relay channels. It takes the
same channels list as the other relay
drivers, except each path is GPIO: followed by the name or number of a pin
listed under the gpio interface's pins:
- type: relay
channel: 0
config:
channels:
- { number: 1, name: "Reset", path: "GPIO:reset_n" }
The pin can't be declared as an input, and two channels can't share a pin. A
channel is on while its pin is at the pin's active_level. With a relay
interface present, address the GPIO as -p mpsse.gpio0 and the relay as
-p mpsse.relay0.
Use it
mimick gpio list -p mpsse.gpio0
mimick gpio write -p mpsse.gpio0 reset_n on
mimick gpio watch -p mpsse.gpio0 boot_sense
In the web UI, select Open GPIO controls on the peripheral's row in the bench's Inventory tab.