该函数的 I2C 时序存在问题,需要进行修改:

  1. 在函数开始处,将设备地址设为函数的参数 deviceAddr,而不是硬编码为 BQ27441_G1_ADDR。

  2. 在发送地址时,应该先发送 START,再发送设备地址,而不是先发送设备地址。

  3. 在发送命令和数据时,应该先发送设备地址和命令,再发送数据。

  4. 在读取数据时,应该先发送设备地址和命令,再发送 RESTART,并将设备地址左移一位,表示读取操作。同时,应该在读取完数据后发送 STOP。

  5. 在读取数据时,应该先判断数据长度是否为 2,如果是,则不需要发送 ACK,而是直接发送 NACK 后发送 STOP。如果不是,则需要发送 ACK。

  6. 函数应该返回读取到的数据。

修改后的函数如下:

uint8_t I2CTransfer(uint16_t deviceAddr, uint8_t cmdArray[], uint8_t dataArray[], uint16_t cmdLen, uint16_t dataLen, uint16_t flag)
{
    /* 1.I2C 空闲检测. */
    while(LL_I2C_IsActiveFlag_BUSY(I2C_Handle));
    
    /* 2.START 信号. */
    LL_I2C_GenerateStartCondition(I2C_Handle);
    while(!LL_I2C_IsActiveFlag_SB(I2C_Handle));
    
    /* 3.发送设备地址和命令. */
    LL_I2C_TransmitData8(I2C_Handle, deviceAddr << 1);
    while(!LL_I2C_IsActiveFlag_ADDR(I2C_Handle));
    LL_I2C_ClearFlag_ADDR(I2C_Handle);
    
    for(uint16_t i = 0; i < cmdLen; i++)
    {
        LL_I2C_TransmitData8(I2C_Handle, cmdArray[i]);
        while(!LL_I2C_IsActiveFlag_TXE(I2C_Handle));
    }
    
    /* 4.发送数据. */
    if(flag == I2C_FLAG_WRITE)
    {
        for(uint16_t i = 0; i < dataLen; i++)
        {
            LL_I2C_TransmitData8(I2C_Handle, dataArray[i]);
            while(!LL_I2C_IsActiveFlag_TXE(I2C_Handle));
        }
    }
    
    /* 5.RESTART 信号. */
    if(flag == I2C_FLAG_WRITE_READ)
    {
        LL_I2C_GenerateRestartCondition(I2C_Handle);
        while(!LL_I2C_IsActiveFlag_SB(I2C_Handle));
        
        LL_I2C_TransmitData8(I2C_Handle, (deviceAddr << 1) | 0x01);
        while(!LL_I2C_IsActiveFlag_ADDR(I2C_Handle));
        LL_I2C_ClearFlag_ADDR(I2C_Handle);
        
        for(uint16_t i = 0; i < cmdLen; i++)
        {
            LL_I2C_TransmitData8(I2C_Handle, cmdArray[i]);
            while(!LL_I2C_IsActiveFlag_TXE(I2C_Handle));
        }
        
        /* 6.读取数据. */
        uint8_t data = 0;
        if(dataLen == 2)
        {
            LL_I2C_AcknowledgeNextData(I2C_Handle, LL_I2C_NACK);
            LL_I2C_ClearFlag_ADDR(I2C_Handle);
            LL_I2C_GenerateStopCondition(I2C_Handle);
            while(!LL_I2C_IsActiveFlag_RXNE(I2C_Handle));
            
            data = LL_I2C_ReceiveData8(I2C_Handle);
        }
        else
        {
            LL_I2C_AcknowledgeNextData(I2C_Handle, LL_I2C_ACK);
            while(!LL_I2C_IsActiveFlag_RXNE(I2C_Handle));
            
            data = LL_I2C_ReceiveData8(I2C_Handle);
            
            LL_I2C_GenerateStopCondition(I2C_Handle);
            while(LL_I2C_IsActiveFlag_STOP(I2C_Handle));
        }
        
        return data;
    }
    
    /* 7.STOP 信号. */
    LL_I2C_GenerateStopCondition(I2C_Handle);
    while(LL_I2C_IsActiveFlag_STOP(I2C_Handle));
    
    return 0;
}
I2C 时序错误修复:优化 I2CTransfer 函数

原文地址: https://www.cveoy.top/t/topic/m9fy 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录