3

几天来,我一直在努力解决一个问题。我需要你的帮助。

我正在尝试从运行 Windows CE7 的板上连接到 I2C。该板是边界设备Nitrogen6X。

我正在尝试用 C# 编写代码。

经过大量的谷歌搜索和反复试验,我现在可以用 I2C 完成几乎所有的事情(我的意思是我将大多数命令包装在有效的方法中)。当然,我还不能做的一件事是阅读/写作。我一直在尝试一些不同的实现,移植据说可以工作的 C 和 C++ 代码。无济于事。目前我正在将更多的精力放在我将在这里复制的两个实现上。

这些实现都不适合我。两者都进入错误管理部分,并且都报告错误号 87 (ERROR_INVALID_PARAMETER)。

有没有人在这类问题上有经验?有人能指出我做错了什么吗?

编辑 1:我可能应该提到,我试图通过简单地将示波器插入到板上的 I2C3:SDA 和 SCL 引脚上“查看”一些信号。I2C 总线上没有连接实际设备。我希望这会在发送第一个字节(地址+读/写)后给我一些错误,因为不会收到确认位。但是,我在代码中看到了错误 87,并且从示波器看到的信号没有变化(两者都在空闲时保持高电平)。

(代码片段如下)

第一个使用指针和东西,可能更接近 C++ 代码:

