STM32F103ZET6的
开发板,MCU作为主I2C,用I2C硬件轮询的方式读写一个I2C从设备。板子启动后,通过一个按钮开关来打开或关闭I2C写数据和读数据,在开始的第一次写数据时会偶现出现BUSY超时错误,后面持续数百万次的写和读操作结果都是正常的,而且这个错误也不是必现,是随机出现的,大概有50%多的错误概率,完全发现不了规律。从调试跟踪的结果看,都是在主I2C给从I2C发送器件地址后,主I2C没有收到ACK,然后超时。看了网上以前的一些分析,提到的一些可能原因,对比分析了,都对应不上。这个是偶现的错误,而且后面的读写都正常,所以写的从I2C的地址肯定是没有问题的。主I2C读写测试是在MCU上电启动后通过按钮开关控制的,不是一上电就开始读写。IO的初始化顺序也试了,IO的端口速率400K和100K都试了,都不能解决这个问题。
通过在软件中判断写操作的结果,如果发现写错误就重复写几次,也解决不了第一次偶然写失败的问题。
另外用中断的方式读写I2C,也有一样的问题,偶现第一次写失败,中断方式中发现主I2C能收到I2C_IT_AF中断错误。从I2C设备暂时不太好分析,现在还不确定到底是STM32F103的I2C的问题还是从设备的I2C问题。
不知道有没有遇到类似的问题的?能不能解决?
下面是STM32F103的I2C的IO/I2C初始化代码和I2C读写单个字节的代码:
void I2C_Config(void)
{
I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_ClocksTypeDef rcc_clocks;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
GPIO_AFIODeInit();
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1|RCC_APB1Periph_I2C2, ENABLE);
RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1|RCC_APB1Periph_I2C2, DISABLE);
GPIO_DeInit(GPIOB);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, GPIO_InitStructure);
GPIO_SetBits(GPIOB, GPIO_InitStructure.GPIO_Pin);
GPIO_PinLockConfig(GPIOB, GPIO_InitStructure.GPIO_Pin);
I2C_DeInit(I2C2);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x23; //unuseful
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 400000;
I2C_Init(I2C2, I2C_InitStructure);
I2C_Cmd(I2C2, ENABLE);
I2C_AcknowledgeConfig(I2C2, ENABLE);
RCC_GetClocksFreq( rcc_clocks);
g_ul
timeOut = (rcc_clocks.SYSCLK_Frequency /10000);
}
void I2C_WriteByte(u8 addr, u8 data)
{
u32 timeout = g_ulTimeOut;
while((timeout--) (I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY)));
I2C_GenerateSTART(I2C2, ENABLE);
timeout = g_ulTimeOut;
while((timeout--) (SUCCESS!=I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)));
I2C_Send7bitAddress(I2C2, IIC_DEVICE_ADDRESS, I2C_Direction_Transmitter);
timeout = g_ulTimeOut;
while((timeout--) (SUCCESS!=I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)));
I2C_SendData(I2C2, addr);
timeout = g_ulTimeOut;
while((timeout--) (SUCCESS!=I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING)));
I2C_SendData(I2C2, data);
timeout = g_ulTimeOut;
while((timeout--) (SUCCESS!=I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED)));
I2C_GenerateSTOP(I2C2, ENABLE);
}
void I2C_ReadByte(u8 addr, u8 *pdata)
{
u32 timeout = g_ulTimeOut;
while((timeout--) I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C2, ENABLE);
timeout = g_ulTimeOut;
while((timeout--) (SUCCESS!=I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)));
I2C_Send7bitAddress(I2C2, IIC_DEVICE_ADDRESS, I2C_Direction_Transmitter);
timeout = g_ulTimeOut;
while((timeout--) (SUCCESS!=I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)));
I2C_SendData(I2C2, addr);
timeout = g_ulTimeOut;
while((timeout--) (SUCCESS!=I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING)));
//restart
I2C_GenerateSTART(I2C2, ENABLE);
timeout = g_ulTimeOut;
while((timeout--) (SUCCESS!=I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT)));
// device address, read action
I2C_Send7bitAddress(I2C2, IIC_DEVICE_ADDRESS, I2C_Direction_Receiver);
timeout = g_ulTimeOut;
while((timeout--) (SUCCESS!=I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)));
// receive byte
I2C_AcknowledgeConfig(I2C2, DISABLE);
I2C_GenerateSTOP(I2C2, ENABLE);
// read
timeout = g_ulTimeOut;
while((timeout--) (SUCCESS!=I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED)));
*pdata = I2C_ReceiveData(I2C2);
I2C_AcknowledgeConfig(I2C2, ENABLE);
}