pq113_6的个人空间 https://bbs.21ic.com/?51690 [收藏] [复制] [RSS]

日志

USB桥接 - 6 USB2IIC

已有 208 次阅读2018-4-23 16:21 |个人分类:USB桥接|系统分类:接口电路

【硬件】

AD0作为IICSCLAD1AD2短接在一起作为SDA

外部不需要使用EEPROM


【配置为MPSSE

配置为MPSSE的模式与USBGPIO相同。

 

【基本原理】

类似SPI的方式,IICStartStop采用GPIO的方式,而数据的输入输出则采用类似SPI的方式。IIC基本只需要3API函数,分别为initreadwrite,其中readwrite采用一次写入IIC的命令。

 

gpio成员函数setClk

gpio新增成员函数setClk,设置gpio的最大频率,即设置命令的重复次数。

public static UInt16 setClk(eClk set)

{

switch(set)

{

case eClk.CLK_800K:

clk = 1;

break;

case eClk.CLK_400K:

clk = 2;

break;

case eClk.CLK_200K:

clk = 4;

break;

case eClk.CLK_100K:

clk = 8;

break;

case eClk.CLK_50K:

clk = 16;

break;

case eClk.CLK_25K:

clk = 32;

break;

case eClk.CLK_12K:

clk = 64;

break;

case eClk.CLK_6K:

clk = 128;

break;

default:

clk = 1;

break;

}

return clk;

}

 

【获取GPIO的方向和状态】

IIC只用到了3IO口,如果采用流数据改变GPIO的状态的话需要整个8bit GPIO的方向和状态,这样才不会影响到另外5IO口作为GPIO的使用,所以要先读回整个ADBUS的方向和状态。

public static void getlbyte(ref byte dir, ref byte state)

{

dir = lbyteDir;

state = lbyteState;

}

 

【设置GPIO的方向和状态】

主要用于将IO口的状态写回,保证外部改变的IO状态能更新到gpio类中。

public static void setlbyte(byte dir, byte state)

{

lbyteDir = dir;

lbyteState = state;

}

 

IIC的初始化】

初始化设置GPIO的频率和设置SCLSDA的方向,并且设置SCLSDA为高电平。

private static UInt32 ftHandle = 0;

private const byte SCL = 0;

private const byte SDAO = 1;

private const byte SDAI = 2;

 

private static UInt16 iicCLK = 0;

private static ArrayList ftCommand = new ArrayList();

 

public static void init(UInt32 handle, gpio.eClk clk)

{

ftHandle = handle;

iicCLK = gpio.setClk(clk);

gpio.setClk(clk);

gpio.setDir(SCL, 0); //SCL is output

gpio.setDir(SDAO, 0); //SDA(AD1) is output

gpio.setDir(SDAI, 1); //SDA(AD2) is input

gpio.output(SCL, gpio.eState.High);

gpio.output(SDAO, gpio.eState.High);

}

 

Start

SCL为高电平,SDA由高电平变为低电平。

private static void start()

{

byte dir = 0, state = 0;

gpio.getlbyte(ref dir, ref state);

state |= (byte)0x03;                    //SCL outputs high, SDA outputs high

for (int i = 0; i < iicCLK; i++)

{

ftCommand.Add((byte)0x80);

ftCommand.Add(state);   

ftCommand.Add(dir);

}

state &= (byte)0xfd;                    //SDA outputs low

for (int i = 0; i < iicCLK; i++)

{

ftCommand.Add((byte)0x80);

ftCommand.Add(state);   

ftCommand.Add(dir);

}

gpio.setlbyte(dir, state);

}

 

Stop

SCL为高电平,SDA由低电平变为高电平。

private static void stop()

{

byte dir = 0, state = 0;

gpio.getlbyte(ref dir, ref state);

state &= (byte)0xfd;                    //SDA outpus low 

for (int i = 0; i < iicCLK; i++)

{

ftCommand.Add((byte)0x80);

ftCommand.Add(state); 

ftCommand.Add(dir);

}

state |= (byte)0x01;                    //SCL outputs high

for (int i = 0; i < iicCLK; i++)

{

ftCommand.Add((byte)0x80);

ftCommand.Add(state); 

ftCommand.Add(dir);

}

state |= (byte)0x02;                    //SDA outputs high

for (int i = 0; i < iicCLK; i++)

{

ftCommand.Add((byte)0x80);

ftCommand.Add(state);

ftCommand.Add(dir);

}

gpio.setlbyte(dir, state);

}

 

Ack

SCL低电平时,SDA输出低电平,SCL变为高电平输出ACK信息。

 

NAck

SCL低电平时,SDA输出高电平,SCL变为高电平输出NACK信息。

 