StructLayout(LayoutKind.Sequential)]
    unsafe public struct UNSAFE_I2C_PACKET
    {
        //[MarshalAs(UnmanagedType.U1)]
        public byte byAddr; //I2C slave device address
        //[MarshalAs(UnmanagedType.U1)]
        public byte byRw; //Read = I2C_Read or Write = I2C_Write
        //[MarshalAs(UnmanagedType.LPArray)]
        public byte* pbyBuf; //Message Buffer
        //[MarshalAs(UnmanagedType.U2)]
        public Int16 wLen; //Message Buffer Length
        //[MarshalAs(UnmanagedType.LPStruct)]
        public int* lpiResult; //Contain the result of last operation
    }
    [StructLayout(LayoutKind.Sequential)]
    unsafe public struct UNSAFE_I2C_TRANSFER_BLOCK
    {
        //public I2C_PACKET pI2CPackets;
        public UNSAFE_I2C_PACKET* pI2CPackets;
        public Int32 iNumPackets;
    }
    [DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
    unsafe internal static extern int DeviceIoControlCE(
        IntPtr hDevice, //file handle to driver
        uint dwIoControlCode, //a correct call to CTL_CODE
        [In, Out]byte* lpInBuffer,
        uint nInBufferSize,
        byte* lpOutBuffer,
        uint nOutBufferSize,
        uint* lpBytesReturned,
        int* lpOverlapped);
    unsafe public void ReadI2C(byte* pBuf, int count)
    {
        int ret;
        int iResult;
        UNSAFE_I2C_TRANSFER_BLOCK I2CXferBlock = new UNSAFE_I2C_TRANSFER_BLOCK();
        UNSAFE_I2C_PACKET i2cPckt = new UNSAFE_I2C_PACKET();

        //fixed (byte* p = pBuf)
        {
            i2cPckt.pbyBuf = pBuf;// p;
            i2cPckt.wLen = (Int16)count;
            i2cPckt.byRw = I2C_READ;
            i2cPckt.byAddr = BASE;
            i2cPckt.lpiResult = &iResult;

            I2CXferBlock.iNumPackets = 1;
            //fixed (I2C_PACKET* pck = &i2cPckt)
            {
                I2CXferBlock.pI2CPackets = &i2cPckt; // pck;
                //fixed (I2C_TRANSFER_BLOCK* tBlock = &I2CXferBlock)
                {
                    if (DeviceIoControlCE(_i2cFile,
                                    I2C_IOCTL_TRANSFER,
                                    (byte*)&I2CXferBlock,//tBlock,
                                    (uint)sizeof(UNSAFE_I2C_TRANSFER_BLOCK),//Marshal.SizeOf(I2CXferBlock),
                                    null,
                                    0,
                                    null,
                                    null) == 0)
                    {
                        int error = GetLastError();
                        diag("Errore nella TRANSFER");
                        diag(error.ToString());
                    }
                }
            }
        }
    }

我正在处理的第二个选项是在托管和非托管之间编组:

[StructLayout(LayoutKind.Sequential)]
    public struct I2C_PACKET
    //public class I2C_PACKET
    {
        //[MarshalAs(UnmanagedType.U1)]
        public Byte byAddr; //I2C slave device address
        //[MarshalAs(UnmanagedType.U1)]
        public Byte byRw; //Read = I2C_Read or Write = I2C_Write
        //[MarshalAs(UnmanagedType.LPArray)]
        public IntPtr pbyBuf; //Message Buffer
        //[MarshalAs(UnmanagedType.U2)]
        public Int16 wLen; //Message Buffer Length
        //[MarshalAs(UnmanagedType.LPStruct)]
        public IntPtr lpiResult; //Contain the result of last operation
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct I2C_TRANSFER_BLOCK
    {
        //public I2C_PACKET pI2CPackets;
        //[MarshalAs(UnmanagedType.LPArray)]
        public IntPtr pI2CPackets;
        //[MarshalAs(UnmanagedType.U4)]
        public Int32 iNumPackets;
    }
[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
    internal static extern int DeviceIoControlCE(
        IntPtr hDevice, //file handle to driver
        uint dwIoControlCode, //a correct call to CTL_CODE
        [In] IntPtr lpInBuffer,
        uint nInBufferSize,
        [Out] IntPtr lpOutBuffer,
        uint nOutBufferSize,
        out uint lpBytesReturned,
        IntPtr lpOverlapped);
unsafe public void ReadI2C(byte[] buffer)
    {
        int count = buffer.Length;
        I2C_TRANSFER_BLOCK I2CXFerBlock = new I2C_TRANSFER_BLOCK();
        I2C_PACKET I2CPckt = new I2C_PACKET();

        I2CPckt.byAddr = BASE;
        I2CPckt.byRw = I2C_READ;
        I2CPckt.wLen = (Int16)count;
        I2CPckt.lpiResult = Marshal.AllocHGlobal(sizeof(int));
        I2CPckt.pbyBuf = Marshal.AllocHGlobal(count);
        //GCHandle packet = GCHandle.Alloc(I2CPckt, GCHandleType.Pinned);

        I2CXFerBlock.iNumPackets = 1;
        I2CXFerBlock.pI2CPackets = Marshal.AllocHGlobal(Marshal.SizeOf(I2CPckt)); //(Marshal.SizeOf(typeof(I2C_PACKET)));//  //(sizeof(I2C_PACKET));// 
        Marshal.StructureToPtr(I2CPckt, I2CXFerBlock.pI2CPackets, false);
        //I2CXFerBlock.pI2CPackets = packet.AddrOfPinnedObject();

        //GCHandle xferBlock = GCHandle.Alloc(I2CXFerBlock, GCHandleType.Pinned);
        IntPtr xfer = Marshal.AllocHGlobal(Marshal.SizeOf(I2CXFerBlock)); //(sizeof(I2C_TRANSFER_BLOCK)); //
        Marshal.StructureToPtr(I2CXFerBlock, xfer, false);
        //IntPtr xfer = xferBlock.AddrOfPinnedObject();
        uint size = (uint)sizeof(I2C_TRANSFER_BLOCK);//Marshal.SizeOf(I2CXFerBlock);
        uint getCnt = 0;
        if ((DeviceIoControlCE(_i2cFile,
            I2C_IOCTL_TRANSFER, 
            xfer, 
            size, 
            xfer, //IntPtr.Zero, 
            size, //0, 
            out getCnt, 
            IntPtr.Zero)) == 0)
        {
            int error = GetLastError();
            diag("Errore nella TRANSFER.");
            diag(error.ToString());
        }
        else
        {
            //success
            I2CXFerBlock = (I2C_TRANSFER_BLOCK)Marshal.PtrToStructure(xfer, typeof(I2C_TRANSFER_BLOCK));
            I2CPckt = (I2C_PACKET)Marshal.PtrToStructure(I2CXFerBlock.pI2CPackets, typeof(I2C_PACKET));
            Marshal.Copy(I2CPckt.pbyBuf, buffer, 0, count);
            diag("Success in TRANSFER: " + buffer[0].ToString());
        }
        Marshal.FreeHGlobal(I2CPckt.pbyBuf);
        Marshal.FreeHGlobal(I2CXFerBlock.pI2CPackets);
        Marshal.FreeHGlobal(xfer);
        //packet.Free();
        //xferBlock.Free();
    }

编辑 2:我拥有的(据称)工作代码(我无法运行)来自我获得的驱动程序,它可能是部分专有的(因此我无法共享)。但是我在网上找到了 I2C 总线的标头,其中包含以下定义:

#define I2C_MACRO_TRANSFER(hDev, pI2CTransferBlock) \
(DeviceIoControl(hDev, I2C_IOCTL_TRANSFER, (PBYTE) pI2CTransferBlock, sizeof(I2C_TRANSFER_BLOCK), NULL, 0, NULL, NULL))

我最初尝试将“null”赋予参数,因为它在这里完成,但我仍然得到相同的错误代码。

编辑 3:来自同一个驱动程序,结构定义:

// I2C Packet
typedef struct
{
    BYTE byAddr;       // I2C slave device address for this I2C operation
    BYTE byRW;         // Read = I2C_READ or Write = I2C_WRITE
    PBYTE pbyBuf;      // Message Buffer
    WORD wLen;         // Message Buffer Length
    LPINT lpiResult;   // Contains the result of last operation
} I2C_PACKET, *PI2C_PACKET;

// I2C Transfer Block
typedef struct
{
    I2C_PACKET *pI2CPackets;
    INT32 iNumPackets;
} I2C_TRANSFER_BLOCK, *PI2C_TRANSFER_BLOCK;

编辑 4:我尝试实现将 a 传递ref给我的结构的版本,正如@ctacke 在他的评论中所建议的那样。我仍然得到同样的错误,所以我想我一定做了与他想象的不同的事情。这是片段:

[StructLayout(LayoutKind.Sequential)]
    public struct REF_I2C_PACKET //public class REF_I2C_PACKET //
    {
        //[MarshalAs(UnmanagedType.U1)]
        public Byte byAddr; //I2C slave device address
        //[MarshalAs(UnmanagedType.U1)]
        public Byte byRw; //Read = I2C_Read or Write = I2C_Write
        //[MarshalAs(UnmanagedType.LPArray)]
        public IntPtr pbyBuf; //Message Buffer
        //[MarshalAs(UnmanagedType.U2)]
        public Int16 wLen; //Message Buffer Length
        //[MarshalAs(UnmanagedType.LPStruct)]
        public IntPtr lpiResult; //Contain the result of last operation
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct REF_I2C_TRANSFER_BLOCK //public class REF_I2C_TRANSFER_BLOCK //
    {
        //public I2C_PACKET pI2CPackets;
        public IntPtr pI2CPackets;
        //[MarshalAs(UnmanagedType.U4)]
        public Int32 iNumPackets;
        //[MarshalAs(UnmanagedType.LPArray)]
        //[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPStruct, SizeConst = 2)]
        //public REF_I2C_PACKET[] pI2CPackets;
    }
    [DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
    unsafe internal static extern int DeviceIoControlCE(
        IntPtr hDevice, //file handle to driver
        uint dwIoControlCode, //a correct call to CTL_CODE
        //[MarshalAs(UnmanagedType.AsAny)]
        //[In] object lpInBuffer, //
        ref REF_I2C_TRANSFER_BLOCK lpInBuffer,
        uint nInBufferSize,
        byte* lpOutBuffer, //ref REF_I2C_TRANSFER_BLOCK lpOutBuffer,
        uint nOutBufferSize,
        out uint lpBytesReturned, //uint* lpBytesReturned,
        int* lpOverlapped);
    unsafe public void RefReadI2C(byte[] buffer)
    {
        int count = buffer.Length;
        REF_I2C_TRANSFER_BLOCK I2CXFerBlock = new REF_I2C_TRANSFER_BLOCK();
        REF_I2C_PACKET[] I2CPckt = new REF_I2C_PACKET[2];
        I2CPckt[0] = new REF_I2C_PACKET();
        I2CPckt[1] = new REF_I2C_PACKET();

        I2CPckt[0].byAddr = BASE;
        I2CPckt[0].byRw = I2C_READ;
        I2CPckt[0].wLen = (Int16)count;
        I2CPckt[0].lpiResult = Marshal.AllocHGlobal(sizeof(int));
        I2CPckt[0].pbyBuf = Marshal.AllocHGlobal(count);
        Marshal.Copy(buffer, 0, I2CPckt[0].pbyBuf, count);

        I2CPckt[1].byAddr = BASE;
        I2CPckt[1].byRw = I2C_READ;
        I2CPckt[1].wLen = (Int16)count;
        I2CPckt[1].lpiResult = Marshal.AllocHGlobal(sizeof(int));
        I2CPckt[1].pbyBuf = Marshal.AllocHGlobal(count);
        Marshal.Copy(buffer, 0, I2CPckt[0].pbyBuf, count);

        I2CXFerBlock.iNumPackets = 2;
        I2CXFerBlock.pI2CPackets = Marshal.AllocHGlobal(Marshal.SizeOf(I2CPckt[0])*I2CPckt.Length);

        uint size = (uint)Marshal.SizeOf(I2CXFerBlock); //sizeof(REF_I2C_TRANSFER_BLOCK);//Marshal.SizeOf(I2CXFerBlock);
        //size += (uint)(Marshal.SizeOf(I2CPckt[0]) * I2CPckt.Length);
        uint getCnt = 0;
        if ((DeviceIoControlCE(_i2cFile,
            I2C_IOCTL_TRANSFER,
            ref I2CXFerBlock,
            size,
            null, //IntPtr.Zero, 
            0, //0, 
            out getCnt,
            null)) == 0)
        {
            int error = GetLastError();
            diag("Errore nella TRANSFER.");
            diag(error.ToString());
        }
        else
        {
            //success

            I2CPckt = (REF_I2C_PACKET[])Marshal.PtrToStructure(I2CXFerBlock.pI2CPackets, typeof(REF_I2C_PACKET[]));
            Marshal.Copy(I2CPckt[0].pbyBuf, buffer, 0, count);
            diag("Success in TRANSFER: " + buffer[0].ToString());
        }
        Marshal.FreeHGlobal(I2CPckt[0].pbyBuf);
        Marshal.FreeHGlobal(I2CPckt[0].lpiResult);
    }

编辑5:
我在网上找到(http://em-works.googlecode.com/svn/trunk/WINCE600/PLATFORM/COMMON/SRC/SOC/COMMON_FSL_V2_PDK1_9/I2C/PDK/i2c_io.cpp)以下代码:

BOOL I2C_IOControl(DWORD hOpenContext, DWORD dwCode, PBYTE pBufIn, 
               DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut,
               PDWORD pdwActualOut)
{
    /*stuff*/
    case I2C_IOCTL_TRANSFER:
        {
#define MARSHAL 1
#if MARSHAL
            DuplicatedBuffer_t Marshalled_pInBuf(pBufIn, dwLenIn, ARG_I_PTR);
            pBufIn = reinterpret_cast<PBYTE>( Marshalled_pInBuf.ptr() );
            if( (dwLenIn > 0) && (NULL == pBufIn) )
            {
                return FALSE;
            }
#endif
            I2C_TRANSFER_BLOCK *pXferBlock = (I2C_TRANSFER_BLOCK *) pBufIn;
            if (pXferBlock->iNumPackets<=0) 
            {
                return FALSE;
            }

#if MARSHAL
            MarshalledBuffer_t Marshalled_pPackets(pXferBlock->pI2CPackets, 
                                                   pXferBlock->iNumPackets*sizeof(I2C_PACKET), 
                                                   ARG_I_PTR);

            I2C_PACKET *pPackets = reinterpret_cast<I2C_PACKET *>(Marshalled_pPackets.ptr());
            if( (NULL == pPackets) )
            {
                return FALSE;
            }
#else
            I2C_PACKET *pPackets = pXferBlock->pI2CPackets;
#endif

#if MARSHAL
           struct Marshalled_I2C_PACKET
            {
                MarshalledBuffer_t *pbyBuf;
                MarshalledBuffer_t *lpiResult;
            } *Marshalled_of_pPackets;

            Marshalled_of_pPackets = new Marshalled_I2C_PACKET[pXferBlock->iNumPackets];
            if (Marshalled_of_pPackets==0)
            {
                return FALSE;
            }

            MarshalledBuffer_t *pMarshalled_ptr;
            int i;

           // Map pointers for each packet in the array
            for (i = 0; i < pXferBlock->iNumPackets; i++)
            {
                switch( pPackets[i].byRW & I2C_METHOD_MASK )
                {
                case I2C_RW_WRITE:
                    pMarshalled_ptr = new MarshalledBuffer_t(
                                           pPackets[i].pbyBuf,
                                           pPackets[i].wLen,
                                           ARG_I_PTR,
                                           FALSE, FALSE);
                    if (pMarshalled_ptr ==0)
                    {
                        bRet = FALSE;
                        goto cleanupPass1;
                    }
                    if (pMarshalled_ptr->ptr()==0)
                    {
                        bRet = FALSE;
                        delete pMarshalled_ptr;
                        goto cleanupPass1;
                    }
                    break;

                case I2C_RW_READ:
                    pMarshalled_ptr = new MarshalledBuffer_t(
                                           pPackets[i].pbyBuf,
                                           pPackets[i].wLen,
                                           ARG_O_PTR, FALSE, FALSE);
                    if (pMarshalled_ptr ==0)
                    {
                        bRet = FALSE;
                        goto cleanupPass1;
                    }
                    if (pMarshalled_ptr->ptr()==0)
                    {
                        bRet = FALSE;
                        delete pMarshalled_ptr;
                        goto cleanupPass1;
                    }
                    break;

                default:
                    {
                        bRet = FALSE;
                        goto cleanupPass1;
                    }
                }

                pPackets[i].pbyBuf = reinterpret_cast<PBYTE>(pMarshalled_ptr->ptr());
                Marshalled_of_pPackets[i].pbyBuf = pMarshalled_ptr;
            }

            for (i = 0; i < pXferBlock->iNumPackets; i++)
            {
                pMarshalled_ptr = new MarshalledBuffer_t(
                                 pPackets[i].lpiResult, sizeof(INT), 
                                 ARG_O_PDW, FALSE, FALSE);

                if (pMarshalled_ptr ==0)
                {
                    bRet = FALSE;
                    goto cleanupPass2;
                }
                if (pMarshalled_ptr->ptr()==0)
                {
                    bRet = FALSE;
                    delete pMarshalled_ptr;
                    goto cleanupPass2;
                }
                pPackets[i].lpiResult = reinterpret_cast<LPINT>(pMarshalled_ptr->ptr());
                Marshalled_of_pPackets[i].lpiResult = pMarshalled_ptr;
            }
#endif

            bRet = pI2C->ProcessPackets(pPackets, pXferBlock->iNumPackets);

#if MARSHAL
            DEBUGMSG (ZONE_IOCTL|ZONE_FUNCTION, (TEXT("I2C_IOControl:I2C_IOCTL_TRANSFER -\r\n")));

            i = pXferBlock->iNumPackets;
cleanupPass2:
            for (--i; i>=0; --i)
            {
                delete Marshalled_of_pPackets[i].lpiResult;
            }

            i = pXferBlock->iNumPackets;
cleanupPass1:
            for (--i; i>=0; --i)
            {
                delete Marshalled_of_pPackets[i].pbyBuf;
            }

            delete[] Marshalled_of_pPackets;

#endif
            break;
        }
/*stuff*/
}

我不能声称理解 100%,但根据 Windows 命名约定(http://msdn.microsoft.com/en-us/library/windows/desktop/aa378932(v=vs.85).aspx)它会看来我应该发送的大小参数是我传输的总字节数,包括所有内容。我试图自己弄清楚这个数字,但到目前为止我还不能。或者,我想可以尝试对必须将它们转换为字节数组的结构做一些事情。只有我猜它需要有一个特定的字节顺序才能让系统理解它。
任何人都可以参与其中吗?

4

0 回答 0