2011-06-07 03:29:05 I2C abort with no information
isabelle leonardi (FRANCE)
Message: 101046
Hi,
I'm using uclinux distribution 2010-RC5 on a BF548.
The software periodically performs I2C read transaction (by calling i2c_smbus_read_byte_data). Sometimes the transaction fails on timeout but there is no error notified on interrupt (no interrupt with MERR bit set). The last interrupt I get shows that MEN bit is reset while the transaction is not finished.
During a normal read sequence, I can observe 4 or 5 interrupts:
- IT1: INT_STAT = 0xC040 - MASTER_CTL = 0x01 on entry - MASTER_CTL = 0x25 on return
- IT2: INT_STAT = 0xC010 - MASTER_CTL = 0x25 on entry - MASTER_CTL = 0x45 on return
- IT3: INT_STAT = 0xC000 - MASTER_CTL = 0x45 on entry - MASTER_CTL = 0x45 on return
- IT4: INT_STAT = 0xC080 - MASTER_CTL = 0x05 on entry - MASTER_CTL = 0x05 on return
- IT5: INT_STAT = 0xC010 - MASTER_CTL = 0x04 on entry - MASTER_CTL = 0x00 on return
During the failing read sequence, I can observe only 1 interrupt:
- IT1: INT_STAT = 0xC050 - MASTER_CTL = 0x00 on entry - MASTER_STAT = 0x00
What can be the reason why the transaction is aborted without any notified error?
The interrupt handler for I2C bfin_twi_interrupt_entry in drivers/i2c/busses/i2c-bfin-twi.c does not particularly handle this case. The whole transaction simply fails on timeout (after 500 jiffies!!). Would it be correct to handle the unexpected case of a MEN reset in the handler by changing the interrupt handler as follows?
...line 203
if (twi_int_status & MCOMP) {
if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
if ((read_MASTER_CTL(iface) & MEN) == 0)
{
iface->result = -1;
write_INT_MASK(iface, 0);
write_MASTER_CTL(iface, 0);
}
else
{
if (iface->readNum == 0) {
/* set the read number to 1 and ask for manual
* stop in block combine mode
*/
iface->readNum = 1;
iface->manual_stop = 1;
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) | (0xff << 6));
} else {
/* set the readd number in other
* combine mode.
*/
write_MASTER_CTL(iface,
(read_MASTER_CTL(iface) &
(~(0xff << 6))) |
(iface->readNum << 6));
}
/* remove restart bit and enable master receive */
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) & ~RSTART);
}
} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
iface->cur_msg+1 < iface->msg_num) {
iface->cur_msg++;
iface->transPtr = iface->pmsg[iface->cur_msg].buf;
iface->writeNum = iface->readNum =
iface->pmsg[iface->cur_msg].len;
/* Set Transmit device address */
write_MASTER_ADDR(iface,
iface->pmsg[iface->cur_msg].addr);
if (iface->pmsg[iface->cur_msg].flags & I2C_M_RD)
iface->read_write = I2C_SMBUS_READ;
else {
iface->read_write = I2C_SMBUS_WRITE;
/* Transmit first data */
if (iface->writeNum > 0) {
write_XMT_DATA8(iface,
*(iface->transPtr++));
iface->writeNum--;
}
}
if (iface->pmsg[iface->cur_msg].len <= 255) {
write_MASTER_CTL(iface,
(read_MASTER_CTL(iface) &
(~(0xff << 6))) |
(iface->pmsg[iface->cur_msg].len << 6));
iface->manual_stop = 0;
} else {
write_MASTER_CTL(iface,
(read_MASTER_CTL(iface) |
(0xff << 6)));
iface->manual_stop = 1;
}
/* remove restart bit and enable master receive */
write_MASTER_CTL(iface,
read_MASTER_CTL(iface) & ~RSTART);
} else {
iface->result = 1;
write_INT_MASK(iface, 0);
write_MASTER_CTL(iface, 0);
}
complete(&iface->complete);
}
Thanks for your help,
Isabelle
QuoteReplyEditDelete
2011-06-17 07:01:00 Re: I2C abort with no information
Sonic Zhang (CHINA)
Message: 101382
Yes, this unexpected MEN reset should be handled for both TWI_I2C_MODE_COMBINED and TWI_I2C_MODE_REPEAT. I will commit a patch soon.
This abort looks like the first transmit interrupt is not served in time because some higher interrupt handler is running in kernel. So, the RESART bit is not set before next I2C clock. When the TWI interrupt handler is called finally, the I2C session is aborted (MEN bit is reset) and both SMITSERV and MCOMP int status bits are set. Don't know why ERR status is not set in this case.