主题中讨论的其他器件: MSP430FR2355
工具与软件:
您好!
AM2434上的 I2C 时钟信号卡在低电平无法恢复时会遇到问题。 在此 I2C 总线上、AM2434是主器件、而有一个 MSP430FR2355和一个 EEPROM 作为从器件。 当 AM2434在 EFT 噪声干扰期间以引导模式向 MSP430FR2355写入引导数据时、I2C 时钟信号会卡在低电平。
下图显示了 EFT 噪声发生器中断传输后,程序调用 I2C_FreeBus()函数(修改自 SDK 的 I2C_recoverBus ()函数)来尝试恢复 I2C 总线(在标记为"Gen 9 Clocks to Recover bus"的点),然后尝试重新发送数据包。 但是、如图所示、当重新发送达到长度字段的第7位时、SDA 和 SCL 都卡在低电平状态。 
随后,由于连续传输失败,程序再次调用 I2C_FreeBus()函数,但这次 SCL 不会产生预期的9个时钟并保持低电平(如下图所示)。 该情况已重试10次、结果与图中所示相同。 SDA 线转换到两次高电平状态,我们怀疑这是调用 I2C_CtrlInit ()函数的结果。 
下面是我们的 I2C_FreeBus()函数、该函数根据 SDK 的 I2C_recoverBus 函数进行了修改。
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 );
}
并且我们还 通过 SDK 修改 I2C_CtrlInit ()、如下所示。
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 );
}我们想问、是否有任何方法可以使 I2C SCL 信号从低电平状态恢复到高电平状态并成功生成时钟信号来解决总线挂起问题。
感谢您的帮助。

