I'm using SDK 2.11 on an LPC5512 using MCUexpresso 11.5.1. I've got an I2C bus (400KHz) and am using an I2S amplifier. The LPC is bus master and there are a couple of slaves on it. I2C driver version is 2.3.0
Every so often (random) I see an loss of arbitration error on the I2C using a write/read. Code:
i2c_master_transfer_t masterXfer;
memset(&masterXfer, 0, sizeof(masterXfer));
masterXfer.slaveAddress = Device;
masterXfer.direction = kI2C_Read;
masterXfer.subaddress = reg_addr;
masterXfer.subaddressSize = 1;
masterXfer.data = rxBuff;
masterXfer.dataSize = rxSize;
masterXfer.flags = kI2C_TransferDefaultFlag;/* direction=write : start+device_write;cmdbuff;xBuff; */
/* direction=recive : start+device_write;cmdbuff;repeatStart+device_read;xBuff; */RetVal = I2C_MasterTransferBlocking(ACCEL_I2C_PERIPHERAL, &masterXfer);
This will go like this:
This appears to be something connected to power somehow BUT I'd like to recover from it. If I just restart the transfer I get something more interesting:
and the transfer hangs forever waiting for some status to happen that never does in fsl_i2c.c around line 425
Interestingly enough, I've got the I2C channel supposedly configured in the peripherals tool to timeout in like 35mS but it never does.
How do I get this thing reset and running again?
I don't find any reference to the timeout code being enabled. Is the tool not putting out the right stuff there? Or does it just not do that?
How did you finally resolve this issue?
I'm asking as I think I see a similar behavior when I force SCL low for even a very short amount of time during times when the I2C bus is idle (for example manually with a push button). That is enough to stop the I2C system in my LPC5526 from working as expected.
> How do I get this thing reset and running again?
Many I2C devices, especially older and less complex one's, seem to be simple state machines. If some impulse gets lost or an additional one interspersed by e.g. EMI, synchonisation is lost. Often, not even a stop event helps. While an amplifier seems not "simple", it might have inherited simpler I2C-IP from older devices ...
One commonly used method is to manually drive CLK pulse (perhaps reconfigure the I2C pins), until the slave releases the bus.
I would try a lower clock frequency as well. Not that I think it is the bus speed per se, assuming the slave has clock stretching implemented.
Hi
Pls try to use non blocking mode, in other words, use the interrupt mechanism to transfer data.
i2c_master_transfer_t masterXfer;
memset(&masterXfer, 0, sizeof(masterXfer));
masterXfer.slaveAddress = Device;
masterXfer.direction = kI2C_Read;
masterXfer.subaddress = reg_addr;
masterXfer.subaddressSize = 1;
masterXfer.data = rxBuff;
masterXfer.dataSize = rxSize;
masterXfer.flags = kI2C_TransferDefaultFlag;
/* direction=write : start+device_write;cmdbuff;xBuff; */
/* direction=recive : start+device_write;cmdbuff;repeatStart+device_read;xBuff; */
RetVal = I2C_MasterTransferNonBlocking(ACCEL_I2C_PERIPHERAL, &g_m_handle,&masterXfer);
You can refer to the example code like:
Because I use the example based on LPC55S69-EVK, I do not know if there is similar example based on LPC5512-EVK.
static bool I2C_ReadAccelRegs(I2C_Type *base, uint8_t device_addr, uint8_t reg_addr, uint8_t *rxBuff, uint32_t rxSize)
{
i2c_master_transfer_t masterXfer;
memset(&masterXfer, 0, sizeof(masterXfer));
masterXfer.slaveAddress = device_addr;
masterXfer.direction = kI2C_Read;
masterXfer.subaddress = reg_addr;
masterXfer.subaddressSize = 1;
masterXfer.data = rxBuff;
masterXfer.dataSize = rxSize;
masterXfer.flags = kI2C_TransferDefaultFlag;
/* direction=write : start+device_write;cmdbuff;xBuff; */
/* direction=recive : start+device_write;cmdbuff;repeatStart+device_read;xBuff; */
I2C_MasterTransferNonBlocking(BOARD_ACCEL_I2C_BASEADDR, &g_m_handle, &masterXfer);
/* wait for transfer completed. */
while ((!nakFlag) && (!completionFlag))
{
}
nakFlag = false;
if (completionFlag == true)
{
completionFlag = false;
return true;
}
else
{
return false;
}
}
Hope it can help you
BR
XiangJun Rong
actually, I had that exact code in there to begin with and changed to blocking to see if that helped (it didn't).