如题,使用本芯片小批做了一批货,在I2C1上(PA14,PA15),SCK/SDA均通过2.2k电阻上拉,外设为RX8025T时钟芯片。
现象为:部分设备在上电后,SCK/SDA均无波形输出,通过拉低2脚RESET到地复位,故障依旧,短接3.3V供电电源到地,实现硬复位,故障恢复
概率大约为1%
解决办法:通过IO模拟I2C时序解决,放弃使用硬件I2C。
希望帮到大家。
离线
附上IO模拟I2C的程序给大家参考:
#define SCL_0 GPIO_ClrBit(GPIO_RTC_SCL_PORT, GPIO_RTC_SCL_PIN)//SCL
#define SCL_1 GPIO_SetBit(GPIO_RTC_SCL_PORT, GPIO_RTC_SCL_PIN)
#define SDA_0 GPIO_ClrBit(GPIO_RTC_SDA_PORT, GPIO_RTC_SDA_PIN)//SDA
#define SDA_1 GPIO_SetBit(GPIO_RTC_SDA_PORT, GPIO_RTC_SDA_PIN)
#define SDA_SET_IN GPIO_Init(GPIO_RTC_SDA_PORT, GPIO_RTC_SDA_PIN, 0, 0, 0, 0)//设置成输入
#define SDA_SET_OUT GPIO_Init(GPIO_RTC_SDA_PORT, GPIO_RTC_SDA_PIN, 1, 1, 0, 0)//设置成输出
#define SDA_VALUE GPIO_GetBit(GPIO_RTC_SDA_PORT, GPIO_RTC_SDA_PIN)
#define ts 15
#define th 15
#define tcycle 30 // half the cycle
/* 用于短暂的延时,在xxMHz的频率下延时时长yyus */
void __delay_cycles(unsigned int z)
{
volatile unsigned int y;
for(y=z; y>0; y--);
}
/*********************************************************
函数名称:I2C_IO_Start()
函数功能:产生一个起始条件
入口参数:无
出口参数:无
备注:
**********************************************************/
static void I2C_IO_Start(void)
{
SCL_0;
__delay_cycles(ts);
SDA_1;
SCL_1;
__delay_cycles(th);
SDA_0;
__delay_cycles(10);
SCL_0;
}
/*********************************************************
函数名称:I2C_IO_Stop()
函数功能:产生一个停止条件
入口参数:无
出口参数:无
备注:
**********************************************************/
static void I2C_IO_Stop(void)
{
__delay_cycles(th);
SDA_0;
__delay_cycles(ts);
SCL_1;
__delay_cycles(10);
SDA_1;
__delay_cycles(5);
}
/*********************************************************
函数名称:I2C_IO_Ack()
函数功能:产生一个ACK
入口参数:无
出口参数:无
备注:
**********************************************************/
static void I2C_IO_Ack(void)
{
SDA_0;
__delay_cycles(ts);
SCL_1;
__delay_cycles(th);
SCL_0;
__delay_cycles(ts);
SDA_1;
}
/*********************************************************
函数名称:I2C_IO_Nack()
函数功能:产生一个NACK
入口参数:无
出口参数:无
备注:
**********************************************************/
static void I2C_IO_Nack(void)
{
SDA_1;
__delay_cycles(ts);
SCL_1;
__delay_cycles(th);
SCL_0;
__delay_cycles(ts);
SDA_0;
}
/*********************************************************
函数名称:I2C_IO_WriteOneByte()
函数功能:写操作 一个字节
入口参数:byte 待写字节
出口参数:1 子器件无应答; 0 完成写一个字节。
备注:
**********************************************************/
static U_CHAR I2C_IO_WriteOneByte(U_CHAR byte)
{
U_CHAR i;
for (i = 0; i < 8; i++) {
SCL_0;
__delay_cycles(ts);
if((byte >> 7) & 0x01)
SDA_1;
else
SDA_0;
byte <<= 1;
SCL_1;
__delay_cycles(tcycle);
}
SCL_0;
SDA_0;
__delay_cycles(ts);
SDA_SET_IN;//SDA 输入,用来检测子器件ACK
SCL_1;
__delay_cycles(th);
i = 0;
while (SDA_VALUE) { //8025T ACK为0
if (++i > 12) {
SCL_0;
SDA_SET_OUT;//SDA作为输出
I2C_IO_Stop();
return 1; //NACK return
}
}
SDA_SET_OUT;//SDA作为输出
SCL_0;
SDA_0;
__delay_cycles(ts);
return 0;
}
/*********************************************************
函数名称:I2C_IO_Write()
函数功能:写操作 iic时序写多个字节
入口参数:registerAddress 器件地址;
WriteBuf 待写数据缓存
len 数据长度(字节数)
出口参数:1 子器件无应答; 0 写操作完成。
备注:
**********************************************************/
U_CHAR I2C_IO_Write(U_CHAR registerAddress, U_CHAR *WriteBuf, U_CHAR len)
{
U_CHAR temp;
I2C_IO_Start();
if (I2C_IO_WriteOneByte(RX8025T_WRITE_ADDR))//写器件地址
return 1;
if (I2C_IO_WriteOneByte(registerAddress))//写寄存器地址
return 1;
while (len--) {
temp = *WriteBuf++;//寄存器地址自动增加,只需写数据
if (I2C_IO_WriteOneByte(temp))//写数据
return 1;
}
I2C_IO_Stop();
return 0;
}
/*********************************************************
函数名称:I2C_IO_ReadOneByte()
函数功能:读操作 一个字节
入口参数:读数据存放地址
出口参数:无
备注:
**********************************************************/
static void I2C_IO_ReadOneByte(U_CHAR *byte)
{
U_CHAR i, retc = 0;
SCL_0;
SDA_SET_OUT;
SDA_1;
SDA_SET_IN;//SDA 输入
for (i = 0; i < 8; i++) {
SCL_1;
__delay_cycles(th);
retc <<= 1;
if (SDA_VALUE)
retc |= 1;
SCL_0;
__delay_cycles(ts);
}
SDA_SET_OUT;
SDA_0;
SCL_0;
*byte = retc;
}
/*********************************************************
函数名称:I2C_IO_Read()
函数功能:读操作
入口参数:registerAddress 器件地址;
ReadBuf 读数据缓存
len 数据长度(字节数)
出口参数:无
备注: 最后一个字节发送NACK,子器件准备接收停止条件
**********************************************************/
U_CHAR I2C_IO_Read(U_CHAR registerAddress, U_CHAR *ReadBuf, U_CHAR len)
{
I2C_IO_Start();
if (I2C_IO_WriteOneByte(RX8025T_WRITE_ADDR))//写器件地址
return 1;
if (I2C_IO_WriteOneByte(registerAddress))//写寄存器地址
return 1;
SDA_SET_OUT;//SDA作为输出
I2C_IO_Start();//重新发送起始条件【Sr】
if (I2C_IO_WriteOneByte(RX8025T_READ_ADDR))//写器件地址(读模式)
return 1;
while (len--) {//读数据
I2C_IO_ReadOneByte(ReadBuf);
ReadBuf++;
if (len == 0)
I2C_IO_Nack();
else
I2C_IO_Ack();
}
I2C_IO_Stop();
return 0;
}
离线