Other Parts Discussed in Thread: AM2434,
Tool/software:
Hi,
We are encountering an issue where the I2C clock signal stuck low and cannot recover. On this I2C bus, the AM2434 is the master, and there is one MSP430FR2355 as slaves. The I2C clock signal gets stuck low when the AM2434 is writing program data to the MSP430FR2355 in boot mode during EFT noise interference.
The diagram below shows that after the EFT noise generator interrupts the transmission, AM2434 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 first byte of 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 in AM2434, 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() of AM2434 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 ); }
In further testing, when the I2C clock (SCL) is stuck low, We attempted to reset the MSP430FR2355 using a hardware method. This approach manually triggers a hardware reset to recover the device and restore normal I2C communication.
After resetting the MSP430FR2355, we observed that the SCL pin returned to the high state, as shown in the image below:
Next, we tested the scenario where the MSP430FR2355 enters APP mode, and EFT noise is introduced to force the I2C clock (SCL) line to remain stuck low. However, in our MSP430FR2355 application, we configured UCB0CTLW1 = 0x03
to enable the Clock Low Timeout feature. When the UCCLTOIFG
flag is detected, we reset the I2C module.
As a result, the I2C clock line successfully recovers to a high state after approximately 44 ms, as shown in the following figure.
I would like to ask if there is a way to configure the MSP430FR2355 BSL to automatically reset the I2C module when the clock (SCL) is detected to be stuck low for a certain period of time. This is to prevent programming failures caused by noise interference during the programming process.
Any guidance would be greatly appreciated!
Regards,
YenTing