CircuitsFT232H. MPSSE
(circuits_ft232h v0.1.0)
Copy Markdown
Pure-function encoder for the FT232H Multi-Protocol Synchronous Serial Engine (MPSSE) command stream.
This module knows nothing about USB or transports. It builds binaries you
hand to CircuitsFT232H.USB.write/3, and helps interpret bytes you read
back via CircuitsFT232H.USB.read/3.
Opcode names and semantics mirror FTDI Application Note AN_108.
Summary
Types
Order in which a byte's bits are clocked out / in.
Which MPSSE base clock to compute against.
Clock edge on which a data bit is driven or sampled.
Functions
The MPSSE byte that precedes the echo of an unrecognised opcode.
Computes the MPSSE divisor that produces target_hz SCK, given the base
clock.
Disables 3-phase data clocking (normal 2-phase SPI behaviour).
Disables adaptive clocking (the chip's default).
Selects the 60 MHz MPSSE base clock (H-series chips only). Required for SCK frequencies above 6 MHz.
Enables 3-phase data clocking. Required for I2C, and for SPI modes that
drive on one edge and sample on the same edge (CPHA = 1).
Enables adaptive clocking — MPSSE pauses after each clock pulse until
GPIOL3 (ADBUS7) is driven high.
Selects the legacy 12 MHz MPSSE base clock (for compatibility with FT2232D-style code).
Configures pins to operate in open-drain mode.
Scans response for a BAD_COMMAND marker (0xFA) and returns the
offending opcode if found.
Reads the current state of ACBUS0..ACBUS7. Response is 1 byte.
Reads the current state of ADBUS0..ADBUS7. Response is 1 byte.
Disables internal loopback (the normal state).
Enables internal TDI→TDO loopback. Useful for init self-tests.
Clocks count bits in from TDO/DI. Response is one byte; the relevant
bits are right-justified (MSB-first) or left-justified (LSB-first)
depending on :bit_order.
Reads count bytes in on the TDO/DI pin while clocking SCK. No data is
driven out.
Returns the SCK frequency produced by the given divisor on the given base
clock. Inverse of clock_divisor/2 (with rounding).
Flushes any pending bytes in the chip's internal IN buffer back to the host. Append this whenever you need to read a response right away.
Sets the high-byte GPIO port (ACBUS0..ACBUS7) state. See set_bits_low/2.
Sets the low-byte GPIO port (ADBUS0..ADBUS7) state.
Sets the SCK clock divisor. Get the right divisor via clock_divisor/2.
Full-duplex bit transfer. Drives the bottom count bits of value while
sampling TDO/DI. Response is one byte.
Full-duplex byte transfer — drives data out on TDI/DO and simultaneously
samples TDO/DI back. The response is byte_size(data) bytes long.
Writes the bottom count bits of value out the TDI/DO pin while
clocking SCK. count must be in 1..8.
Writes data out the TDI/DO pin while clocking SCK.
Types
@type bit_order() :: :msb_first | :lsb_first
Order in which a byte's bits are clocked out / in.
@type clock_base() :: :high_speed | :legacy
Which MPSSE base clock to compute against.
@type clock_edge() :: :positive | :negative
Clock edge on which a data bit is driven or sampled.
Functions
@spec bad_command_byte() :: byte()
The MPSSE byte that precedes the echo of an unrecognised opcode.
@spec clock_divisor(pos_integer(), clock_base()) :: 0..65535
Computes the MPSSE divisor that produces target_hz SCK, given the base
clock.
Use :high_speed (default) for the 60 MHz base (FT232H, requires
disable_clock_divide_by_5/0) and :legacy for the 12 MHz base
(FT2232D-compatible, requires enable_clock_divide_by_5/0).
The formula is SCK = base / ((1 + divisor) × 2). Result is rounded and
clamped to 0..0xFFFF.
@spec disable_3_phase_clocking() :: binary()
Disables 3-phase data clocking (normal 2-phase SPI behaviour).
@spec disable_adaptive_clocking() :: binary()
Disables adaptive clocking (the chip's default).
@spec disable_clock_divide_by_5() :: binary()
Selects the 60 MHz MPSSE base clock (H-series chips only). Required for SCK frequencies above 6 MHz.
@spec enable_3_phase_clocking() :: binary()
Enables 3-phase data clocking. Required for I2C, and for SPI modes that
drive on one edge and sample on the same edge (CPHA = 1).
@spec enable_adaptive_clocking() :: binary()
Enables adaptive clocking — MPSSE pauses after each clock pulse until
GPIOL3 (ADBUS7) is driven high.
Originally designed so MPSSE could synchronise with an ARM target's
RTCK signal, this gives a free clock-stretching mechanism for I2C if
ADBUS0 (SCL) is externally jumpered to ADBUS7: the slave can hold
SCL low and MPSSE will wait for it.
@spec enable_clock_divide_by_5() :: binary()
Selects the legacy 12 MHz MPSSE base clock (for compatibility with FT2232D-style code).
Configures pins to operate in open-drain mode.
Pins set in the masks drive low when their output bit is 0, and are
tristated when their output bit is 1. Combined with external pull-up
resistors this provides true open-drain behaviour — the key trick that
makes I2C work on the FT232H.
Available on FT232H only (not FT2232D / FT2232C).
Scans response for a BAD_COMMAND marker (0xFA) and returns the
offending opcode if found.
@spec get_bits_high() :: binary()
Reads the current state of ACBUS0..ACBUS7. Response is 1 byte.
@spec get_bits_low() :: binary()
Reads the current state of ADBUS0..ADBUS7. Response is 1 byte.
@spec loopback_off() :: binary()
Disables internal loopback (the normal state).
@spec loopback_on() :: binary()
Enables internal TDI→TDO loopback. Useful for init self-tests.
Clocks count bits in from TDO/DI. Response is one byte; the relevant
bits are right-justified (MSB-first) or left-justified (LSB-first)
depending on :bit_order.
Same options as read_bytes/2.
@spec read_bytes( pos_integer(), keyword() ) :: iodata()
Reads count bytes in on the TDO/DI pin while clocking SCK. No data is
driven out.
Options:
:edge(default:positive) — clock edge on which to sample each bit.:bit_order(default:msb_first).
@spec sck_frequency(0..65535, clock_base()) :: float()
Returns the SCK frequency produced by the given divisor on the given base
clock. Inverse of clock_divisor/2 (with rounding).
@spec send_immediate() :: binary()
Flushes any pending bytes in the chip's internal IN buffer back to the host. Append this whenever you need to read a response right away.
Sets the high-byte GPIO port (ACBUS0..ACBUS7) state. See set_bits_low/2.
Sets the low-byte GPIO port (ADBUS0..ADBUS7) state.
value is the level each output pin should drive (bit 0 = ADBUS0).
direction is the per-pin direction mask — 1 for output, 0 for input.
In MPSSE mode the engine overrides direction for SCK / MOSI / MISO so it
is safe to leave those as outputs in the direction mask.
@spec set_tck_divisor(0..65535) :: binary()
Sets the SCK clock divisor. Get the right divisor via clock_divisor/2.
Full-duplex bit transfer. Drives the bottom count bits of value while
sampling TDO/DI. Response is one byte.
Same options as transfer_bytes/2.
Full-duplex byte transfer — drives data out on TDI/DO and simultaneously
samples TDO/DI back. The response is byte_size(data) bytes long.
Options:
:write_edge(default:negative) — clock edge on which to drive.:read_edge(default:positive) — clock edge on which to sample.:bit_order(default:msb_first).
Writes the bottom count bits of value out the TDI/DO pin while
clocking SCK. count must be in 1..8.
Same options as write_bytes/2.
Writes data out the TDI/DO pin while clocking SCK.
Options:
:edge(default:negative) — clock edge on which to drive each bit.:bit_order(default:msb_first) — bit order within each byte.
The chip transmits byte_size(data) bytes. The command auto-splits into
multiple 0x1? blocks if data is longer than 65536 bytes.