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:
  • 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

QFN32TSSOP28categoryFT232RFT245R
14powerVCCIOVCCIO
25IO-DBUSRXDD1
36IO-DBUSRI#D7
47powerGNDGND
58NC?--
69IO-DBUSDSR#D5
710IO-DBUSDCD#D6
811IO-DBUSCTS#D3
912IO-CBUSCBUS4PWREN#
1013IO-CBUSCBUS2RD#
1114IO-CBUSCBUS3WR
12-NC--
13-NC--
1415USBUSBDPUSBDP
1516USBUSBDNUSBDN
1617power3V3OUT3V3OUT
1718powerGNDGND
1819controlRESET#RESET#
1920powerVCCVCC
2021powerGNDGND
2122IO-CBUSCBUS1TXE#
2223IO-CBUSCBUS0RXF#
2324NC?--
2425powerAGNDAGND
25-NC--
2626controlTESTTEST
2727clockOSCIOSCI
2828clockOSCOOSCO
29-NC--
301IO-DBUSTXDD0
312IO-DBUSDTR#D4
323IO-DBUSRTS#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 valuevalid on pinsfunction
0x0allUART TXDEN
0x1allPWREN#
0x2allUART RXLED#
0x3allUART TXLED#
0x4allUART TXRXLED#
0x5allSLEEP#
0x6allCLK48
0x7allCLK24
0x8allCLK12
0x9allCLK6
0xaCBUS0-CBUS3I/O (for CBUS bitbang mode)
0xbCBUS0-CBUS3bitbang WR#
0xcCBUS0-CBUS3bitbang RD#
0xdCBUS0FIFO RXF#
0xdCBUS1FIFO TXE#
0xdCBUS2FIFO RD#
0xdCBUS3FIFO 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:

pinFT232RFT245R
CBUS0TXLED#RXF#
CBUS1RXLED#TXE#
CBUS2TXDENRD#
CBUS3PWREN#WR
CBUS4SLEEP#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
  • 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)
  • 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

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
}
}