打印
[APM32F4]

硬件I2C通信:速度飞快,但要小心卡死问题!

[复制链接]
4796|55
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Fordhs168|  楼主 | 2023-7-31 17:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Fordhs168 于 2023-7-31 17:27 编辑

#技术资源#

  硬件I2C(Inter-Integrated Circuit)通信在APM32F407等微控制器上具有引人瞩目的速度和稳定性,成为众多应用领域的首选。相较于模拟I2C,硬件I2C不依赖于软件实现,而是由硬件直接控制数据传输,因此具备更快的通信速度。这意味着高效的数据交换,更快的响应时间,以及优化的性能表现。
然而,我们也应该认识到硬件I2C可能面临的一个主要问题——卡死或经常遇到总线BUSY。当通信中断、数据错误或外设故障发生时,硬件I2C有可能陷入僵局,导致整个系统崩溃。为了避免这种情况,开发者必须仔细设计错误处理机制,确保系统在异常情况下能够恢复正常运行。
尽管硬件I2C可能会面临一些挑战,但它的高速传输和稳定性仍然使其成为众多应用场景中的首选。无论是高频率数据传输、实时通信还是传感器读取,硬件I2C都能够胜任,并为您的应用程序带来卓越的性能表现。
综上所述,硬件I2C的速度之快让人叹为观止,但同时也需要我们谨慎对待可能出现的卡死问题。只要合理规划和处理,硬件I2C必将成为提高系统效率的得力工具。

下面给出基于APM32F407的硬件I2C例程供参考;
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date           Author       Notes
* 2023-07-31     geehy       the first version
*/
#ifndef APPLICATIONS_GEEHY_I2C_H_
#define APPLICATIONS_GEEHY_I2C_H_
#include <rtthread.h>
#include "apm32f4xx_gpio.h"
#include "apm32f4xx_i2c.h"
#include "apm32f4xx_rcm.h"
void I2C1_Init(void);
void I2C_EE_BufferRead(I2C_T* i2c,uint8_t* pBuffer,uint8_t DeviceAddr, uint16_t ReadAddr, uint32_t NumByteToRead);
void I2C_EE_BufferWrite(I2C_T* i2c,uint8_t* pBuffer,uint8_t DeviceAddr, uint16_t WriteAddr, uint32_t NumByteToWrite);
void I2C_BufferWritePage(I2C_T* i2c,uint8_t DeviceAddr,uint16_t WriteAddr,uint8_t *pBuffer,uint32_t lenth);
void EEprom_Test(void);

#define SLAVE_ADDR 0X00A0  //AT24c256地址

#endif /* APPLICATIONS_GEEHY_I2C_H_ */



#include "Geehy_I2C.h"


void I2C1_Init(void){
   GPIO_Config_T gpioConfigStruct;
   I2C_Config_T i2cConfigStruct;

   /** Enable I2C related Clock */
   RCM_EnableAHB1PeriphClockLPMode(RCM_AHB1_PERIPH_GPIOB);
   RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_I2C1);
   GPIO_ConfigPinAF(GPIOB,GPIO_PIN_SOURCE_6,GPIO_AF_I2C1);
   GPIO_ConfigPinAF(GPIOB,GPIO_PIN_SOURCE_7,GPIO_AF_I2C1);
   /** Free I2C_SCL and I2C_SDA */
   gpioConfigStruct.mode = GPIO_MODE_AF;
   gpioConfigStruct.otype = GPIO_OTYPE_OD;
   gpioConfigStruct.speed = GPIO_SPEED_50MHz;
   gpioConfigStruct.pin = GPIO_PIN_6;
   GPIO_Config(GPIOB, &gpioConfigStruct);

   gpioConfigStruct.mode = GPIO_MODE_AF;
   gpioConfigStruct.otype = GPIO_OTYPE_OD;
   gpioConfigStruct.speed = GPIO_SPEED_50MHz;
   gpioConfigStruct.pin = GPIO_PIN_7;
   GPIO_Config(GPIOB, &gpioConfigStruct);


   /** Config I2C1 */
   I2C_Reset(I2C1);
   i2cConfigStruct.mode = I2C_MODE_I2C;
   i2cConfigStruct.dutyCycle = I2C_DUTYCYCLE_2;
   i2cConfigStruct.ackAddress = I2C_ACK_ADDRESS_7BIT;
   i2cConfigStruct.ownAddress1 = 0X4f;
   i2cConfigStruct.ack = I2C_ACK_ENABLE;
   i2cConfigStruct.clockSpeed = 400000;
   I2C_Config(I2C1,&i2cConfigStruct);
   /** NVIC coniguration */
