牛卧堂MCU技术交流
标题:
[求助]M451的I2C通信问题
[打印本页]
作者:
cpf1232008
时间:
2016-7-8 10:34
标题:
[求助]M451的I2C通信问题
使用芯片:
M452LG6AE
环境:通过I2C去读取电池管理芯片OZ9313,
OZ9313
支持SMBus。上拉电阻原为4.7K,因clock波形不好(tr时间长),后面改到1.2K。
故障现象:
M452芯片启动后能够正常通信获取电池信息,但是过一段时间(几小时)后就读取不到芯片上的信息,调试代码发现I2C读取超时,示波器抓取波形为SDA一直为高电平,SCL一直有正常的clock波形(波形还挺好~),
更改代码尝试
在通信失败后
调用I2C_STOP(I2C0)(代码如下),会卡死在while循环中,
static __INLINE void I2C_STOP(I2C_T *i2c)
{
(i2c)->CTL |= (I2C_CTL_SI_Msk | I2C_CTL_STO_Msk);
while(i2c->CTL & I2C_CTL_STO_Msk);
}
更改代码在通信失败后定时重新初始化I2C中断,结果还是读取超时,获取不到信息。
作者:
cpf1232008
时间:
2016-7-22 09:53
自己回复一下吧,
经过调试,楼上问题确认是死锁问题,因电池侧不会掉电,总线busy,导致m451侧发送stop/软重启都无效。经过调试并优化后。i2c配置增加开启smbus的相关配置,自动ack等等。稳定性好了很多,不过偶尔还是会出现上一楼的死锁问题(主要是因充电器干扰,正常情况下i2c还是很稳定的),目前已添加通信失败后更改配置SCL为GPIO OUT,发送9个脉冲进行解锁。目前正进行烤机测试中,有结果再反馈~
PS:引用别人回复:
对于一个完整的I2C程序,起码应该具有三个标志
就是NoACK(无应答),Busy(器件忙)和BusFault(总线错误)。
1.当STA+SLA+R/W后,如果9th BIT=1,则置位NoACK,表示被寻址的I2C器件不存在。
2.当正处于访问一个I2C设备的过程中,程序应置位Busy。即STA和STO之间Busy=1.
3.如果初始化I2C(释放总线)后,SDA=0和(或)SCL=0,程序应置位BusFault。
根据以上三个条件合理控制程序的流程,才是一个完整的I2C程序。
当出现BusFault标志时,如果只有SDA=0,问题可能出现在主接收模式下的从发送数据等于0,这是可以通过附加SCL脉冲解决。如果不能解锁,应检查其它原因;如果只有SCL=0,应检查总线是否是多主系统。
当然以上条件是建立在硬件设计没有错误,器件没有损坏前提下进行的。
作者:
cpf1232008
时间:
2016-8-5 14:32
已测试一周,目前无死机现象出现,验证恢复状态良好,这个问题算解决了。。提供代码如下:
void count_delay_us(uint32_t time_us)
{
uint32_t i;
uint32_t cons = 17;
for(i=0; i<time_us; i++)
{
while(cons--) ;
cons = 22;
}
return;
}
void I2C_recover(void)
{
int i;
//first: changed the scl to gpio out
SYS->GPA_MFPL &= ~(SYS_GPA_MFPL_PA3MFP_Msk | SYS_GPA_MFPL_PA2MFP_Msk);
SYS->GPA_MFPL |= (SYS_GPA_MFPL_PA3MFP_GPIO | SYS_GPA_MFPL_PA2MFP_GPIO);
delayms(1);
GPIO_SetMode(PA, BIT3, GPIO_MODE_OUTPUT);
PA3=0;
//second: send nine clock
delayms(1);
for(i=0; i<10; i++)
//while(1)
{
PA3=1;
count_delay_us(10);
PA3=0;
count_delay_us(10);
}
//PA3=1;
delayms(1);
return;
}
int I2C_Conifiguration(void)
{
//I2C_recover();
SYS->GPA_MFPL &= ~(SYS_GPA_MFPL_PA3MFP_Msk | SYS_GPA_MFPL_PA2MFP_Msk);
SYS->GPA_MFPL |= (SYS_GPA_MFPL_PA3MFP_I2C0_SCL | SYS_GPA_MFPL_PA2MFP_I2C0_SDA);
/* Reset I2C0 */
//SYS_ResetModule(I2C0_RST);
/* Open I2C module and set bus clock */
I2C_Open(I2C0, 80000);
/* Enable I2C interrupt */
I2C_EnableInt(I2C0);
NVIC_EnableIRQ(I2C0_IRQn);
I2C_SMBusOpen(I2C0, I2C_SMBH_ENABLE);
I2C_SMBusPECTxEnable(I2C0, I2C_PECTX_DISABLE);
//I2C_SMBUS_ACK_MANUAL(I2C0);
I2C_SMBUS_ACK_AUTO(I2C0);
//SYS_ResetModule(I2C0_RST);
return 0;
}
void I2C_deinit(void)
{
/* Disable I2C0 interrupt and clear corresponding NVIC bit */
I2C_DisableInt(I2C0);
NVIC_DisableIRQ(I2C0_IRQn);
/* Disable I2C0 and close I2C0 clock */
I2C_Close(I2C0);
//CLK_DisableModuleClock(I2C0_MODULE);
//i2c all use ,donot close its clock
}
复制代码
欢迎光临 牛卧堂MCU技术交流 (http://nuvoton-mcu.com/)
Powered by Discuz! X3.2