FT4232H 开发笔记

FTDI 硬件是由 FTDI chip 公司开发的用于高性能 USB 转各种底层通信协议 的芯片。所支持的协议包括 UART / SPI / I2C / JTAG etc. ,还有特殊的 bit-bang 协议。

FT4232 基本上是 FT2232 的升级版,从 2个8bit 独立通道,升级成 4个8bit 独立通道,每个通道都具有独立互不干扰的时钟。

FT4232HL 芯片可以实现 USB 2.0 转换成 四个虚拟通道VCP,即 Virtual COM Port) 的功能,该四个虚拟通道可以模拟 UART / JTAG / SPI / I2C 功能,IO口电压为 3.3V

本文基于 FT423H 的迷你模块进行开发,该芯片的官方说明如 《FT4232HL》 。

ENVIRONMENT

libusb 1.0 - Library for talking to USB devices from user-space. Needed by libftdi. libconfuse - Library for parsing configuration files. Needed by ftdi_eeprom.

ELECTRICAL SPECIFICATION

image-20220623145709022

FT4232HL开发板 正面 视图引脚分布:

img

FT4232HL开发板 反面 视图引脚分布:

SPI PINOUT

如果使用 libMPSSE 进行 SPI 通信开发,则默认使用下方的通信接口。

image-20220707162556201

FT4232HL PIN DESCRIPTION

image-20220707162928727

Bit-Bang 模式下的 FT4232H 的引脚

FT4232H的通道 A、B、C 或通道 D 可以被配置为 bit-bang 接口。有两种类型的 bit-bang 模式:同步和异步。

当配置为任何 bit-bang 模式(同步或异步)时,使用的引脚和信号的描述见表3.6

image-20220707163519992
image-20220707163532847

DRIVER INSTALL

FT4232H 的驱动分为 VCP / D2XXX 和 D3XXX 三个。其中,D3XXX 是适用于 USB 3.0 的,这里不需要安装。

window 版本的驱动安装器就包含了 VCP 和 D2XXX。

驱动安装页面:Virtual COM Port Drivers

官方驱动安装教程:Windows 10/11 Installation Guide

装了CDM驱动的Windows平台
linux平台的usb列表

注意:驱动安装完毕之后,PC 不会立即识别 该设备。需要使用 跳线帽,将 CN3 的 13 口进行短接。让设备供上5V的电。

image-20220623145344049

D2XXX 编程指南

D2XXX 是针对 FTDI 的专用接口(Proprietary Interface )。

FTDI provides two alternative software interfaces for its range of USB-UART and USB-FIFO ICs. One interface provides a Virtual COM Port (VCP) which appears to the system as a legacy COM port. The second interface, D2XX, is provided via a proprietary DLL (FTD2XX.DLL). The D2XX interface provides special functions that are not available in standard operating system COM port APIs, such as setting the device into a different mode or writing data into the device EEPROM.

FTDI 为USB-UART 和 USB-FIFO IC 提供两种可供选择的软件接口:虚拟串口VCP,Virtual COM Port) 和 D2XXX

在 Windows 上,D2XXX 和 VCP 驱动 则在同一个驱动包中进行分发,称为 综合驱动模块(CDM, Combined Driver Model)。下图解释了 Windows 端的 CDM 模块架构。

image-20220627122210831

而在 类Unix平台 和 Windows CE 上,VCP 和 D2XXX 是相互排斥的选项,因为在一个特定的时间内,一个特定的设备ID只能安装一种驱动类型。

Windows 上虽然可以装 VCP 和 D2XXX 两种驱动,但是任意时间也只有一种驱动能用。

VCP 是专用于 虚拟串口 的驱动,因此FTDI 官方并不提供 应用级 示例代码。而 D2XXX 是 FTDI 的专用接口,官方提供了 FTD2XXX 库的应用程序以供开发。

image-20220627140842391

其中,libMPSSE 是 SPI/I2C/JTAG 的通信的库文件,依赖于底层的 libftd2xx

FT_SetBitMode()

image-20220707154811965

ucMarsk 设置说明

位模式的必要值。这设置了哪些位是输入和输出。位值为0时,将相应的引脚设为输入,位值为1时,将相应的引脚设为输出。

