DeviceIoControlCE для I2C

Я уже несколько дней бьюсь головой о проблему. Я хотел бы вашей помощи.

Я пытаюсь подключиться к I2C с платы под управлением Windows CE7. Плата Boundary Devices Nitrogen6X.

Я пытаюсь закодировать это в C#.

После долгих поисков, проб и ошибок я теперь могу делать почти все с I2C (под этим я подразумеваю, что обернул большинство команд в методы, которые работают). Конечно, одна вещь, которую я пока не могу сделать - это чтение / запись. Я пробовал несколько разных реализаций, портируя код на C и C++, который предположительно работал. Но безрезультатно. В настоящее время я прилагаю больше усилий в двух реализациях, которые я скопирую здесь.

Ни одна из этих реализаций не работает для меня. Оба вводят часть управления ошибками, и оба сообщают об ошибке номер 87 (ERROR_INVALID_PARAMETER).

У кого-нибудь есть опыт решения подобных проблем? кто-то может указать, что я делаю не так?

Редактировать 1: Я, вероятно, должен упомянуть, что я пытаюсь "увидеть" некоторые сигналы на выводах SDA и SCL платы I2C3: платы, просто подключив к ним осциллограф. Фактическое устройство не подключено к шине 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: я пытался реализовать версию, передавая 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) это будет Похоже, что параметр размера, который я должен отправить, - это общее количество байтов моей передачи, включая все. Я сам пытался выяснить это число, но пока не смог. В качестве альтернативы, я думаю, можно было бы попытаться что-то сделать со структурами, которые мне нужны, чтобы превратить их в байтовый массив. Только я предполагаю, что система должна иметь определенный порядок байтов, чтобы система могла это понять.
Кто-нибудь может рассказать об этом?

0 ответов

Другие вопросы по тегам