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.

Tiva c TM4C1294 + I2C Expander (PCA9056)

Hi,


My developing environments:

TM4C1294 custom board, FreeRTOS v7.1.1, LWIP 1.4.1, CCS 6.0.1

I am working on detecting fail bits from I2C expander, and there is only one Master which is MCU.

I thought it worked well since I could read the right values(4 bytes) from the expander. However, it suddenly stops working after running 2~3 hours.(both SDA and SCL go high).

The task,I2CTask in my project, is executed in a regular time basis and read values.

Here is my I2C init funciton:

void i2c_init(void)
{
   // The I2C5 peripheral must be enabled before use.
   ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C5);
   while(!(ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_I2C5)));
   ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
   while(!(ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB)));

   ROM_GPIOPinConfigure(GPIO_PB0_I2C5SCL);
   ROM_GPIOPinConfigure(GPIO_PB1_I2C5SDA);

   // Select the I2C function for these pins.  This function will also
   // configure the GPIO pins for I2C operation, setting them to
   // open-drain operation with weak pull-ups.
   ROM_GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_0);
   ROM_GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_1 );

   // Initialize Master and Slave
   // true: 400kbps I2C clock (false: 100kbps)
   ROM_I2CMasterInitExpClk(I2C5_BASE, g_ui32SysClock, false);


}

Also here is read function:

unsigned long read32_PCA9506()
{
   int err[2]; 					//used for debugging
   int i,loopdelay;						// delay loop variable
   unsigned char byte[4];		// 4 byte array for retrieved bytes holding
//   unsigned char byte1,byte2,byte3,byte4 ;		// holders for the 4 retrieved bytes
   unsigned long return_fails = 0;		// 32bit return holder of assembled bytes

// Program the SLAVE address into registers, and select a WRITE operation
// for I2C bus
   ROM_I2CMasterSlaveAddrSet(I2C5_BASE, PCA9506_ADDR, I2C_SEND);//PCA9506_ADDR:0x20

// Note: The I^2C bus requires us to transmit the ' START ' condition
// 	     from the Micro to the PCA9506. The next byte transfered must be the
//		 address of the slave device. A0,A1,A2 of PCA9506 are tied low (000).
//  	 The address is the 7 MSB of a byte, with the LSB being the R/W selection bit.
//		 For our configuration, 0x20 is the address of the PCA9506
// 		 The address is loaded into Slave address register, then the register
//		 address byte is loaded into a write register with the type of 'START'
//		 configuration we want to use....  START toggle is sent, then slave address
//		 goes out automatically, then register to write too is transmitted.

   // Load Slave address, select type of START transmission, and write
   // register address to OUTPUT write register for I2C0

   ROM_I2CMasterDataPut( I2C5_BASE, COMMAND_REG);//COMMAND_REG: 0x80

// Transmit START, slave address,  -- NO STOP sent
   ROM_I2CMasterControl( I2C5_BASE, I2C_MASTER_CMD_BURST_SEND_START );

   while (!(ROM_I2CMasterBusy( I2C5_BASE ))) {}		//sometime does not catch flag,so put this code
   while (ROM_I2CMasterBusy( I2C5_BASE )) {}	// wait for transmission to finish


   err[0] = ROM_I2CMasterErr(I2C5_BASE);	// read the error status of last transmission and

   if ( err[0] != I2C_MASTER_ERR_NONE )
   {
	   UARTprintf("error[0] = %x\n",err[0] );
	   // error detected during START BURST MODE, SEND STOP COMMAND
	   ROM_I2CMasterControl( I2C5_BASE, I2C_MASTER_CMD_BURST_SEND_ERROR_STOP );
//	   ROM_I2CMasterIntClear(I2C5_BASE);

	   I2C5_error_count = (I2C5_error_count + 1);		// increment the detected error counter for I2C0
	   return_fails = 0;
	   return (unsigned long) return_fails;					// return from READ function, reporting no
												   // FAIL bit status, but with error count increased
   }

   ROM_I2CMasterSlaveAddrSet( I2C5_BASE, PCA9506_ADDR, I2C_RECV );
   //repeat start condition followed by receive operation with data negative acknowledge
   //master goes to Master receive state
   ROM_I2CMasterControl( I2C5_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START  );

   for ( i=0; i<4; i++)
   {


	   while (!ROM_I2CMasterBusy( I2C5_BASE ));
	   while (ROM_I2CMasterBusy( I2C5_BASE )){}

	   // BYTE 1 - IO-O HAS NOW BEEN READ, SO RETRIEVE THE VALUE AND STORE IT IN return
	   byte[i] = ROM_I2CMasterDataGet( I2C5_BASE );

	   UARTprintf("Data Get: byte[%d] == %x\n", i, byte[i]);

	   ROM_I2CMasterControl(I2C5_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT);

	   err[1] = ROM_I2CMasterErr(I2C5_BASE);
	   if ( err[1] != I2C_MASTER_ERR_NONE )
	   {
		   UARTprintf("error[1] = %x\n",err[2] );
		   // error detected during START BURST MODE, SEND STOP COMMAND

		   ROM_I2CMasterControl( I2C5_BASE, I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP );
//		   ROM_I2CMasterIntClear(I2C5_BASE);

		   I2C5_error_count = (I2C5_error_count + 1);		// increment the detected error counter for I2C5
		   return_fails = 0;
		   return (unsigned long) return_fails;					// return from READ function, reporting no
												   // FAIL bit status, but with error count increased
	   }

	   for(loopdelay=0; loopdelay<1000; loopdelay++);//8.33 uSec

   }//end for


   return_fails = (byte[3] << 24) | (byte[2] << 16) | (byte[1] << 8) | byte[0];	// assemble 32bit FAIL register

   // all 4 registers have now been read, so transmit the STOP signal to IC2 slave
   // transmit a receive stop condition - Current State is receive - write 0x04 to I2CMCS register
   // with NO acknowledge to put I2C bus into IDLE state

   ROM_I2CMasterControl( I2C5_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH  ); // transmit STOP only to free up bus


   I2C5_error_count = 0;			// if we reach this point, we have successfully completed
   	   	   	   	   	   	   	   	    // a read process of 32 bits ( 4 bytes ) from the PCA9506 chip
   for(loopdelay=0; loopdelay<1000; loopdelay++);

   return (unsigned long) return_fails;
}

