This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

400 kHz I²C problem: INTCODE=0 or XRDY interrupt missing

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

 

  • Since I have been working on that problem for the last days, I have more information to provide as of today.

    I have made a simple test case program with I²C communication protocol only, and no bug was happening, the I²C is properly working at 400 kHz with my code.

    If I add the timer0 interrupt, the bug occurs and the frequency of errors is proportional to the duty cycle of the timer0 interrupt.  Since I can trig the oscilloscope when the bug occurs, I can see that the bug occurs when the timer0 interrupt routine is executed exactly during the last bit of the address byte  of the slave-transmitter response (the 9th bit, being the ACK).  This makes the I²C interrupt to trig on the AAS interrupt but to "forget" the first XRDY interrupt.  I tried disabling interrupts when executing the timer0 isr or when executing the I²C  isr but it doesn't change anything.

    Anyone could provide information or advices on this ?

    Pat

     

  • More information...  if it could help to get some clues.

    I have made the I²C top priority using the software interrupt priorization.  I am now also nesting the interrupts, timer0 and I²C.  I have also made my i2c_isr much shorter, around 300 to 700 ns.  I still got the error around 0.002% of the time (1 out of 50000 transactions).  Still the same error, as it seems like XRDY interrupt is treated before AAS interrupt, with the first answer byte being a dummy byte and the true answer being shifted one byte, beginning at the second Tx byte.

    Again, if I make the timer0_isr to happend 10 times more often, I get 10 times the number of errors, even if the timer0_isr is lower priority and nested...

    I can't figure out how I could make it error less.  It looks like at this frequency, the I²C is just now working well.  Anyone using the I²C on F280x and can status that it is going perfeclty ?

    Anyone have any clue ?

  • Hello Patrick,

    What is the your SYSCLKOUT?

     

    Best regards,

    Filipe Teixeira

     

    www.kulzertec.com

  • Hello Filipe

    I am running at 100 MHz.

    Pat

  • Hello Pat,

    I am using the F28069, this one only goes up to 80MHz. In the F28069 you have to specify the clock divider for the i2C module so it is between 7 and 12MHz, is this also a issue in the F2809?

    Best regards,

    Filipe Teixeira

  • Yes, it is, and I did it.

        I2caRegs.I2CPSC.all = 9;        // Prescaler - need 7-12 Mhz on module clk  (100 MHz / (9+1)) = 10 MHz
        I2caRegs.I2CCLKL = 10;         //
        I2caRegs.I2CCLKH = 5;           //

    Regards

    Pat

  • Finally, I found a workaround for this problem.

    It looks like when the delay between AAS and XRDY interrupts is too short, there is a problem with the treatment of the second one.  I tried software interrupts priorisation and interrupt nesting but it didn't solved the problem completely.  Finally, I have made my code to interrupt only on RRDY,  XRDY and SCD and not anymore on AAS.  It works well.

    Thanks to pointers.

    Pat