FT232R and FT245R
The fourth generation of fixed-function D2xx devices, an upgrade to FT232B and FT245B. The devices are:
- FT232RL: UART mode, 28-pin TSSOP
- FT232RQ: UART mode, 32-pin QFN
- FT245RL: FIFO mode, 28-pin TSSOP
- FT245RQ: FIFO mode, 32-pin QFN
- FT232RNL: revised version, UART mode, 28-pin TSSOP
- FT232RNQ: revised version, UART mode, 32-pin QFN
- FT245RNL: revised version, FIFO mode, 28-pin TSSOP
- FT245RNQ: revised version, FIFO mode, 32-pin QFN
FT232R and FT245R are the exact same device, and differ only in a configuration bit in the internal EEPROM. That bit can just be reprogrammed by the user. Likewise, FT232RN and FT245RN are the exact same device.
The FT2xxRN is a minor revision of FT2xxR, making the internal oscillator work when powered by 3.3V VCC.
Features:
- is a full-speed USB 1.1 peripherial
- single channel D2xx device, set to either UART or FIFO base mode by EEPROM
- in UART mode, the device has 5 CBUS pins that can be programmed (via EEPROM) to a variety of functions
- added EEPROM-programmable signal inversion on all UART pins
- dynamically-selectable alternate modes include:
- FT2xxB-like async bitbang
- FT2232-like sync bitbang
- a new CBUS bitbang mode
- 256-byte IN FIFO, 128-byte OUT FIFO
- internal EEPROM, replacing the external EEPROM interface of FT2xxB
- pre-programmed factory area in EEPROM, including a unique chip ID
- 48MHz internal base clock, generated from either internal 12MHz oscillator or external 12MHz crystal
- external oscillator has to be selected through EEPROM configuration
- internal oscillator doesn't work on 3.3V VCC on the original FT2xxR
- ... leading to a fun factory programming procedure if you wish to use the device on 3.3V VCC, which likely further motivated the FT2xxRN revision
- 3.3V or 5V VCC supply for internal circuitry
- separate 1.8V to 5V VCCIO supply for business-end IO
- internal 5V-to-3.3V LDO
- internal D+ pullup resistor
- internal power-on reset circuit
- required external support circuitry:
- just the decoupling capacitors
The default VID:PID of the device is 0403:6001 (FT2xxR) or 0403:6049 (FT2xxRN), unless configured otherwise by the EEPROM. The bcdDevice value is 0x0600.
Pinout
| QFN32 | TSSOP28 | category | FT232R | FT245R |
|---|---|---|---|---|
| 1 | 4 | power | VCCIO | VCCIO |
| 2 | 5 | IO-DBUS | RXD | D1 |
| 3 | 6 | IO-DBUS | RI# | D7 |
| 4 | 7 | power | GND | GND |
| 5 | 8 | NC? | - | - |
| 6 | 9 | IO-DBUS | DSR# | D5 |
| 7 | 10 | IO-DBUS | DCD# | D6 |
| 8 | 11 | IO-DBUS | CTS# | D3 |
| 9 | 12 | IO-CBUS | CBUS4 | PWREN# |
| 10 | 13 | IO-CBUS | CBUS2 | RD# |
| 11 | 14 | IO-CBUS | CBUS3 | WR |
| 12 | - | NC | - | - |
| 13 | - | NC | - | - |
| 14 | 15 | USB | USBDP | USBDP |
| 15 | 16 | USB | USBDN | USBDN |
| 16 | 17 | power | 3V3OUT | 3V3OUT |
| 17 | 18 | power | GND | GND |
| 18 | 19 | control | RESET# | RESET# |
| 19 | 20 | power | VCC | VCC |
| 20 | 21 | power | GND | GND |
| 21 | 22 | IO-CBUS | CBUS1 | TXE# |
| 22 | 23 | IO-CBUS | CBUS0 | RXF# |
| 23 | 24 | NC? | - | - |
| 24 | 25 | power | AGND | AGND |
| 25 | - | NC | - | - |
| 26 | 26 | control | TEST | TEST |
| 27 | 27 | clock | OSCI | OSCI |
| 28 | 28 | clock | OSCO | OSCO |
| 29 | - | NC | - | - |
| 30 | 1 | IO-DBUS | TXD | D0 |
| 31 | 2 | IO-DBUS | DTR# | D4 |
| 32 | 3 | IO-DBUS | RTS# | D2 |
TODO: FT245R datasheet and FT_PROG claim that CBUS pins are not programmable on the FT245R and perform fixed functions. This is most likely to be a lie.
CBUS pins
The device has 5 CBUS pins. They can be configured through the EEPROM to do the following functions:
| EEPROM value | valid on pins | function |
|---|---|---|
0x0 | all | UART TXDEN |
0x1 | all | PWREN# |
0x2 | all | UART RXLED# |
0x3 | all | UART TXLED# |
0x4 | all | UART TXRXLED# |
0x5 | all | SLEEP# |
0x6 | all | CLK48 |
0x7 | all | CLK24 |
0x8 | all | CLK12 |
0x9 | all | CLK6 |
0xa | CBUS0-CBUS3 | I/O (for CBUS bitbang mode) |
0xb | CBUS0-CBUS3 | bitbang WR# |
0xc | CBUS0-CBUS3 | bitbang RD# |
0xd | CBUS0 | FIFO RXF# |
0xd | CBUS1 | FIFO TXE# |
0xd | CBUS2 | FIFO RD# |
0xd | CBUS3 | FIFO WR |
TODO: this list (particularly "valid on pins" and everything relating to FT245R) should be deemed extremely suspicious, as it seems to differ a lot between the datasheet, FT_PROG, and libftd2xx, and also doesn't seem to make all that much sense. The above is merely a least-squares approximation assembled from multiple lying sources.
The factory-programmed defaults are as follows:
| pin | FT232R | FT245R |
|---|---|---|
| CBUS0 | TXLED# | RXF# |
| CBUS1 | RXLED# | TXE# |
| CBUS2 | TXDEN | RD# |
| CBUS3 | PWREN# | WR |
| CBUS4 | SLEEP# | PWREN# |
The TXDEN, TXLED#, RXLED#, PWREN# and SLEEP# functions perform the same role as corresponding FT232B pins. TXRXLED# is a composite LED output, showing both TX and RX activity. CLK* functions provide a clock output of the selected frequency (6 to 48MHz).
EEPROM format
The device has a 40×32-bit internal EEPROM. However, it pretends to be a 80×16-bit word EEPROM on the USB interface. Words 0x00..0x40 are user-programmable, while words 0x40..0x50 contain factory-programmed data and are (allegedly) immutable. Note that the factory area is not covered by the checksum (or maybe has its own checksum).
The device introduces a simple "EEPROM write lock" mechanism: the EEPROM can only be programmed when the current latency timer is set to 0x77.
The "erase EEPROM" request is not supported on FT2xxR (presumably because, if supported, it'd erase the entire EEPROM along with factory data).
The 32-bit dword internal organization of the EEPROM is completely transparent on reads: the device will read the whole dword and reply to the USB request with just the relevant half of it. However, writes need to be handled specially:
- when the device receives a "write EEPROM word" request for an even-address word, the data is stored in an internal register, but EEPROM is not modified
- when the device receives a "write EEPROM word" request for an odd-address word, the data is combined together with the last data word previously stored in the register by an even-address write, and the whole 32-bit dword is written into EEPROM
This effectively means that EEPROM writes always have to be issued in aligned word pairs to work properly. In an infamous incident, FTDI Windows drivers abused this subtle behavior (which FT2xxR clones generally didn't replicate) to selectively brick clone devices.
The EEPROM format is:
- word 0x00:
- bit 0: device kind
- 0: FT232R
- 1: FT245R
- NOTE: the vendor programming tools go out of their way to preserve the value of this bit. However, using the raw control requests, it can be modified just fine, turning an FT232R device into an FT245R or vice-versa.
- bit 1: use external oscillator
- bit 2: high-current IO
- bit 3: enable bind to VCP driver
- bit 4: regulator on during suspend
- bit 8-15: bulk endpoint max packet size (0x40 by default)
- note: badly-programmed devices exist with this field set to 0; this needs to be worked around in the driver
- TODO: it is unclear whether this applies to IN, OUT, or both
- bit 0: device kind
- word 0x01: idVendor (USB VID)
- word 0x02: idProduct (USB PID)
- word 0x03: bcdDevice (0x600)
- word 0x04: USB config (goes straight to configuration descriptor)
- bits 0-7: bmAttributes
- bit 5: remote wakeup enabled
- bit 6: self-powered
- bit 7: always set to 1
- bits 8-15: bMaxPower (max power in units of 2mA)
- bits 0-7: bmAttributes
- word 0x05: device control
- bit 2: IO pulldown in suspend
- bit 3: serial number enabled
- bit 8: invert TXD (FT232R only)
- bit 9: invert RXD (FT232R only)
- bit 10: invert RTS (FT232R only)
- bit 11: invert CTS (FT232R only)
- bit 12: invert DTR (FT232R only)
- bit 13: invert DSR (FT232R only)
- bit 14: invert DCD (FT232R only)
- bit 15: invert RI (FT232R only)
- word 0x06: bcdUSB (always 2.0?)
- word 0x07: manufacturer string pointer
- word 0x08: product description string pointer
- word 0x09: serial number string pointer
- word 0x0a:
- bits 0-3: CBUS0 function (see table above)
- bits 4-7: CBUS1 function
- bits 8-11: CBUS2 function
- bits 12-15: CBUS3 function
- word 0x0b:
- bits 0-3: CBUS4 function
- words 0x0c..0x3f: string / user area
- word 0x3f: checksum
- words 0x40..0x50: factory data (mostly unknown)
- word 0x42:
- bit 1: is FT2xxRN
- word 0x43: low word of unscrambled chipid (unique per-device ID)
- word 0x44: high word of unscrambled chipid
- word 0x42:
String pointers are formatted as follows:
- bits 0-6: pointer to descriptor within EEPROM (counted in bytes)
- bit 7: always set to 1
- bits 8-15: total length of descriptor in bytes
The string descriptors are stored in ROM with the descriptor header included, as follows:
- word 0: header
- bits 0-7: total length of descriptor in bytes (includes header)
- bits 8-15: descriptor type (always 3 — string)
- words 1 and up: string in UTF-16
The checksum can be computed as follows:
#![allow(unused)] fn main() { fn checksum(eeprom: &[u16; 0x50]) -> u16 { let mut res: u16 = 0xaaaa; for pos in 0..0x3f { // checksum word is NOT included — we're calculating it res ^= eeprom[pos]; res = res.rotate_left(1); } res } }
For unknown reasons, the libftchipid library returns the chipid in scrambled form, computed as follows:
#![allow(unused)] fn main() { fn scramble_byte(b: u8) -> u8 { (b & 1) << 1 | (b & 2) << 5 | (b & 4) >> 2 | (b & 8) << 4 | (b & 0x10) >> 1 | (b & 0x20) >> 1 | (b & 0x40) >> 4 | (b & 0x80) >> 2 } fn scramble_chipid(eeprom_chipid: u32) -> u32 { let scrambled_b0 = scramble_byte((unscrambled_chipid & 0xff) as u8); let scrambled_b1 = scramble_byte((unscrambled_chipid >> 8 & 0xff) as u8); let scrambled_b2 = scramble_byte((unscrambled_chipid >> 16 & 0xff) as u8); let scrambled_b3 = scramble_byte((unscrambled_chipid >> 24 & 0xff) as u8); // note the byte reversal let word = (scrambled_b0 as u32) << 24 | (scrambled_b1 as u32) << 16 | (scrambled_b2 as u32) << 8 | (scrambled_b3 as u32); word ^ 0xa5f0f7d1 } }