//   NVIC_EnableIRQRequest(I2C1_EV_IRQn,1,0);
   /** Enable the I2C1 Interrupt */
//   I2C_EnableInterrupt(I2C1,I2C_INT_EVT);

   /** Enable I2Cx */
   I2C_Enable(I2C1);

//   I2C_ClearIntFlag(I2C1,);


}
//void I2C_Start(I2C_T* i2c, uint8_t address, uint8_t direction){
//}

void I2C_EE_BufferRead(I2C_T* i2c,uint8_t* pBuffer,uint8_t DeviceAddr, uint16_t ReadAddr, uint32_t NumByteToRead){
    uint8_t trans[2];
    trans[0]=ReadAddr>>8;
    trans[1]=ReadAddr;
    while (I2C_ReadStatusFlag(i2c,I2C_FLAG_BUSBSY));
    //产生起始信号
    I2C_EnableGenerateStart(i2c);
     //检测并清除EV5
    while(!I2C_ReadEventStatus(i2c,I2C_EVENT_MASTER_MODE_SELECT));
    //发送从设备地址
    I2C_Tx7BitAddress(i2c,DeviceAddr,I2C_DIRECTION_TX);

    //检测并清除EV6
    while(!I2C_ReadEventStatus(i2c,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){}


    /*AT24C256-从设备内部地址是16bit-分两次写入*/
    I2C_TxData(i2c, trans[0]);
    //检测并清除EV8
    while(!I2C_ReadEventStatus(i2c,I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_TxData(i2c, trans[1]);
    //检测并清除EV8
    while(!I2C_ReadEventStatus(i2c,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    //第二次Start信号
    I2C_EnableGenerateStart(i2c);
     //检测并清除EV5
    while(!I2C_ReadEventStatus(i2c,I2C_EVENT_MASTER_MODE_SELECT));
    //发送从设备地址
    I2C_Tx7BitAddress(i2c,DeviceAddr,I2C_DIRECTION_RX);
    //检测并清除EV6
    while(!I2C_ReadEventStatus(i2c,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)){}


    while(NumByteToRead){
    //读到最后一个数据时,发送非应答信号,结束传输
        if(NumByteToRead==1){
            //disable ACK
        I2C_DisableAcknowledge(i2c);
            //发送STOP信号
        I2C_EnableGenerateStop(i2c);
        }
         while(I2C_ReadEventStatus(i2c,I2C_EVENT_MASTER_BYTE_RECEIVED)==0){}


        *pBuffer = I2C_RxData(i2c);

        pBuffer++;

        NumByteToRead--;

    }
    I2C_EnableAcknowledge(i2c);
}
void I2C_EE_BufferWrite(I2C_T* i2c,uint8_t* pBuffer,uint8_t DeviceAddr, uint16_t WriteAddr, uint32_t NumByteToWrite){
    uint8_t trans[2];
    trans[0]=WriteAddr>>8;
    trans[1]=WriteAddr;
    while (I2C_ReadStatusFlag(i2c,I2C_FLAG_BUSBSY));
    //产生起始信号
    I2C_EnableGenerateStart(i2c);
     //检测并清除EV5
    while(!I2C_ReadEventStatus(i2c,I2C_EVENT_MASTER_MODE_SELECT));
    //发送从设备地址
    I2C_Tx7BitAddress(i2c,DeviceAddr,I2C_DIRECTION_TX);
    //检测并清除EV6
    while(!I2C_ReadEventStatus(i2c,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){}

     /*AT24C256-从设备内部地址是16bit-分两次写入*/
    I2C_TxData(i2c, trans[0]);
     //检测并清除EV8
    while(!I2C_ReadEventStatus(i2c,I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_TxData(i2c, trans[1]);
     //检测并清除EV8
    while(!I2C_ReadEventStatus(i2c,I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    while(NumByteToWrite--){
        I2C_TxData(i2c,*pBuffer);
        pBuffer++;
       //检测并清除EV8
        while(!I2C_ReadEventStatus(i2c,I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    }
    I2C_EnableGenerateStop(i2c);
}


/*跨页写入数据*/
void I2C_BufferWritePage(I2C_T* i2c,uint8_t DeviceAddr,uint16_t WriteAddr,uint8_t *pBuffer,uint32_t lenth)
{
    uint32_t page_remain = 64-WriteAddr%64;    //算出开始写入数据的某一页的剩余未写字节数
    if(page_remain>=lenth)    //该页剩余的空间足够写入这些数据时
    {
        page_remain=lenth;    //把写入长度赋值
    }
    while(1)
    {
        rt_thread_mdelay(7);/*写完一页需要加个7ms左右延时,否者I2C容易卡死*/
        I2C_EE_BufferWrite(i2c,pBuffer,DeviceAddr,WriteAddr,page_remain);

        if(page_remain==lenth) break;   //判断是否写完,如果剩余的空间足够写入这些数据,就执行一次上面的函数,如果不够则进行下面的语句。

        WriteAddr+=page_remain;    //如果不相等说明len比page_remain大,则地址偏移已经写入的长度
        pBuffer+=page_remain;    //数据偏移
        lenth-=page_remain;   //总长度减去已经写入的长度
        if(lenth<64)   //判断剩余长度是否够写一整页,不够就赋值实际剩余长度,够就赋值64
        {
            page_remain=lenth;
        }
        else
        {
            page_remain=64;
        }
    }
}

void EEprom_Test(void){
    u8 i=0;
    uint8_t Wdata[255];
    u8 Rdata[255];
    /**eeprom*/
    for( i = 0; i < 255; i++){
        Wdata[i] = (i);
    }
    /*AT24C256 每页64字节 不可跨页操作,写入数据超过64字节需要做判断 -总共256K 分成512页*/
    I2C_BufferWritePage(I2C1,SLAVE_ADDR,0x0000,Wdata,255);/*跨页操作*/
    rt_thread_mdelay(7);
    I2C_EE_BufferRead(I2C1,Rdata,SLAVE_ADDR,0x0020,255);/*从 AT24C256 读数据没有跨页限制   */
}




使用特权

评论回复
评论
Fordhs168 2023-7-31 17:25 回复TA
实试这个例程通用在F103、F407系列MCU上,硬件I2C,不同型号MCU,只需要修改一些头文件定义,IO配置等; 
沙发
updownq| | 2023-8-4 15:24 | 只看该作者
I2C总线是低速高阻总线,在PCB布线时要注意抗干扰

使用特权

评论回复
板凳
maudlu| | 2023-8-4 15:38 | 只看该作者
总线上挂载的设备数量应该适当,以避免影响通信质量和通信速度。

使用特权

评论回复
地板
timfordlare| | 2023-8-4 15:47 | 只看该作者
在通信过程中增加异常处理机制,及时处理通信中断或协议错误,以避免卡死现象的发生。

使用特权

评论回复
5
burgessmaggie| | 2023-8-4 15:58 | 只看该作者
注意设置上拉电阻               

使用特权

评论回复
6
saservice| | 2023-8-4 16:06 | 只看该作者
硬件I2C通信的速度确实比软件I2C通信要快

使用特权

评论回复
7
mollylawrence| | 2023-8-4 16:16 | 只看该作者
尽可能缩短引线长度               

使用特权

评论回复
8
uiint| | 2023-8-4 16:25 | 只看该作者
I2C总线上的SCL和SDA线需要连接上拉电阻,以确保信号在空闲状态时保持高电平。

使用特权

评论回复
9
fengm| | 2023-8-4 16:33 | 只看该作者
在使用I2C传输之前做一个读取bus位来判断I2C总线是否卡死

使用特权

评论回复
10
sdCAD| | 2023-8-4 16:43 | 只看该作者
I2C总线的电缆长度应该尽量短,以减少信号的衰减和干扰。

使用特权

评论回复
11
hearstnorman323| | 2023-8-4 16:52 | 只看该作者
需要注意通信距离的限制              

使用特权

评论回复
12
primojones| | 2023-8-4 17:00 | 只看该作者
与STM32完全兼容但是解决了STM32的硬件I2C bug

使用特权

评论回复
13
i1mcu| | 2023-8-4 17:08 | 只看该作者
需要注意通信速率的选择              

使用特权

评论回复
14
abotomson| | 2023-8-4 17:16 | 只看该作者
在高速传输时,一些问题可能导致I2C通信卡死。

使用特权

评论回复
15
fengm| | 2023-8-4 17:31 | 只看该作者
通过优化通信协议,减少通信延迟和数据传输错误,从而降低卡死现象的发生。

使用特权

评论回复
16
yeates333| | 2023-8-4 17:39 | 只看该作者
从设备的上拉电阻应该选择合适的阻值

使用特权

评论回复
17
cemaj| | 2023-8-4 17:48 | 只看该作者
硬件IIC是有问题的              

使用特权

评论回复
18
tifmill| | 2023-8-4 17:55 | 只看该作者
硬件I2C 到底怎么样?               

使用特权

评论回复
19
chenjun89| | 2023-8-5 20:06 | 只看该作者
硬件IIC速度飞快?何以见得?

使用特权

评论回复
20
weifeng90| | 2023-8-6 08:46 | 只看该作者
第一,硬件IIC不算飞快。第二,跑死和硬件IIC有啥关系?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

15

主题

26

帖子

0

粉丝