在CBUS Bit Bang的情况下,这个值的上位数控制哪些引脚是输入和输出,而下位数控制哪些输出是高电平和低电平。

注意: 它与 FT_SetBitMode() 不是互相的关系

根据 SPI PINOUT 的图标说明,应该将以下引脚的掩码设置为如下:

主控引脚 所接从设备引脚 输入输出状态 掩码
A0 SCLK output 1
A1 MOSI output 1
A2 MISO input 0
A3 SNCS output 1
A4 x
A5 x
A6 x
A7 x

此时,掩码必须设置为 0xFB0x0B

ucMode 设置说明

0x0 = Reset 0x1 = Asynchronous Bit Bang 0x2 = MPSSE (FT2232, FT2232H, FT4232H and FT232H devices only) 0x4 = Synchronous Bit Bang (FT232R, FT245R, FT2232, FT2232H, FT4232H and FT232H devices only) 0x8 = MCU Host Bus Emulation Mode (FT2232, FT2232H, FT4232H and FT232H devices only) 0x10 = Fast Opto-Isolated Serial Mode (FT2232, FT2232H, FT4232H and FT232H devices only) 0x20 = CBUS Bit Bang Mode (FT232R and FT232H devices only) 0x40 = Single Channel Synchronous 245 FIFO Mode (FT2232H and FT232H devices only)

FT_GetBitMode()

FT_GetBitMode 返回各引脚的瞬时值。将返回一个单字节,其中包含各引脚的当前值,包括那些输入和输出的引脚。

或对FT232R的可用位模式的描述,请参见应用说明 "FT232R和FT245R的bit-bang模式"。 关于FT2232的可用位模式的描述,请参见应用说明 "FT2232的位模式功能"。 关于FT232B和FT245B的比特爆炸模式的描述,见应用说明 "FT232B/FT245B比特爆炸模式"。 关于T4232H和FT2232H器件支持的位模式的描述,请参见IC数据表。 这些应用说明可从FTDI网站下载。

FT_SetBaudRate()

数据传输的速率可以通过使用 FT_SetBaudRate() 命令来控制。异步模式的时钟实际上是所设波特率的16倍。一个9600波特的值将以每秒(9600x16)=153600 byte的速度传输数据,或每6.5μS一个 byte。

FTDI 器件最大可设置的波特率是 3M baud,但为了让数据有时间在 WR# 选通周围设置和保持,数据的波特率最大应该是 1M baud(62500x16)。最小的数据波特率是 4.8kbaud(300 x 16)。

FT_Read()

image-20220707151059741

FT_Read always returns the number of bytes read in lpdwBytesReturned. This function does not return until dwBytesToRead bytes have been read into the buffer. The number of bytes in the receive queue can be determined by calling FT_GetStatus or FT_GetQueueStatus, and passed to FT_Read as dwBytesToRead so that the function reads the device and returns immediately.

When a read timeout value has been specified in a previous call to FT_SetTimeouts, FT_Read returns when the timer expires or dwBytesToRead have been read, whichever occurs first. If the timeout occurred, FT_Read reads available data into the buffer and returns FT_OK. An application should use the function return value and lpdwBytesReturned when processing the buffer. If the return value is FT_OK, and lpdwBytesReturned is equal to dwBytesToRead then FT_Read has completed normally. If the return value is FT_OK, and lpdwBytesReturned is less then dwBytesToRead then a timeout has occurred and the read has been partially completed. Note that if a timeout occurred and no data was read, the return value is still FT_OK.

FT_Read() 总是返回在 lpdwBytesReturned 中读取的字节数。 在 dwBytesToRead 字节被读入缓冲区之前,该函数不会返回。接收队列中的字节数可以通过调用FT_GetStatus()FT_GetQueueStatus() 来确定,并作为 dwBytesToRead 传给 FT_Read(),以便该函数读取设备并立即返回。

当在先前对 FT_SetTimeouts() 的调用中指定了一个读取超时值时,FT_Read() 在定时器过期或 dwBytesToRead 已被读取时返回,以先发生者为准。如果超时发生,FT_Read() 将可用数据读入缓冲区并返回 FT_OK