I have not found what is wrong with this.

As you see this is the polling mode, so may be better to use interrupt mode? if then can you give a tip to use interrupt mode in my situation like sending and receiving 4 bytes?

Thanks,

Jin

  • Jin Seo said:
    ...worked well ... read the right (4 bytes) from the expander. However, it suddenly stops working after running 2~3 hours

    "Working well" - by running for 2-3 hours - yet w/out describing the frequency of those I2C transactions - may not (quite) qualify as, "well working."

    Many more facts should be introduced into evidence - don't you agree?   (and their lack may explain why this post has just "sat.")

    • Is your I2C I/O expander resident upon an "official" board or home-brew?   If your build - have all connections been exhaustively checked & probed?
    • What is the separation and wiring/cabling between the extender and your MCU board?   Is the separation "reasonable" - does the connection avoid noisy signals?
    • Is the I2C expander powered adequately - and at all times?
    • Might high currents or high speed data prove the cause of your disconnect?
    • Might the external circuit - which your expander monitors - create the condition which "breaks" your I2C operation?  (i.e. "glitches" your I2C bus or the expander)

    There exist fairly standard methods to "recover" from a "broken" I2C connection.   Have you employed these?

    Moving from polling to interrupt mode - usually - but not always - will not identify nor cure your offending condition(s).   That identification (and correction) would seem your (more correct) first order of business...

  • Hi,

    The I2C expander resides on another pcb that connects to the custom MCU through the header(8x2), and there are no connection problems.


    Also, the expander runs at 100 kbps and both SDA and SCL are within around 3.3v and acceptable noise/glitch

    Sorry I don't have a proper size of USB flash or cable now. the above wave form describes SDA/SCL of bank 4(3rd bytes from expander)

    The reason why I think of changing from polling to interrupts mode is that other tasks with different priority/schedule run concurrently with I2C task(now set up for the lowest priority) and if I2CMasterBusy() takes too long to detect of transmission complete sometimes then it might cause problems.

    Right now the expander on the separate from MCU board does not have a reset connected with MCU. Eventually it will be connected with MCU but right now I am focusing on what caused this issue.

    Thank you for replying to me.

  • Hello Jin,

    When the IO expander stops responding (SDA and SCL going High), what does the next I2C Frame on the scope show? I am trying to check Time Event Failure + 1 to see what went wrong at the Failure Time Event. Also the acceptable glitch may not be acceptable to the I2C Master Controller. Did you try and use the Glitch Filter to see if the issue happens?

    Regards
    Amit
  • Hi Amit,

    I have not applied "Glitch Filter" and I don't know what it does now. What I did about glitch was kept monitoring SDA/SCL using scopes to see if glitches took place, and I did not see any glitches.

    Sorry about my unclear explanation of "acceptable glitch"

    Thanks,
    Jin
  • Hello Jin,

    A glitch may be few 10's of ns wide during 2-3 hrs of testing, I doubt visual check on scope will show that (unless the scope is configured to catch such an event). I would still advise, to use the glitch filter and then we can see what is the effect of the same. Also my RFI for what happens on the next to the failing I2C Frame request, remains unanswered!!!!

    Regards
    Amit
  • Hi Amit,

    I think you are talking about the below codes for "glitch filter", so I added it on I2C set up function.

    
    
       // 8.33ns at 120Hz
       // for the standard mode(100kbps), glitch suppression of 50nsec woulbe be
       // 6 clocks --> chose 8
       ROM_I2CMasterGlitchFilterConfigSet(I2C5_BASE,I2C_MASTER_GLITCH_FILTER_8);

    Thanks,

    Jin

  • Hello Jin,

    Yes, that is correct function to use for TM4C129. Do make sure that after using the same the Register for Glitch Filter shows the correct setting.

    Regards
    Amit