receiveByte

主端在SCL为低电平的时候可以改变SDA的状态,因为在SCL为高电平时改变SDA会引发StartStop

private static void receiveByte(bool ack)

{

byte dir = 0, state = 0;

gpio.getlbyte(ref dir, ref state);

 

state &= (byte)0xfc;                    //SCL outputs low, SDA outputs low

dir &= (byte)0xfd;                      //Set SDA as input

ftCommand.Add((byte)0x80);

ftCommand.Add(state);

ftCommand.Add(dir);


ftCommand.Add((byte)0x22);

ftCommand.Add((byte)7);

 

state &= (byte)0xfc;                    //SCL outputs low, SDA outputs low

dir |= (byte)0x02;                      //Set SDA as output

ftCommand.Add((byte)0x80);

ftCommand.Add(state);

ftCommand.Add(dir);

 

ftCommand.Add((byte)0x12); //Clock Data Bits Out on clock raise edge MSB first

ftCommand.Add((byte)0x0); // 1bit

if (ack == true)

ftCommand.Add((byte)0x00); // SDA outputs low means ack

else

ftCommand.Add((byte)0x80); // SDA outputs high means nack, only use bit7.

 

ftCommand.Add((byte)0x87);

 

state &= (byte)0xfe;                    //SCL outputs low

ftCommand.Add((byte)0x80);

ftCommand.Add(state);

ftCommand.Add(dir);

 

gpio.setlbyte(dir, state);

}

首先SCL输出低电平,SDA输出低电平,并且把AD1脚设置为输入脚(不然AD2脚不会被从机输出对应电平),然后读入8bit的数据(命令0x22是上升沿读入比特数据?存疑,是否是高电平读入数据,如果改成0x26也可以正常读取数据),数据读完(读入的数据会在buffer中,后面再全部从buffer中读入)再将AD1设置为输出脚,并根据参数ack输出ack还是nack。最后SCL输出低电平结束。

 

sendByte

private static void sendByte(byte dat)

{

byte dir = 0, state = 0;

gpio.getlbyte(ref dir, ref state);

 

state &= (byte)0xfe;                    //SCL outputs low

state |= (byte)0x02;                    //SDA outputs high

dir |= (byte)0x02;                      //Set SDA as output

ftCommand.Add((byte)0x80);

ftCommand.Add(state);

ftCommand.Add(dir);

 

ftCommand.Add((byte)0x12); //Clock Data Bits Out on clock raise edge MSB first

ftCommand.Add((byte)7);

ftCommand.Add(dat);

 

state &= (byte)0xfc;

dir &= (byte)0xfd;                      //Set SDA as input

for (int i = 0; i < iicCLK; i++)

{

ftCommand.Add((byte)0x80);

ftCommand.Add(state);

ftCommand.Add(dir);

}

 

ftCommand.Add((byte)0x26); //Clock Data Bits In on clock falling edge MSB first

ftCommand.Add((byte)0);                 // 1bit

ftCommand.Add((byte)0x87);

 

state &= (byte)0xfe;                    //SCL outputs low

for (int i = 0; i < iicCLK; i++)

{

ftCommand.Add((byte)0x80);

ftCommand.Add(state);

ftCommand.Add(dir);

}

 

state |= (byte)0x02;                    //SDA outputs high

dir |= (byte)0x02;                      //Set SDA as output

ftCommand.Add((byte)0x80);

ftCommand.Add(state);

ftCommand.Add(dir);

 

gpio.setlbyte(dir, state);

}

首先SCL输出低电平,SDA输出低电平,并且把AD1脚设置为输出脚,然后输出8bit的数据(同样0x12改为0x13也可以正常工作),完成后设置AD1为输入脚,准备读入ACK信号,读入ACK信号只能用0x26(如果使用0x22会导致如果后面接一个Start话会插入一个Stop,即如果用0x22 sendByte + start会变成sendByte + stop + start)。最后设置SCL为低电平,然后设置SDA为输出,并输出高电平。

 

read

public static bool read(byte slaveAddr, byte addrbit, UInt16 addr, byte[] dat, UInt32 len)

