Hi.
I have a problem occuring with I²C at 400 kHz and not happening at 100 kHz. I am using a F2809 DSP in slave I²C. I am sending GET_STATUS command which is basically requesting for 4 status bytes from the DSP. One address byte, one command byte, repeated start, then reading 4 status bytes.
In this explanation, I'll use the status 0xAA 0xBB 0xCC 0xDD. Bug is happening around 1% of the time.
The resulting behavious is that the first byte is junk and then the status is sent, like 0x5D 0xAA 0xBB 0xCC (with last byte missing). When I probe and log interrupts, I get the following.
I will use this notation for interrupts and status flags. I enable interrupts on these 4 conditions in the I2CIER.
AAS: Addressed as slave
RRDY: Receive data ready
XRDY: Transmit data ready
SCD: Stop condition
The sequence is the following when everything goes well.
AAS - RRDY - SCD - AAS - XRDY - XRDY - XRDY - XRDY - SCD and I get 0xAABBCCDD as resulting 4 bytes.
When the bug occurs, I read an INTCODE = 000 sometimes
AAS - RRDY - SCD - AAS - NONE - XRDY - XRDY - XRDY - SCD and I get 0xAABBCCDD as resulting 4 bytes.
In this case, reading the I2CSTR status register, I get nothing else than [SDIR + BB + XSMT + AAS]. Flag for XRDY is not set, compared to when there is no bug. If I use some TestGPIO to monitor when the interrupt is occuring, I see no change compared to the working sequence. Interrupt is trigged, but read as NONE for INTCODE. During the process, I also save into debug arrays the complete sequence and nothing is different except for this INTCODE and for the XRDY flag in the I2CSTR.
Another behaviour that I saw few times is that instead of a INTCODE=000, no interrupt is occuring at all at the first XRDY interrupt regular spot. This also cause data to be erroneous, repeating the first byte (0xAA). [AAS - RRDY - SCD - AAS - - XRDY - XRDY - XRDY - SCD]
So my questions are the following:
- How is it possible to get an INTCODE=000
- Why is the DSP missing a XRDY interrupt by reading INTCODE=000 or by missing it completely?
- Anyone is seeing anything in my code that cuold result in this behaviour ?
I attached the i2c_isr function I am using, I removed the debugging logging arrays and flags for simplicity purpose.
// ****************************************************************************
// Function: i2c_int1a_isr
// ****************************************************************************
interrupt void i2c_int1a_isr(void) // I2C-A
{
Uint16 IntSource;
static uint16 CmdIncomplete = 0;
// Read interrupt source
IntSource = I2caRegs.I2CISRC.bit.INTCODE & 0x7;
switch(IntSource)
{
case I2C_NO_ISRC: // = 0
case I2C_ARB_ISRC: // = 1 Arbitration lost.
case I2C_NACK_ISRC: // = 2 No acknowledgment.
case I2C_ARDY_ISRC: // = 3 Register access ready.
break;
case I2C_RX_ISRC: // = 4 Receive ready.
if(RxIndex == 0 && g_DataReady)
Device.Status.bit.OverrunError = 1;
else
Device.Status.bit.OverrunError = 0;
if(g_DataReady || Device.Status.bit.OverrunError)
{
RxIndex = 0xFFFF;
Flush = I2caRegs.I2CDRR;
break;
}
RxBuff[RxIndex] = I2caRegs.I2CDRR;
// Rx Cmd
if(RxIndex == 0)
{
if(RX_CMD < (DIM(CmdSize)))
{
RxDataSize = CmdSize[RX_CMD];
CmdIncomplete = BIT_CMD_ERROR;
}
else
RxDataSize = 0;
}
if(RxIndex <= (RX_BUFF_SIZE-1))
RxIndex++;
if(RxIndex >= RxDataSize)
{
g_DataReady = BIT_BUSY;
CmdIncomplete = 0;
I2caRegs.I2CDXR = 0;
}
break;
case I2C_TX_ISRC: // =5 Transmit Ready.
if(TxIndex < TX_BUFF_SIZE)
{
I2caRegs.I2CDXR = TxBuff[TxIndex];
TxIndex++;
}
else
{
I2caRegs.I2CDXR = 0;
}
break;
case I2C_SCD_ISRC: // =6 Stop condition detected.
I2caRegs.I2CDXR = 0; // first byte read by the host is always 0.
break;
case I2C_AAS_ISRC: // =7 Addressed as Slave.
if(I2caRegs.I2CSTR.bit.SDIR) // slave transmitter or receiver ?
{
PUT_U32(TxBuff, TX_STATUS, 0xAABBCCDD);
I2caRegs.I2CDXR = TxBuff[0]; // First byte sent
TxIndex = 1;
}
else
{
RxIndex = 0;
}
break;
default:
asm(" ESTOP0"); // Halt on invalid number.
}
// Enable further I2C (PIE Group 8) interrupts
PieCtrlRegs.PIEACK.all = PIEACK_GROUP8;
}
Thank you for your inputs.
Pat