I think i have found a bug in the Windows CE 6.0 (and 7.0?) I2C driver (PLATFORM/COMMON/SOC/MX28_FSL_V2_PDK1_9/I2C/PDK/i2cClass.cpp). The Original code is not working if I try to simply read data:
I2C_TRANSFER_BLOCK I2CXferBlock;
I2C_PACKET I2CPacket[2];
BYTE byOutValue;
INT iResult[2];
byOutValue = byAddr | 1; //READ
I2CPacket[0].pbyBuf = (PBYTE) &byOutValue;
I2CPacket[0].wLen = 1;
I2CPacket[0].byRW = I2C_RW_WRITE;
I2CPacket[0].lpiResult = &iResult[0];
I2CPacket[1].pbyBuf = (PBYTE) lpbBuffer;
I2CPacket[1].wLen = iBufferSize;
I2CPacket[1].byRW = I2C_RW_READ;
I2CPacket[1].lpiResult = &iResult[1];
I2CXferBlock.pI2CPackets = I2CPacket;
I2CXferBlock.iNumPackets = 2;
if(I2CTransfer(hI2C, &I2CXferBlock))
{
*lpiResult = iResult[1];
}
else
{
*lpiResult = -1;
}
The 1. Byte is send but the iMX28 do not continue sending clock's to read the Data bytes. This results in a locked up I2C Bus (Data line may stay low because the I2C slave has written the first bit but do not get any further Clocks).
I found that the problem is the RETAIN_CLOCK Bit in HW_I2C_CTRL0, unfortunately this bit is not very good documented, but to me it seems necessary to set this bit before changing in receive mode.
This is the pach I made to i2CClass.cpp:
Index: i2cClass.cpp
===================================================================
--- i2cClass.cpp (revision 2281)
+++ i2cClass.cpp (revision 2282)
@@ -552,9 +552,10 @@
dwCtrl0 |= BM_I2C_CTRL0_PRE_SEND_START;
// if there is more than 1 packet in the chain, set the RETAIN_LOCK bit on all buffers except first and last
- if ( numPackets > 1 && i != 0)
+ // we have to set RETAIN_LOCK if the next packet is a a read!
+ if ( numPackets > 1 && packets[i+1].byRW == I2C_RW_READ)
dwCtrl0 |= BF_I2C_CTRL0_RETAIN_CLOCK(BV_I2C_CTRL0_RETAIN_CLOCK__HOLD_LOW);
// WAIT4ENDCMD
dwDMACmd |= BF_APBX_CHn_CMD_WAIT4ENDCMD(1);
}
@@ -609,6 +610,7 @@
}
Martin