{

if (len == 0)

return false;

UInt32 rdLen = (UInt32)(addrbit / 8 + 2 + len);

UInt32 rdDatLen = len;

 

D2XX.eDeviceStatus ftStatus = D2XX.eDeviceStatus.FT_DEVICE_NOT_FOUND;

UInt32 byteWritten = 0, byteRead = 0, dly = 0;

ftStatus = D2XX.FT_GetQueueStatus(ftHandle, ref byteRead);

if (byteRead > 0)

{

byte[] tmpbuf = new byte[byteRead];

ftStatus = D2XX.FT_Read(ftHandle, tmpbuf, (UInt32)byteRead, ref byteRead);

}

 

ftCommand.Clear();

start();

sendByte(slaveAddr);

if (addrbit == 16)

sendByte((byte)(addr >> 8));

sendByte((byte)(addr >> 0));

start();

sendByte((byte)(slaveAddr | 0x01));

while (--len > 0)

{

receiveByte(true);

}

receiveByte(false);

ftCommand.Add((byte)0x87);

stop();

 

byte[] cmdBuf = new byte[ftCommand.Count];

for (int i = 0; i < ftCommand.Count; i++)

cmdBuf[i] = (byte)ftCommand[i];


ftStatus = D2XX.FT_Write(ftHandle, cmdBuf, (UInt32)cmdBuf.Length, ref byteWritten);

if (ftStatus != D2XX.eDeviceStatus.FT_OK || byteWritten != (UInt32)cmdBuf.Length)

{

Console.Write("iic read - write command fail\n");

return false;

}

while (true)

{

ftStatus = D2XX.FT_GetQueueStatus(ftHandle, ref byteRead);

if (ftStatus != D2XX.eDeviceStatus.FT_OK)

{

Console.Write("iic read - get queue fail\n");

return false;

}

dly++;

if (dly > 0xffff)

{

Console.Write("iic read - time out\n");

return false;

}

if (byteRead >= rdLen)

break;

Thread.Sleep(1);

}

byte[] rdBuf = new byte[byteRead];

ftStatus = D2XX.FT_Read(ftHandle, rdBuf, (UInt32)rdBuf.Length, ref byteRead);

if (ftStatus != D2XX.eDeviceStatus.FT_OK || byteRead != (UInt32)rdBuf.Length)

{

Console.Write("iic read - read data fail\n");

return false;

}

for (int i = 0; i < rdBuf.Length - rdDatLen; i++)

{

if ((rdBuf[i] & 0x01) == 0x01)

{

Console.Write("iic read - return nack\n");

return false;

}

}

for (int i = (int)(rdBuf.Length - rdDatLen); i < rdBuf.Length; i++)

{

dat[i - (rdBuf.Length -

rdDatLen)] = rdBuf[i];

}

return true;

}

 

write

public static bool write(byte slaveAddr, byte addrbit, UInt16 addr, byte[] dat, UInt32 len)

{

if (len == 0)

return false;

UInt32 rdLen = (UInt32)(addrbit / 8 + 1 + len);

ftCommand.Clear();

start();

sendByte(slaveAddr);

if (addrbit == 16)

sendByte((byte)(addr >> 8));

sendByte((byte)(addr >> 0));

int n = 0;

while (len-- > 0)

{

sendByte(dat[n++]);

}

stop();

ftCommand.Add((byte)0x87);

 

byte[] cmdBuf = new byte[ftCommand.Count];

for (int i = 0; i < ftCommand.Count; i++)

cmdBuf[i] = (byte)ftCommand[i];

 

D2XX.eDeviceStatus ftStatus = D2XX.eDeviceStatus.FT_DEVICE_NOT_FOUND;

UInt32 byteWritten = 0, byteRead = 0, dly = 0;

ftStatus = D2XX.FT_Write(ftHandle, cmdBuf, (UInt32)cmdBuf.Length, ref byteWritten);

if (ftStatus != D2XX.eDeviceStatus.FT_OK || byteWritten != (UInt32)cmdBuf.Length)

{

Console.Write("iic write - write command fail\n");

return false;

}

while (true)

{

ftStatus = D2XX.FT_GetQueueStatus(ftHandle, ref byteRead);

if (ftStatus != D2XX.eDeviceStatus.FT_OK)

{

Console.Write("iic write - get queue fail\n");

return false;

}

dly++;

if (dly > 0xffff)

{

Console.Write("iic write - time out\n");

return false;

}

if (byteRead >= rdLen)

break;

Thread.Sleep(1);

}

byte[] rdBuf = new byte[byteRead];

ftStatus = D2XX.FT_Read(ftHandle, rdBuf, (UInt32)rdBuf.Length, ref byteRead);

if (ftStatus != D2XX.eDeviceStatus.FT_OK || byteRead != (UInt32)rdBuf.Length)

{

Console.Write("iic write - read ack fail\n");

return false;

}

for (int i = 0; i < rdBuf.Length; i++)

{

if ((rdBuf[i] & 0x01) == 0x01)

{

Console.Write("iic write - return nack\n");

return false;

}

}

return true;

}

 

【速度测试】

测试方法:外接AT32C24,读写10KB数据。测试到的速度数据如下:



路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)