ch582f的i2c跑一段时间后出现通信故障的问题。

我目前的项目是ch582f根mpu6050通信。在通信成功几十分钟或几个小时(老化测试一晚)过后会出现无法继续读取mpu6050的情况。提示i2c总线出于忙状态,但是我用示波器和逻辑分析仪测试没有出现sda被拉低的情况,scl和sda线都是高电平状态。image.pngimage.png


uint8_t i2c_timeout(uint32_t *p_times)      //Timeout processing

{

    (*p_times)++;

    //x5_delay_us(1);

    i2c_ch58xx_delay_us(1);

    if(*p_times > I2C_TIMEOUT)    {

        return 1;

    }

    return 0;

}


void x5_i2c_init_bsp(uint8_t no, x5_i2c_config_t *config)

{

    if (no > 0 || !config){

        printf("ch58xx x5_i2c_init_bsp error:no > 0 or config == NULL\r\n");

    }

//

//    static uint8_t init_flag = 0;

//   if (init_flag == 0) {

//      GPIOB_ModeCfg(GPIO_Pin_13 | GPIO_Pin_12, GPIO_ModeIN_PU);

//      I2C_Init(I2C_Mode_I2C, 400000, I2C_DutyCycle_16_9, I2C_Ack_Enable,

//              I2C_AckAddr_7bit, HOST_NO_ADDR);

        if (i2c_info[no].port_clk == CH58xx_GPIOB)        {

            GPIOB_ModeCfg(i2c_info[no].pin_clk, GPIO_ModeIN_PU);

        }else{

            GPIOA_ModeCfg(i2c_info[no].pin_clk, GPIO_ModeIN_PU);

        }

        if (i2c_info[no].port_sda == CH58xx_GPIOB)        {

            GPIOB_ModeCfg(i2c_info[no].pin_sda, GPIO_ModeIN_PU);

        }else{

            GPIOA_ModeCfg(i2c_info[no].pin_sda, GPIO_ModeIN_PU);

        }


        printf("ch58xx x5_i2c_init_bsp: mode:%d,speed:%d,duty_cycle:%d,ack_add:%d,host_NO_ADDR:%d, \r\n",

                i2c_mode[config->mode], i2c_speed[config->speed],i2c_duty_cycle[config->dc],

                I2C_AckAddr_7bit, HOST_ADDR);

        I2C_Init(i2c_mode[config->mode], i2c_speed[config->speed], i2c_duty_cycle[config->dc],

                I2C_Ack_Enable, I2C_AckAddr_7bit, HOST_ADDR);

//      init_flag = 1;

//  }

}


/***************************************

 * read n bytes of data continuously

 * param:

 *      addr-Slave address

 *      mem-Register addr

 *      men_16-Enbale 16 bit register

 *      p_des-Destination pointer

 *      len-Read length

 * return:

 *      0:succeed

 *      1~7:error in 1~7 step.

 *      0x01:error in read continuously

 */


static uint8_t i2c_read_nBytes(uint8_t addr, uint16_t mem, uint8_t mem_16, uint8_t *p_des, uint8_t len)

{

    uint32_t i_timeout = 0;


    /*send register addr*/

    //I2C_GenerateSTOP(DISABLE);

    while(I2C_GetFlagStatus(I2C_FLAG_BUSY))    {                           //IIC whether host busy

        if(i2c_timeout(&i_timeout))

            return 1;

    }


    I2C_GenerateSTART(ENABLE);                                          //start signal

    i_timeout = 0;

    while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)) {               //wait BUSY, MSL and SB flags

        if(i2c_timeout(&i_timeout))

            return 2;

    }


    I2C_Send7bitAddress(addr<<1, I2C_Direction_Transmitter);               //send component addr , bit0 = 0 indicate "write"

    i_timeout = 0;

    while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))    {  //wait BUSY, MSL, ADDR, TXE and TRA flags

        if(i2c_timeout(&i_timeout))

            return 3;

    }


    if(mem_16)    {

        I2C_SendData((uint8_t)(mem>>8));                                    //If mem addr is 16bit, Send the upper 8 bits of the memory address

        i_timeout = 0;

        while(!I2C_GetFlagStatus(I2C_FLAG_TXE)){                             //wait send finished.

            if(i2c_timeout(&i_timeout))

                return 4;

        }

        i_timeout = 0;

    }


    I2C_SendData((uint8_t)mem);                                         //Send the lower 8 bits of the memory address

    while(!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED))  {          //wait TRA, BUSY, MSL, TXE and BTF flags, send register addr finished.

        if(i2c_timeout(&i_timeout))

            return 5;

    }


    /*Generate a re-start signal to start the reading process*/

    I2C_GenerateSTART(ENABLE);                                          //re-start signal

    i_timeout = 0;

    while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)) {               //wait BUSY, MSL and SB flags

        if(i2c_timeout(&i_timeout))

            return 6;

    }


    I2C_AcknowledgeConfig(ENABLE);                                      //After the transmission is completed, turn on ACK enable again

    I2C_Send7bitAddress(addr<<1, I2C_Direction_Receiver);                  //send component addr , bit0 = 1 indicate "read"

    i_timeout = 0;

    while(!I2C_CheckEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)){   //wait BUSY, MSL and ADDR flags

        if(i2c_timeout(&i_timeout))

            return 7;

    }


    for(uint8_t i=0; i<len; i++){

        if(i == len-1)

            //I2C_NACKPositionConfig(I2C_NACKPosition_Next);

            I2C_AcknowledgeConfig(DISABLE);

        //Clear the ACK bit (PE may be cleared here in some cases, this line can be removed, but the logic analyzer will receive one more byte of data if it captures the timing)

        //In order for the master device to generate a NACK signal after receiving the last byte, it must clear the ACK bit (ACK=0) after reading the penultimate byte (after the penultimate RxNE event)


        i_timeout = 0;

        while(!I2C_GetFlagStatus(I2C_FLAG_RXNE))  {                      //wait receive data

            if(i2c_timeout(&i_timeout)){

                printf("[-->%d]I2C_ReceiveData: i =%d\r\n",__LINE__,i);

                return 0xff;

            }

        }

        *(p_des+i) = I2C_ReceiveData();                                   //read data from Rx register

    }

    I2C_GenerateSTOP(ENABLE);                                           //Turn on the stop signal


    return 0;

}


情况能怎么防止或者清除这个busy标志?

自顶一下。-》帮帮我!-》帮帮我!


解决了,在SDA和SCL都拉高的时候不判断BUSY标志位,直接开始I2C通信即直接发送START信号。


只有登录才能回复,可以选择微信账号登录