在处理缓冲区时,应用程序应使用该函数的返回值和 lpdwBytesReturned 。如果返回值为 FT_OK,并且 lpdwBytesReturned 等于 dwBytesToRead ,那么 FT_Read() 已经正常完成。如果返回值是 FT_OK,并且 lpdwBytesReturned 小于 dwBytesToRead,那么就发生了一个超时,读取已经部分完成。

请注意,如果发生了超时并且没有读取任何数据,返回值仍然是 FT_OKFT_IO_ERROR 的返回值表明函数的参数有错误,或者发生了致命的错误,如USB断开连接。

BIT BANG MODE

异步Bit-Bang模式

异步 Bit-Bang 模式与 BM-style Bit-Bang 模式相同。在任何配置为异步模式的通道上,以正常方式写入设备的数据将被自锁到并行I/O数据引脚(那些被配置为输出的引脚)。每个I/O引脚都可以独立设置为输入或输出。数据的时钟输出速率由波特率发生器控制。

为了使数据发生变化,必须有新的数据写入,而且 波特率时钟 必须跳动。如果没有新的数据被写入通道,引脚将保持最后写入的值。

  1. 那这个波特率时钟 怎么控制?能否指定任一引脚进行输出?

同步Bit-Bang模式

The synchronous Bit-Bang mode will only update the output parallel I/O port pins whenever data is sent from the USB interface to the parallel interface. When this is done, data is read from the USB Rx FIFO buffer and written out on the pins. Data can only be received from the parallel pins (to the USB Tx FIFO interface) when the parallel interface has been written to.

With Synchronous Bit-Bang mode, data will only be sent out by the FT4232H if there is space in the FT4232H USB TXFIFO for data to be read from the parallel interface pins. This Synchronous Bit-Bang mode will read the data bus parallel I/O pins first, before it transmits data from the USB RxFIFO. It is therefore 1 byte behind the output, and so to read the inputs for the byte that you have just sent, another byte must be sent.

同步模式只有在数据从USB接口发送到并行接口时才会更新输出的 并行I/O端口 引脚。当这样做的时候,数据从USB Rx FIFO缓冲器中读出,并在引脚上写出。只有当并行接口被写入时,才能从并行引脚接收数据(到USB Tx FIFO接口)。

同步Bit-Bang模式与异步Bit-Bang模式的不同之处在于,只有当USB接口写入并行输出时,设备的并行输出才被读取。这使得控制程序更容易测量对USB输出刺激的反应,因为返回到USB接口的数据与输出数据是同步的。

在同步模式下,读和写操作会被同步进行。此时,数据总线引脚会在写入数据前先读取数据(针对每个byte)。因此,该数据引脚读取到的数值总是比写出去的数值要慢一个byte。

与异步模式不同,数据引脚只会在写入数据前立即进行读取操作。因此,为了读取 “写入一个byte的响应结果” ,必须要发送另一个byte。 另外,只有当设备中有空间可以从引脚读取数据时,数据才会被写入引脚。

每个引脚都可以独立设置为输入或输出。数据的时钟输出率由波特率发生器控制。要改变引脚的状态,必须写入新的数据,并且波特率时钟必须跳动(the baud rate clock hask to tick)。如果没有新的数据被写入设备,输出引脚将保持最后写入的数值。

当同步模式被启用时,I/O信号线的配置如表3.1所示。请注意,在首次进入同步模式后,任何引脚的默认配置,如果设置为输出,则默认被设置为 输出低电平(0V)。(随后向任何引脚写一个 1 将把该引脚设置为VCCIO) 当进入同步模式后,如果希望在任何输出上驱动一个高值,那么有必要首先用 FT_SetBitMode() 方法把这些引脚设置为输入,用 FT_Write() 把它们写一个 1 ,然后用 FT_SetBitMode() 把它们设置为输出。请注意,当设备处于同步位串模式时,EEPROM UART信号反转选项(signal inversion option)对这些引脚没有影响。

image-20220707152918917

FT200XD 和 FT201X提供两条信号线;FT220X、FT230X 和 FT234XD提供四条信号线;而 FT221X、FT231X 和 FT240X上总共有八条信号线。

