FT4222H的SPI从模式只支持SPI,不支持DSPI,QSPI接口,并且只支持Mode0、Mode3两种模式,另外,从模式也不支持Android系统(指的是J2XX驱动)。
注意因为USB的数据传输特性,也许SPI Master通过SPI读数据时USB接口并没有将数据准备好,所以如果要保证可靠的通信,建议使用协议的方式交互数据。
目前的library在每次写操作(Slave->Master)时会在有效数据前自动添加一个字节0x00,在Master端需要移除掉这个字节。如果不需要这个机制,可以直接调用D2XX的FT_Write写数据。
【初始化为SPI(从)接口】
当FT4222H打开后可以得到一个handle值,将该值赋值给变量spiSHandle。
对应的API函数是FT4222_SPISlave_Init或FT4222_SPISlave_InitEx。
[DllImport("LibFT4222.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern eFT4222Status FT4222_SPISlave_Init(IntPtr ftHandle);
[DllImport("LibFT4222.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern eFT4222Status FT4222_SPISlave_InitEx(IntPtr ftHandle, eSPISlaveProtocol protocolOpt);
区别在于FT4222_SPISlave_InitEx可以指定是否采用协议的方式通信,而FT4222_SPISlave_Init则是默认采用SPI_SLAVE_WITH_PROTOCOL。
当使用协议方式时, Master端需要处理对应的数据结构,使之符合协议的格式,其协议的格式如下:
Sync word固定为0x5A;Command的定义如下:
SN表示包的序列号,用于packets的识别;2个字节的size表示,大端模式,高位在前;Checksum是所有数据(从Sync Word开始到Data的最后一个字节)相加后取低2字节,大端模式。
比如Master要发送1个字节0x55的数据给FT4222H,数据流如下:
FT4222H是自动处理协议的,对于用户来说就是得到实际数据0x55(FT4222_SPISlave_Read读到的数据,并不会读到其他协议的数据),后面的ACK也是自动回复给Master的(会自动插入一个0x00)。
如果Master需要读一个字节回来时,因为SPI是全双工通信,实际Master可以在发送数据的同时接收数据,数据流如下(第一个字节是FT4222H库函数自动增加的一个字节0x00):
如果是FT4222H主动发送数据时,FT4222H同样是发送和Master发送一样格式的数据,不过对于调用API FT4222_SPISlave_Write函数来说,只需要发送原始数据即可,API FT4222_SPISlave_Write函数会自动将数据转成协议的格式。
【设置模式】
SPI模式只支持Mode0和Mode3,默认Mode0。
[DllImport("LibFT4222.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern eFT4222Status FT4222_SPISlave_SetMode(
IntPtr ftHandle, eSPICPOL cpol, eSPICPHA cpha);
【获取接收队列中数据的长度】
[DllImport("LibFT4222.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern eFT4222Status FT4222_SPISlave_GetRxStatus(
IntPtr ftHandle, ref UInt16 pRxSize);
参数pRxSize是接收队列(即Master发送过来的数据)中的数据长度。
【读函数】
[DllImport("LibFT4222.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern eFT4222Status FT4222_SPISlave_Read(
IntPtr ftHandle, byte[] buffer, UInt16 bufferSize, ref UInt16 sizeOfRead);
参数buffer是读入的数据;参数bufferSize是需要读入的数据个数;参数sizeOfRead是实际读入的数据个数。
【写函数】
[DllImport("LibFT4222.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern eFT4222Status FT4222_SPISlave_Write(
IntPtr ftHandle, byte[] buffer, UInt16 bufferSize, ref UInt16 sizeTransferred);
参数buffer是写入的数据,注意实际写出去的数据第一个字节会插入一个0x00;参数bufferSize是写入的数据个数;参数sizeTransferred是实际写的数据个数。
用STM32F030平台作为Master验证FT4222H的SPI Slave功能,在STM32F030端接收发送数据,并把读到的数据打印到串口。
uint8_t head[] = {0x5A, 0x80, 0x00, 0x00, 0x00};
head[3] = (uint8_t)((length >> 8) & 0xff);
head[4] = (uint8_t)(length & 0xff);
SpiMasterCSEn();
dat = spiTransferByte(0xff); //Skip 0x00
for(i = 0; i < 5; i++)
{
dat = spiTransferByte(head[i]);
checkSum += head[i];
Printf("%x ", dat);
}
Printf("\nValid Data:");
for(i = 0; i < length; i++)
{
dat = spiTransferByte(0x55 & 0xff);
checkSum += 0x55;
if((i % 16) == 0)
Printf("\n");
Printf("%x ", dat);
}
Printf("\nCheckSum:\n");
{
uint16_t sum = 0;
dat = spiTransferByte((uint8_t)((checkSum >> 8) & 0xff));
Printf("%x ", dat);
sum = dat;
dat = spiTransferByte((uint8_t)(checkSum & 0xff));
Printf("%x ", dat);
sum = (sum << 8) | dat;
}
Printf("\nACK data:");
for(i = 0; i < 8; i++)//FT4222H auto add 0x00 at first byte.
{
dat = spiTransferByte(0xff);
if((i % 16) == 0)
Printf("\n");
Printf("%x ", dat);
}
而FT4222H端如果要发送数据到STM32F030则需要先写入到buffer,等Master启动SPI通信时才真正的传输数据。
wrBuf[0] = 0xAA;
sendHexLen = 1;
status = FT4222H.FT4222_SPISlave_Write(spiSHandle, wrBuf, (UInt16)sendHexLen, ref lpBytesWritten);
然后在一个BackgroundWorker里面不停的检测接收队列,有数据就读回数据。
while(true)
{
UInt16 rxSize = 0;
status = FT4222H.FT4222_SPISlave_GetRxStatus(spiSHandle, ref rxSize);
if (status == FT4222H.eFT4222Status.FT4222_OK)
{
if (rxSize > 0)
{
Console.WriteLine("SPIS rd len:" + rxSize);
byte[] rdBuf = new byte[rxSize];
UInt16 sizeTransferred = 0;
status = FT4222H.FT4222_SPISlave_Read(spiSHandle, rdBuf, (UInt16)rxSize, ref sizeTransferred);
if (status != FT4222H.eFT4222Status.FT4222_OK)
Console.Write("SPI Slave read fail:" + status);
for (int i = 0; i < rxSize; i++)
{
spiSRevQueue.Enqueue(rdBuf[i]);
}
bgWorkerSpiS.ReportProgress(0);
}
}
}
串口的打印数据:
SPI SLAVE With Protocol Read Data 1
5a 81 2 0 1
Valid Data:
aa
CheckSum:
1 88
ACK data:
0 5a 84 0 0 0 0 de