I2C loss of arbitration on LPC5512

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

I2C loss of arbitration on LPC5512

2,032 次查看
randylee
Contributor V

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:

randylee_0-1662067185397.png

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:

randylee_1-1662067245833.png

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.

randylee_2-1662067485682.png

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?

 

标签 (1)
4 回复数

989 次查看
danielholala
Senior Contributor II

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.

0 项奖励
回复

1,986 次查看
frank_m
Senior Contributor III

> 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.

0 项奖励
回复

2,015 次查看
xiangjun_rong
NXP TechSupport
NXP TechSupport

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:

xiangjun_rong_0-1662357805663.png

 

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

0 项奖励
回复

1,990 次查看
randylee
Contributor V

actually, I had that exact code in there to begin with and changed to blocking to see if that helped (it didn't).