打印

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

[复制链接]
2943|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gakiki|  楼主 | 2023-9-21 14:18 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
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;
}

使用特权

评论回复
沙发
gakiki|  楼主 | 2023-9-21 17:37 | 只看该作者

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

补充一下:排查问题发现是在TBE标志位等待,异常情况的波形TBE标志位等待延时了20us左右,导致会在TI标志位等待超时跳出。手动在这个地方加了一个20us的延时函数测试验证问题就是出在这里,在TBE后TI前的地方加了一个us级延时函数,i2c必定异常。各位大佬有没有遇到过类似情况的,帮忙看看,谢谢!

使用特权

评论回复
板凳
tpgf| | 2023-10-12 14:03 | 只看该作者
为什么iic对时序的要求这么严格呢

使用特权

评论回复
地板
八层楼| | 2023-10-12 14:32 | 只看该作者
tpgf 发表于 2023-10-12 14:03
为什么iic对时序的要求这么严格呢

而且不知道为啥 用io模拟的iic反而运行起来更顺畅

使用特权

评论回复
5
guanjiaer| | 2023-10-12 15:57 | 只看该作者
一般是什么原因导致等待这个标志位超时呢

使用特权

评论回复
6
keaibukelian| | 2023-10-12 16:16 | 只看该作者
iic有没有复位函数呢 如果有的话 当复位后 iic还需要重新进行初始化吗

使用特权

评论回复
7
观海| | 2023-10-12 20:12 | 只看该作者
主从双方都可以通过重发机制进行保护吗

使用特权

评论回复
8
heimaojingzhang| | 2023-10-12 22:33 | 只看该作者
是不是可以考虑定时对iic设备进行初始化

使用特权

评论回复
9
1358001518| | 2023-10-13 11:36 | 只看该作者
老哥能把gd32l23x的cmsis那些文件发一份给我吗 在官网找不到 麻烦您了

使用特权

评论回复
10
cr315| | 2024-2-11 18:51 | 只看该作者
检查硬件连接

使用特权

评论回复
11
cr315| | 2024-2-11 18:52 | 只看该作者
I2C的初始化配置、软件配置是否有误

使用特权

评论回复
12
cr315| | 2024-2-11 18:52 | 只看该作者
可能是硬件故障

使用特权

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

本版积分规则

1

主题

2

帖子

0

粉丝