问答

汇集网友智慧,解决技术难题

21ic问答首页 - gd32l23cct6 硬件i2c 等待TI / RBNE标志位超时

GD32 I2c

gd32l23cct6 硬件i2c 等待TI / RBNE标志位超时

gakiki2023-09-21
gd32l23cct6芯片在硬件i2c读写过程中会偶尔出现write函数在TI标志位超时跳出,read函数在RBNE标志位超时跳出,TIMEOUT时间测试200ms+,在这两个标志位超时异常跳出导致i2c通信时序缺少stop位,bsy标志位一直位1,i2c再也无法继续通信,一定要通过复位i2c外设才能解决。硬件i2c驱动代码去下
int gd32_i2c_write(unsigned char bus, unsigned short addr, unsigned char *data, unsigned int data_len)
{
    drv_i2c_mgr_t *i2c_mgr = NULL;
    unsigned int timeout = DRV_I2C_TIME_OUT;
    unsigned int idx;

    if (bus >= DRV_I2C_BUS_MAX)
    {
        return -1;
    }

    i2c_mgr = &s_st_i2c_mgr[bus];
    if (0 == i2c_mgr->is_init)
    {
        return -1;
    }

    /* wait until I2C bus is idle */
    timeout = DRV_I2C_TIME_OUT;
    i2c_master_addressing(i2c_mgr->periph, addr<<1, I2C_MASTER_TRANSMIT);
    i2c_address_config(i2c_mgr->periph, DRV_I2C_OWN_ADDRESS7, I2C_ADDFORMAT_7BITS);
    /* len not include addr byte */
    i2c_transfer_byte_number_config(i2c_mgr->periph, data_len);
    while(i2c_flag_get(i2c_mgr->periph, I2C_FLAG_I2CBSY))
    {
        if ((timeout--) == 0)
        {
            return -1;
        }
    }

    /* send a start condition to I2C bus */
    timeout = DRV_I2C_TIME_OUT;
    i2c_start_on_bus(i2c_mgr->periph);

    /* wait until the transmit data buffer is empty */
    I2C_STAT(i2c_mgr->periph) |= I2C_STAT_TBE;
    while(!i2c_flag_get(i2c_mgr->periph, I2C_FLAG_TBE))
    {
        if ((timeout--) == 0)
        {
            return -1;
        }
    }

    for(idx = 0; idx < data_len; idx++)
    {
        /* data transmission */
        timeout = DRV_I2C_TIME_OUT;
        i2c_data_transmit(i2c_mgr->periph, data[idx]);
        while(!i2c_flag_get(i2c_mgr->periph, I2C_FLAG_TI))
        {
            if ((timeout--) == 0)
            {
                LOG_DIRECT_ERR("ti\r\n");
                return -1;
            }
        }
    }
    timeout = DRV_I2C_TIME_OUT;
    while(!i2c_flag_get(i2c_mgr->periph, I2C_FLAG_TC))
    {
        if ((timeout--) == 0)
        {
            return -1;
        }
    }

    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(i2c_mgr->periph);
    /* wait until stop condition generate */
    while(!i2c_flag_get(i2c_mgr->periph, I2C_FLAG_STPDET))
    {
        if ((timeout--) == 0)
        {
            return -1;
        }
    }

    /* clear the STPDET bit */
    i2c_flag_clear(i2c_mgr->periph, I2C_FLAG_STPDET);

    return 0;
}

int gd32_i2c_read(unsigned char bus, unsigned short addr, unsigned char *data, unsigned int data_len)
{
    drv_i2c_mgr_t *i2c_mgr = NULL;
    unsigned int timeout = DRV_I2C_TIME_OUT;
    unsigned int idx;

    if (bus >= DRV_I2C_BUS_MAX)
    {
        return -1;
    }

    i2c_mgr = &s_st_i2c_mgr[bus];
    if (0 == i2c_mgr->is_init)
    {
        /* I2C init fail ,value invalid */
        return -1;
    }

    /* wait until I2C bus is idle */
    i2c_master_addressing(i2c_mgr->periph, addr<<1, I2C_MASTER_RECEIVE);
    i2c_address_config(i2c_mgr->periph, addr<<1, I2C_ADDFORMAT_7BITS);
    i2c_transfer_byte_number_config(i2c_mgr->periph, data_len);

    timeout = DRV_I2C_TIME_OUT;
    while(i2c_flag_get(i2c_mgr->periph, I2C_FLAG_I2CBSY))
    {
        if ((timeout--) == 0)
        {
            return -1;
        }
    }

    /* send a start condition to I2C bus */
    i2c_start_on_bus(i2c_mgr->periph);

    for(idx = 0; idx < data_len; idx++)
    {
        /* wait until the RBNE bit is set */
        timeout = DRV_I2C_TIME_OUT;
        while(!i2c_flag_get(i2c_mgr->periph, I2C_FLAG_RBNE))
        {
            if ((timeout--) == 0)
            {
                LOG_DIRECT_ERR("rbne\r\n");
                return -1;
            }
        }
        /* read a data from I2C_DATA */
        data[idx] = i2c_data_receive(i2c_mgr->periph);
    }

    while(!i2c_flag_get(i2c_mgr->periph, I2C_FLAG_TC))
    {
        timeout = DRV_I2C_TIME_OUT;
        if ((timeout--) == 0)
        {
            return -1;
        }
    }
    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(i2c_mgr->periph);
    /* wait until stop condition generate */
    while(!i2c_flag_get(i2c_mgr->periph, I2C_FLAG_STPDET))
    {
        timeout = DRV_I2C_TIME_OUT;
        if ((timeout--) == 0)
        {
            return -1;
        }
    }

    /* clear the STPDET bit */
    i2c_flag_clear(i2c_mgr->periph, I2C_FLAG_STPDET);   

    return 0;
}

回答 +关注 16
2900人浏览 11人回答问题 分享 举报
11 个回答
12下一页

您需要登录后才可以回复 登录 | 注册