任何一个FT-X系列器件的CBUS引脚都可以被配置为在器件处于同步位串模式时发出 内部读取 RD#内部写入 WR# 频段(strobes)(注意,FT200XD、FT220X、FT221X和FT234XD只有一个CBUS 引脚,因此只能选择 RD#WR# )。通过在内部EEPROM中设置适当的值,CBUS 引脚也可用于提供时钟信号。

所有的bit-bang模式都需要使用D2XX驱动,不可能通过VCP驱动使用这些功能,也不可能同时使用 CBUS bit-bangVCP。表3.2列出了用于同步 bit-bang 模式的基本命令。这些功能的完整描述可在《D2XX程序员指南》中找到。

image-20220707152805911

FTDI BIT-BANG

FT432 如果需要配置成 Bit-Bang模式,需要:

  1. 使用 FT_Open() 打开对应通道
  2. 使用 FT_SetBitMode() 为8个pin配置输入或输出,FTDI 称之为掩码(mask),0则代表输入,1则代表输出,例如 0x0F 则代表 0~3 pin 设置为输出,4~7 pin设置为输入。
  3. 同时,在 FT_SetBitMode() 第三个参数 ucEnable 传递参数即可打开对应模式,如:
    1. FT_BITMODE_SYNC_BITBANG 即 同步 Bit-Bang 模式
    2. FT_BITMODE_SYNC_BITBANG 即 异步 Bit-Bang 模式
    3. FT_BITMODE_RESET 即 默认的 UART 模式。
  4. FT4232 的每个通道都是具有独立时钟的,为 FT_SetBaudRate() 传递参数即可设置SPI通信频率。实际上此处设置的并不是 SPI外设的工作频率,而是该 channel 通过 FT_Write() 接口改变引脚高低电平的频率。
    1. 同步 Bit-Bang 模式下,每 100000 波特率约为 250KHz 时钟,如果使其工作在 1MHz 频率下,则需要设置波特率为 400000
    2. 异步 Bit-Bang 模式下的时钟为波特率的 16
  5. 使用读取和写入的接口 FT_Write()FT_Read() 会按照该通道设定的时钟频率去改变/读取引脚数据。

操作一次 FT_Write() ,如下,即可在 一个频率的半个周期内 改变 8个pin 的高低电平。

1
2
3
4
5
6
bytes_written_number = 0;
ftStatus = FT_Write(ft_handle,
&(byte_write_to_slave->all),
bits_to_send,
&bytes_written_number);
CHECK_STATUS(ftStatus);
  • ft_handle 是通道的句柄(注意:一个通道一个句柄,不是一个句柄适用所有通道)

  • byte_write_to_slave.all 是一个 8bit 的 UCHAR 类型数据。

  • bits_to_send 为 待发送数据量

  • bytes_written_number 是 已写入数据量

例1

如果将 掩码 配置为 0xFF ,即8个通道均为输出。且输出每个通道单次输出的数值,均为 0xFF,输出 16次,即调用 FT_Write() 16次,那么得到的图像应该如下:

index

例2

如果将 掩码 配置为 0xFF 。交替输出 0xFF0x00,输出 16 次,那么得到的图像应该如下:

Q: 为什么上面只有8个时钟,即1个byte大小,为什么是输出16次?

A: 因为FTDI的 FT_Write() 接口写入一次数据,只能控制半个周期内的8个pin脚数据,如果需要发送一个周期的数据,则需要写两次,如果需要发送8个bit,则需要输出16次。

2

例3

如果将 掩码 配置为 0x0B,即 0000 1011 ,(按照 MPSSE-SPI Example 设置的相同配置),pin0SCKpin1MOSIpin2MISOpin3CS

默认情况下,输入引脚的电平会被拉低。如果设置为输入引脚,FT_Write() 无法改变其电平。

FT_Write() 一共需要写入 32次数据:

1
2
3
4
5
UCHAR byte_write_to_slave[32] = {
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x02,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00};

3

可以看到在 byte_write_to_slave[14]byte_write_to_slave[15] 时需要主动拉高 pin1 的电平,并维持 2个 falf period(即 one period)。

再用 FT_Read() 读取 32 次数据,将数据存储到 UCHAR byte_read_from_slave[32] 中,并从 byte_read_from_slave[16] ~ byte_read_from_slave[31] 的 16 个数据中,每间隔1个数据,将对应 pin2 的数据左移存储到 data_read 中。

代码可以是这样的:

