Other Parts Discussed in Thread: MSP430FR2355
Tool/software:
Hi,
We are encountering an issue where the I2C clock signal on the AM2434 gets stuck low and cannot recover. On this I2C bus, the AM2434 is the master, and there is one MSP430FR2355 and one EEPROM as slaves. The I2C clock signal gets stuck low when the AM2434 is writing boot data to the MSP430FR2355 in boot mode during EFT noise interference.
The diagram below shows that after the EFT noise generator interrupts the transmission, the program calls the I2C_FreeBus() function (modified from the SDK's I2C_recoverBus() function) to try to recover the I2C bus (at the point labeled "Gen 9 clocks to recover bus"), and then attempts to resend the packet. However, as shown in the diagram, when resending reaches the 7th bit of the Length field, both SDA and SCL get stuck in a low state.
Subsequently, due to continuous transmission failures, the program calls the I2C_FreeBus() function again, but this time SCL does not generate the expected 9 clocks and remains low (as shown in the diagram below). This situation was retried 10 times, and the results were the same as shown in the diagram. The SDA line transitions to a high state twice, which we suspect is the result of calling the I2C_CtrlInit() function.
Below is our I2C_FreeBus() function, which is modified from the SDK's I2C_recoverBus function.
void I2C_FreeBus( I2C_Handle handle ) { I2C_Object *pObject; Uint32 SysTest, i; pObject = ( I2C_Object* )handle->object; /* Acquire the lock for this particular I2C handle */ ( void )SemaphoreP_pend( &pObject->mutex, SystemP_WAIT_FOREVER ); /* Check if SDA or SCL is stuck low based on the SYSTEST. * If SCL is stuck low we reset the IP. * If SDA is stuck low drive 9 clock pulses on SCL and check if the * target has released the SDA. If not we reset the I2C controller. */ SysTest = I2CControllerGetSysTest( pObject->baseAddr ); I2C_CtrlInit( handle ); /* SDA output high */ /* generate 9 clk pulses on SCL */ /* switch to system test mode */ HW_SET_FIELD32( SysTest, I2C_SYSTEST_ST_EN, I2C_SYSTEST_ST_EN_ENABLE ); HW_SET_FIELD32( SysTest, I2C_SYSTEST_TMODE, I2C_SYSTEST_TMODE_LOOPBACK ); // HW_SET_FIELD32( SysTest, I2C_SYSTEST_SDA_O, I2C_SYSTEST_SDA_O_SDAOH ); I2CControllerSetSysTest( pObject->baseAddr, SysTest ); for( i = 0; i < 9; i++ ) { HW_SET_FIELD32( SysTest, I2C_SYSTEST_SCL_O, I2C_SYSTEST_SCL_O_SCLOH ); I2CControllerSetSysTest( pObject->baseAddr, SysTest ); Delay_us( 5 ); HW_SET_FIELD32( SysTest, I2C_SYSTEST_SCL_O, I2C_SYSTEST_SCL_O_SCLOL ); I2CControllerSetSysTest( pObject->baseAddr, SysTest ); Delay_us( 5 ); } /* Switch back to functional mode */ HW_SET_FIELD32( SysTest, I2C_SYSTEST_ST_EN, I2C_SYSTEST_ST_EN_DISABLE ); HW_SET_FIELD32( SysTest, I2C_SYSTEST_TMODE, I2C_SYSTEST_TMODE_FUNCTIONAL ); I2CControllerSetSysTest( pObject->baseAddr, SysTest ); /* Now check if the SDA is releases. If its still stuck low, * There is nothing that can be done. We still try to reset our IP. */ SysTest = I2CControllerGetSysTest( pObject->baseAddr ); if ((SysTest & I2C_SYSTEST_SDA_I_FUNC_MASK) == 0U) { I2C_CtrlInit( handle ); } /* Release the lock for this particular I2C handle */ ( void )SemaphoreP_post( &pObject->mutex ); }
And we also modify I2C_CtrlInit() from SDK as below.
void I2C_CtrlInit( I2C_Handle handle ) { I2C_HwAttrs const *pHwAttrs; I2C_Object *pObject; Uint32 Delay = 50U; Uint32 OutputClk; Uint32 InternalClk; Uint32 RegVal; /* Get the pointer to hwAttrs */ pObject = ( I2C_Object* )handle->object; pHwAttrs = ( I2C_HwAttrs const* )handle->hwAttrs; /* Put i2c in reset/disabled state */ I2CControllerDisable( pObject->baseAddr ); /* Do a software reset */ I2CSoftReset( pObject->baseAddr ); /* Enable i2c module */ I2CControllerEnable( pObject->baseAddr ); /* Wait for the reset to get complete -- timeout = 50ms */ while( ( ( HW_RD_REG32( pObject->baseAddr + I2C_SYSS ) & I2C_SYSS_RDONE_MASK ) == 0 ) && ( Delay != 0 ) ) { Delay--; Delay_us( 1000 ); } /* Put i2c in reset/disabled state */ I2CControllerDisable( pObject->baseAddr ); /* Configure i2c bus speed*/ switch( pObject->i2cParams.bitRate ) { case I2C_100KHZ: { OutputClk = 100000U; InternalClk = I2C_MODULE_INTERNAL_CLK_4MHZ; break; } case I2C_400KHZ: { OutputClk = 400000U; InternalClk = I2C_MODULE_INTERNAL_CLK_12MHZ; break; } case I2C_1P0MHZ: { OutputClk = 3400000U; InternalClk = I2C_MODULE_INTERNAL_CLK_12MHZ; break; } default: { /* Default case force it to 100 KHZ bit rate */ OutputClk = 100000U; InternalClk = I2C_MODULE_INTERNAL_CLK_4MHZ; } break; } /* Set the I2C configuration */ I2CControllerInitExpClk( pObject->baseAddr, pHwAttrs->funcClk, InternalClk, OutputClk ); /* Configure I2C_SYSC params * Disable auto idle mode * Both OCP and systen clock cut off * Wake up mechanism disabled * No idle mode selected */ RegVal = I2C_AUTOIDLE_DISABLE | I2C_CUT_OFF_BOTH_CLK | I2C_ENAWAKEUP_DISABLE | I2C_NO_IDLE_MODE; I2CSyscInit( pObject->baseAddr, RegVal ); /* Configure I2C_CON params */ RegVal = I2C_OPMODE_FAST_STAND_MODE | I2C_NORMAL_MODE; I2CConfig( pObject->baseAddr, RegVal ); /* Take the I2C module out of reset: */ I2CControllerEnable( pObject->baseAddr ); /* Enable free run mode */ I2CControllerEnableFreeRun( pObject->baseAddr ); /*Clear status register */ I2CControllerIntClearEx( pObject->baseAddr, I2C_INT_ALL ); }
We would like to ask if there is any way to get the I2C SCL signal to recover from a low state to a high state and successfully generate clock signals to resolve the bus hang issue.
Thank you for your assistance.