主题中讨论的其他器件:AM2434、
工具与软件:
您好!
我们会遇到 I2C 时钟信号始终处于低电平无法恢复的问题。 在此 I2C 总线上、AM2434是主器件、有一个 MSP430FR2355 作为从器件。 当 AM2434 在 EFT 噪声干扰期间以引导模式将程序数据写入 MSP430FR2355时、I2C 时钟信号会卡在低电平。
下图显示、在 EFT 噪声发生器中断传输后、AM2434调用 I2C_FreeBus ()函数(根据 SDK 的 I2C_recoverBus ()函数进行修改)来尝试恢复 I2C 总线(在标记为"Gen 9 Clocks to Recover bus"的点上)、然后尝试重新发送数据包。 但是、如图所示、当重新发送达到长度字段第一个字节的第7位时、SDA 和 SCL 都卡在低电平状态。
随后,由于连续传输失败,程序再次调用 I2C_FreeBus()函数,但这次 SCL 不会产生预期的9个时钟并保持低电平(如下图所示)。 该情况已重试10次、结果与图中所示相同。 SDA 线转换到两次高电平状态,我们怀疑这是调用 I2C_CtrlInit ()函数的结果。
下面是 AM2434中的 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 修改 AM2434的 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)持续处于低电平时、我们尝试 使用硬件方法对 MSP430FR2355进行复位。 此方法可手动触发硬件复位、以恢复器件并恢复正常的 I2C 通信。
在复位 MSP430FR2355后、我们观察到 SCL 引脚返回到高电平状态、如下图所示:
接下来、我们测试了 MSP430FR2355 进入 APP 模式、并且引入 EFT 噪声以强制 I2C 时钟(SCL)线路保持低电平的情况。 但是、在我们的 MSP430FR2355应用中、我们将配置UCB0CTLW1 = 0x03
为启用时钟低电平超时功能。 当UCCLTOIFG
检测到该标志时、我们将复位 I2C 模块。
因此、I2C 时钟线在大约44ms 后成功恢复到高电平状态、如下图所示。
我想问是否有配置的方法 MSP430FR2355 BSL 当检测到时钟(SCL)在一段时间内卡在低电平时、自动复位 I2C 模块。 这是为了防止在编程过程中由噪声干扰引起的编程失败。
非常感谢您提供任何指导!
此致、
Yenting