你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F103ZET6的I2C硬件轮询方式作为主发送数据,在第一次发送数据会出现偶现的等待从机ACK错误

[复制链接]
Outerman 提问时间:2023-1-12 17:09 / 未解决
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_ulTimeOut = (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);
}


收藏 评论6 发布时间:2023-1-12 17:09

举报

6个回答
1+1=2 回答时间:2023-1-13 08:26:38
用软件吧,硬件的感觉不太稳定的样子
废鱼 回答时间:2023-1-13 08:39:00
楼主,您好。建议先抓一下波形,先保证I2C不是被锁死的状态。可以考虑初始化时增加一个I2C的结束操作,让I2C总线的设备进入正常状态。另外,I2C总线上上拉电阻是否焊接,上拉电阻的阻值是多少?
老牛洋车 回答时间:2023-1-13 08:57:44
启动I2C通讯时加一个延时看看。
Outerman 回答时间:2023-1-14 11:32:56
1+1=2 发表于 2023-1-13 08:26
用软件吧,硬件的感觉不太稳定的样子

软件模拟通过延时来确定SCL的频率,不精确,对实时性要求高的需求就不行了。
butterflyspring 回答时间:2023-1-16 11:35:41
对于主的I2C设备,Repeated Start condition setup time 是有一定时间间隔的。楼主不妨加一点点延时试试看。
Outerman 回答时间:2023-2-25 10:48:53

废鱼 发表于 2023-1-13 08:39
楼主,您好。建议先抓一下波形,先保证I2C不是被锁死的状态。可以考虑初始化时增加一个I2C的结束操作,让I2 ...

没抓波形。有上拉电阻,上拉1K,2.2K,5.1K都有。这个问题是随机出现的。我的测试方法是,用STM32F103写好的测试程序,MCU和从I2C上电初始化后,I2C是不能读写的。通过一个按键控制的,当控制按键按下后,MCU的主I2C开始发送写和读操作,读写操作是持续循环的。在第一次的时候发生写操作错误,错误的原因分析出来是发现主I2C没有收到ACK,用中断模式的情况下会伴随发现AF中断错误。第一次错误后,后面的写和读操作都正常了。我改测试程序,如果判断写错误,重新写5次,发现这样重复写5次也是一样错,软件发现写错误时,有发STOP操作。

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版