CH341 IIC通讯时钟速率问题

一年前咨询过,因为iic 从机为MCU硬件,在处理主机读取数据时,速度比较慢,会出现连续读取数据时,在上一byte的ACK回复完后1个clk时间内不能释放scl的问题。

现在自己重新写读取函数实现了,如下:

但是此函数因为iic数据流包大小被限制在32byte,所以当我的读取数据连续超过12个byte时,iic数据流超出了32个字节

当我使用两个数据流宝来实现时,两个包之间的时间有200-1200us间隔不等,请问有好的解决办法没有?

public bool MulReadIIC(UInt32 iIndex, byte addr, byte reg, Byte[] data, uint data_Len)

        {

            byte i = 0;

            Byte[] mBuffer = new Byte[64];

            UInt32 mLength, mInLen;

            mBuffer[i++] = USBIOXdll.mCH341A_CMD_I2C_STREAM;  // 命令码

            mBuffer[i++] = USBIOXdll.mCH341A_CMD_I2C_STM_STA;  // 产生起始位

            mBuffer[i++] = USBIOXdll.mCH341A_CMD_I2C_STM_OUT | 2;  //  

            mBuffer[i++] = addr;  // 

            mBuffer[i++] = reg;  // 

            mBuffer[i++] = USBIOXdll.mCH341A_CMD_I2C_STM_STA;  // 产生起始位

            mBuffer[i++] = USBIOXdll.mCH341A_CMD_I2C_STM_OUT;  //  

            mBuffer[i++] = (byte)(addr + 1);  // 产生起始位

            for(byte count=0;count< data_Len-1; count++)

            {

                mBuffer[i++] = USBIOXdll.mCH341A_CMD_I2C_STM_US + 4;  // 延时4us

                mBuffer[i++] = USBIOXdll.mCH341A_CMD_I2C_STM_IN + 1;  // 输入数据,位5-位0为长度,0长度则只接收一个字节并发送无应答

            }

            mBuffer[i++] = USBIOXdll.mCH341A_CMD_I2C_STM_US + 4;  // 延时4us

            mBuffer[i++] = USBIOXdll.mCH341A_CMD_I2C_STM_IN;  // 输入数据,位5-位0为长度,0长度则只接收一个字节并发送无应答

            mBuffer[i++] = USBIOXdll.mCH341A_CMD_I2C_STM_END;  // 当前包提前结束

            mLength = i;

            mInLen = 0;


            USBIOXdll.USBIO_WriteRead(iIndex, mLength, mBuffer, 0x3F, 1, ref mInLen, mBuffer);  // 写出数据块

            return true;

        }


您好,可尝试按照如下方式组包,实现发送I2C设备地址后延迟一段时间读数据,以及连续读取数据的时钟之间插入微秒级延迟。如下函数支持长包读写,也即将需要读写的过程拼成长包处理。也可以发邮件给我们获取完整工程用于测试。邮箱:tech@wch.cn 

BOOL    WINAPI  CH341StreamI2C_Delay(  // 处理I2C数据流,2线接口,时钟线为SCL引脚,数据线为SDA引脚(准双向I/O),速度约56K字节

    ULONG           iIndex,  // 指定CH341设备序号

    ULONG           iWriteLength,  // 准备写出的数据字节数

    PVOID           iWriteBuffer,  // 指向一个缓冲区,放置准备写出的数据,首字节通常是I2C设备地址及读写方向位

    ULONG           iReadLength,  // 准备读取的数据字节数

    PVOID           oReadBuffer,   // 指向一个缓冲区,返回后是读入的数据

    UCHAR           iReadDelay1,   //地址后的延时,单位US,数值范围:0~15

    UCHAR           iReadDelay2)   //读间隔延时,单位US,数值范围:0~15