1
2
3
4
5
UCHAR data_read = 0;
for (int i = 0; i < 8; i++)
{
data_read |= ( byte_read_from_slave[ 16 + i * 2 ] & 0x03) << ( 7 - i );
}

Q: 为什么 FT_Read() 需要读取32次数据?

A: 因为这是 同步 Bit-Bang 模式的特性,根据手册说明,每次读取一定数据量之前,都要写入一定的数据量。异步 Big-Bang 模式是不用这样的。

SPI + BIT-BANG

如果按照例3 的方法去发送数据,可能会发现收到的数据一直是异常的。

因为 输出引脚 会保持其最后的输出电平,如 byte_read_from_slave[31] 数据为 0x00,这就让 pin0 ,即 SCK 发送完数据之后保持了低电平,与 CPOL=1 的要求相违背。

因此不能只发送和接收32个数据,而应该在对应的发送数据的前后加上一个周期,即声明一个长度为36的数组 UCHAR byte_read_from_slave[36] 。

byte_read_from_slave[0] / byte_read_from_slave[1] / byte_read_from_slave[34] / byte_read_from_slave[35] 均应设置为 0x09 ,如下波形所示。

image-20220714173158679

FTDI HAL

FTDI HAL 是基于 D2XX 库、由个人编写的、可替换libMPSSE的SPI库,目前仅有SPI相关的代码。

2022年7月11日 16:10

各通道的可以配置不同的handle和config 参数去打开和关闭。也可以读GPIO,没问题了。

image-20220711161012120

ftd2xx_hal_read_pin_level

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* @brief GPIO 电平读取接口
* @param {FT_HANDLE*} ft_handle:待读取通道句柄
* @param {UCHAR} pin_to_read:待读取引脚
* @param {UCHAR*} pin_level:电平值
* @return FT_OK if successful, otherwise the return value is an FT error code.
*/
FT_STATUS ftd2xx_hal_read_pin_level(FT_HANDLE* ft_handle,
UCHAR pin_to_read,
UCHAR* pin_level)
{
FT_STATUS ftStatus = FT_OK;
FTD2XX_HAL_DATA byte_read_from_slave;
FTD2XX_HAL_DATA byte_write_to_slave;
DWORD byte_read_number = 0;
byte_write_to_slave.all = 0;

if (pin_to_read > 7 || pin_level == NULL)
{
return FT_INVALID_ARGS;
}

ftStatus =
FT_Write(*ft_handle, &(byte_write_to_slave.all), 1, &byte_read_number);
CHECK_STATUS(ftStatus);

// 从同道中读取8个pin的电平
byte_read_number = 0;
ftStatus =
FT_Read(*ft_handle, &(byte_read_from_slave.all), 1, &byte_read_number);
CHECK_STATUS(ftStatus);

*pin_level = (byte_read_from_slave.all >> pin_to_read) & 0x01;

return ftStatus;
}

电平读取能力分析

  • 利用esp32 的 GPIO 发送pwm波(宽度为 350ns ,周期约为 750ns ),发送 10000次后停止,该接口能够读取到 76~80 次。

image-20220712121857849
  • 拉长 pwm波周期至 33us,同样发送 10000次后停止,该接口能够读取到 6660 次左右。

image-20220712122514462

GPIO电平读取频率大致在 5KHz ~ 50KHz 之间,即接口两次调用的时间间隔在 20us ~ 200us 之间。

DEBUG RECORD

NULL expression encountered

image-20220711123340879

这是因为运行需要 sudo 权限,即 sudo ./tmp/galileo_sdk/application/sample_app_raw_data_irq 。如果还是不行,应该是没有卸载 ftdi_siousbserial ,即 sudo rmmod ftdi_sio usbserial

注意:卸载 usbserial 后,如果这时候linux系统内有其他设备对 libusb-1.0-0-dev 有依赖,那它会无法正常工作。

REFERENCE

  1. FTDI GPIO example
  2. aehparta/ftdi-bitbang
  3. FTDI Knowledgebase
  4. swharden/AVR-projects
  5. Bit-Bang FTDI USB-to-Serial Converters to Drive SPI Devices
  6. libFTDI - FTDI USB driver with bitbang mode
  7. Documents/Application Notes