{

    UCHAR           mBuffer[ mDEFAULT_COMMAND_LEN + mDEFAULT_COMMAND_LEN / 8 ];

    ULONG           i, j, mLength;

    PUCHAR          mWrBuf;

    //if ( dllCH341VerIC[ iIndex ] < 0x20 ) return( FALSE );  // not CH341A

    mLength = max( iWriteLength, iReadLength );

    if ( mLength > mMAX_BUFFER_LENGTH ) return( FALSE );

    if ( mLength <= mDEFAULT_BUFFER_LEN ) mWrBuf = (PUCHAR)mBuffer;  // 不超过默认缓冲区长度

    else {  // 超过则需要另外分配内存

        mWrBuf = (PUCHAR)LocalAlloc( LMEM_FIXED, mMAX_COMMAND_LENGTH + mMAX_COMMAND_LENGTH / 8 );  // 分配内存

        if ( mWrBuf == NULL ) return( FALSE );  // 分配内存失败

    }

    i = 0;

    mWrBuf[ i++ ] = mCH341A_CMD_I2C_STREAM;  // 命令码

    //if ( ( dllCH341StreamMode[ iIndex ] & 0x03 ) == 0 ) {

    //  mWrBuf[ i++ ] = mCH341A_CMD_I2C_STM_US | 10;  // 延时10微秒

    //  mWrBuf[ i++ ] = mCH341A_CMD_I2C_STM_US | 10;  // 延时10微秒

    //}

    mWrBuf[ i++ ] = mCH341A_CMD_I2C_STM_STA;  // 产生起始位

    if ( iWriteLength ) {

        for ( j = 0; j < iWriteLength; ) {

            mLength = mCH341_PACKET_LENGTH - i % mCH341_PACKET_LENGTH;  // 当前包剩余长度,

            if ( mLength <= 2 ) {

                while ( mLength-- ) mWrBuf[ i++ ] = mCH341A_CMD_I2C_STM_END;  // 当前包提前结束

                mLength = mCH341_PACKET_LENGTH;

            }

            if ( mLength >= mCH341_PACKET_LENGTH ) {

                mWrBuf[ i++ ] = mCH341A_CMD_I2C_STREAM;  // 新包的命令码

                mLength = mCH341_PACKET_LENGTH - 1;

            }

            mLength--;  // 去掉尾部的提前结束码

            mLength--;  // 去掉输出数据的命令码

            if ( mLength > iWriteLength - j ) mLength = iWriteLength - j;  // 本次输出有效数据长度

            mWrBuf[ i++ ] = (UCHAR)( mCH341A_CMD_I2C_STM_OUT | mLength );  // 输出数据,位5-位0为长度

            while ( mLength-- ) mWrBuf[ i++ ] = *( (PUCHAR)iWriteBuffer + j++ );  // 复制数据

        }

    }

    if ( iReadLength ) {

        mLength = mCH341_PACKET_LENGTH - i % mCH341_PACKET_LENGTH;  // 当前包剩余长度,

        if ( mLength <= 3 ) {

            while ( mLength-- ) mWrBuf[ i++ ] = mCH341A_CMD_I2C_STM_END;  // 当前包提前结束

            mLength = mCH341_PACKET_LENGTH;

        }

        if ( mLength >= mCH341_PACKET_LENGTH ) mWrBuf[ i++ ] = mCH341A_CMD_I2C_STREAM;  // 新包的命令码

        if ( iWriteLength > 1 ) {  // 先输出

            mWrBuf[ i++ ] = mCH341A_CMD_I2C_STM_STA;  // 产生起始位

            mWrBuf[ i++ ] = (UCHAR)( mCH341A_CMD_I2C_STM_OUT | 1 );  // 输出数据,位5-位0为长度

            mWrBuf[ i++ ] = *(PUCHAR)iWriteBuffer | 0x01;  // I2C目标设备地址,最低位为1则进行读操作

        }

        else if ( iWriteLength ) {  // 输出一字节后直接输入

            i--;

            mWrBuf[ i++ ] = *(PUCHAR)iWriteBuffer | 0x01;  // I2C目标设备地址,最低位为1则进行读操作

        }

        mWrBuf[ i++ ] = mCH341A_CMD_I2C_STM_US | ( iReadDelay1& 0x0f );  // 延时10微秒

        for ( j = 1; j < iReadLength; ) {

            mLength = mCH341_PACKET_LENGTH - i % mCH341_PACKET_LENGTH;  // 当前包剩余长度,

            //mLength = 1;

            if ( mLength <= 1 ) {

                if ( mLength ) mWrBuf[ i++ ] = mCH341A_CMD_I2C_STM_END;  // 当前包提前结束

                mLength = mCH341_PACKET_LENGTH;

            }

            if ( mLength >= mCH341_PACKET_LENGTH ) mWrBuf[ i++ ] = mCH341A_CMD_I2C_STREAM;  // 新包的命令码

            //mLength = iReadLength - j >= mCH341A_CMD_I2C_STM_MAX ? mCH341A_CMD_I2C_STM_MAX : iReadLength - j;  // 本次输入有效数据长度

            mLength = iReadLength - j >= mCH341A_CMD_I2C_STM_MAX ? mCH341A_CMD_I2C_STM_MAX : 1;  // 本次输入有效数据长度

            mWrBuf[ i++ ] = (UCHAR)( mCH341A_CMD_I2C_STM_IN | mLength );  // 输入数据,位5-位0为长度

            j += mLength;

            if ( mLength >= mCH341A_CMD_I2C_STM_MAX ) {  // 当前包将满

                mWrBuf[ i ] = mCH341A_CMD_I2C_STM_END;  // 当前包提前结束

                i += mCH341_PACKET_LENGTH - i % mCH341_PACKET_LENGTH;  // 跳过当前包剩余部分

            }

            mWrBuf[ i++ ] = mCH341A_CMD_I2C_STM_US | ( iReadDelay2& 0x0f );  // 延时10微秒

        }

        mLength = mCH341_PACKET_LENGTH - i % mCH341_PACKET_LENGTH;  // 当前包剩余长度,

        if ( mLength <= 1 ) {

            if ( mLength ) mWrBuf[ i++ ] = mCH341A_CMD_I2C_STM_END;  // 当前包提前结束

            mLength = mCH341_PACKET_LENGTH;

        }

        if ( mLength >= mCH341_PACKET_LENGTH ) mWrBuf[ i++ ] = mCH341A_CMD_I2C_STREAM;  // 新包的命令码

        mWrBuf[ i++ ] = mCH341A_CMD_I2C_STM_IN;  // 输入数据,只接收一个字节并发送无应答

    }

    mLength = mCH341_PACKET_LENGTH - i % mCH341_PACKET_LENGTH;  // 当前包剩余长度,

    if ( mLength <= 1 ) {

        if ( mLength ) mWrBuf[ i++ ] = mCH341A_CMD_I2C_STM_END;  // 当前包提前结束

        mLength = mCH341_PACKET_LENGTH;

    }

    if ( mLength >= mCH341_PACKET_LENGTH ) mWrBuf[ i++ ] = mCH341A_CMD_I2C_STREAM;  // 新包的命令码

    mWrBuf[ i++ ] = mCH341A_CMD_I2C_STM_STO;  // 产生停止位

    mWrBuf[ i++ ] = mCH341A_CMD_I2C_STM_END;  // 当前包提前结束

    mLength = 0;

    if ( iReadLength ) j = CH341WriteRead( iIndex, i, mWrBuf, mCH341A_CMD_I2C_STM_MAX, ( iReadLength + mCH341A_CMD_I2C_STM_MAX - 1 ) / mCH341A_CMD_I2C_STM_MAX, &mLength, oReadBuffer );  // 执行数据流命令,先输出再输入

    else j = CH341WriteData( iIndex, mWrBuf, &i );  // 写出数据块

    if ( j && mLength != iReadLength ) j = FALSE;

    if ( mWrBuf != mBuffer ) LocalFree( mWrBuf );  // 如果是分配的内存则释放

    return( j );

}



谢谢!
我先尝试一下!


长包命令格式是怎么样的?



如电话沟通,这边整理下格式然后邮件发送过去。


只有登录才能回复,可以选择微信账号登录