I2C通讯记录

I2C通讯总结:

  1. 确定I2C地址;一般i2c有7位跟10位的区分,8位地址是7位地址左移1位,或者读写位,读位1 写为0;
    在这里插入图片描述
    在这里插入图片描述
    I2C设备的写地址 = I2C设备地址 << 1
    I2C设备的读地址 = (I2C设备地址 << 1) + 1
    假设一个i2c 7位地址位0x50 ,则它的读地址为(0x50<<1)| 0x1=0xA1,写地址为0xA0;
    10位地址暂时不谈;
  2. 通讯时序
    开始信号:
    在这里插入图片描述
    停止信号:
    在这里插入图片描述

读数据:SCL拉低是SDA可以改变,SCL 高的时候,SDA数据要稳定,SCL高这个时候读SDA数据;
在这里插入图片描述

回读reg数据:(包含ack,nack是传完最后一个字节时会回应NACK, NACK SDA为高)
在这里插入图片描述

  1. 通讯流程
    在这里插入图片描述

通讯过程步骤:

  1. 某个从机A发送start 信号,A变成了主机模式,A发送通讯从机地址B的写地址,如果有ack,表明A已发送地址并收到B回应;
  2. A 发送需要写入/读取的寄存器地址reg_addr,收到ack后,发送restart信号;
  3. A 发送从机B地址(读就发送读地址,写就发送写地址),有ack后,发送要读/写的数据.如果是多个数据,则中间每个数据都会有ack,最后一个字节发送完,会有NACK;
  4. 主机A发送停止信号;
    单片机硬件I2C通讯流程:
    在这里插入图片描述

寄存器介绍:
在这里插入图片描述
在这里插入图片描述

硬件i2c初始化

void i2c1_config(void)
{

    unsigned char val;
    i2c_cfg[1].i2c_peri = I2C1;
    i2c_cfg[1].addr = DEFAULT_BACKPLANE_ADDR;
    
    i2c_cfg[1].i2c_rd = rngCreate(I2C_RNG_SIZE);

    i2c_cfg[1].i2c_wr = rngCreate(I2C_RNG_SIZE);

    if(!i2c_cfg[1].i2c_rd || !i2c_cfg[1].i2c_wr)
        return ;
    i2c_cfg[1].mutex = xSemaphoreCreateMutex();
      
    i2c_cfg[1].xfer.mode = MODE_MASTER;
    
    rcu_periph_clock_enable(RCU_I2C1);
    /* I2C1 SDA/PB11 SCL/PB10 SMBA/PB12*/
    gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
    
    i2c_deinit(I2C1);
    /* configure I2C clock */
    i2c_clock_config(I2C1, I2C1_SPEED, I2C_DTCY_2);
#ifdef I2C_SMBUS
    /* configure I2C address */  
    i2c_mode_addr_config(I2C1, I2C_SMBUSMODE_ENABLE, I2C_ADDFORMAT_7BITS, i2c_cfg[1].addr);
    /* configure SMBUS HOST/DEVICE */
    i2c_smbus_type_config(I2C1, I2C_SMBUS_HOST);
#endif

    
    i2c_interrupt_enable(I2C1, I2C_INT_EV);
    i2c_interrupt_enable(I2C1, I2C_INT_ERR);
    i2c_interrupt_enable(I2C1, I2C_INT_BUF);
    //i2c_interrupt_enable(I2C1, I2C_INT_STPSEND);
    
    nvic_irq_enable(I2C1_EV_IRQn, 0, 2);
    nvic_irq_enable(I2C1_ER_IRQn, 0, 2);

    /* enable I2C1 */
    i2c_enable(I2C1);  
    
    i2c_ack_config(I2C1, I2C_ACK_ENABLE);
}

中断处理函数:

//i2c_cfg结构体
 struct I2C_Config {
    RING_ID i2c_rd;
    RING_ID i2c_wr;
    unsigned int i2c_peri;   
    unsigned char addr;
    struct i2c_transfer_t xfer;
    SemaphoreHandle_t mutex;
    unsigned char support_eeprom;
};
static struct I2C_Config i2c_cfg[2];

void i2c_ev_isr(unsigned int index)
{
    unsigned char val=0;
    unsigned int i2c_peri = i2c_cfg[index].i2c_peri;
    
    if(i2c_cfg[index].xfer.mode == MODE_SLAVE){
        if(i2c_interrupt_flag_get(i2c_peri, I2C_INT_FLAG_ADDSEND) == SET){
            i2c_interrupt_flag_clear(i2c_peri, I2C_INT_FLAG_ADDSEND);
            //从机发送
            if(i2c_cfg[index].xfer.flag & FLAG_START){
                
                SMBusCommandProcess(index);
            } else{
                i2c_cfg[index].xfer.flag |= FLAG_START;
                
            }  
        } 
        if(i2c_interrupt_flag_get(i2c_peri, I2C_INT_FLAG_RBNE) == SET){
            i2c_interrupt_flag_clear(i2c_peri, I2C_INT_FLAG_RBNE);
            
            val = i2c_data_receive(i2c_peri);
            
            if(rngBufPut(i2c_cfg[index].i2c_rd, &val, 1) != 1){ printf("i2c data save error \n");;}
                  //printf("I2C%x recv lost %x\r\n", index, val);   
              
            ++i2c_cfg[index].xfer.rd_len;

            printf("MODE_SLAVE 0x%x\n", val);
        } 
        if(i2c_interrupt_flag_get(i2c_peri, I2C_INT_FLAG_TBE) == SET){

                rngBufGet(i2c_cfg[index].i2c_wr, &val, 1);
                
                i2c_data_transmit(i2c_peri, val);
                
                 printf("send 0x%x\n", val);
                //当移位寄存器与DATA都为空,可以再写一个字节
                if(i2c_interrupt_flag_get(i2c_peri, I2C_INT_FLAG_TBE) == SET){
                    rngBufGet(i2c_cfg[index].i2c_wr, &val, 1);
                   
                    i2c_data_transmit(i2c_peri, val);     
                }

                
        } 
        //slave 读结束flag
        if(SET == i2c_interrupt_flag_get(i2c_peri, I2C_INT_FLAG_STPDET)){
            i2c_enable(i2c_cfg[index].i2c_peri);
            //从机接收
            SMBusCommandProcess(index);
            //清空buffer
            rngFlush(i2c_cfg[index].i2c_rd);               
            rngFlush(i2c_cfg[index].i2c_wr);

            i2c_cfg[index].xfer.rd_len = 0;
            i2c_cfg[index].xfer.wr_len = 0;
            
        }
    } else {
      //主机模式下 判断是否发送了地址并收到了ack
        if(i2c_interrupt_flag_get(i2c_peri, I2C_INT_FLAG_ADDSEND) == SET){
           //收到发送了地址并收到了ack,清除掉这个标志位
            i2c_interrupt_flag_clear(i2c_peri, I2C_INT_FLAG_ADDSEND);
            i2c_cfg[index].xfer.flag |= FLAG_START;
 
        } 
        if(i2c_interrupt_flag_get(i2c_peri, I2C_INT_FLAG_RBNE) == SET){ 
             printf("i2c_cfg[index].xfer.rd_len:%d\n",i2c_cfg[index].xfer.rd_len);
              if(i2c_cfg[index].xfer.rd_len ==0)
            { 
              
               i2c_interrupt_flag_clear(i2c_peri, I2C_INT_FLAG_RBNE);
               val = i2c_data_receive(i2c_peri);//当接收长度为0时,为了消除I2C_INT_FLAG_RBNE标志位,需要对I2C_DATA进行对操作;
               printf("i2c:len :0x%x  rev val 0x%x\n", i2c_cfg[index].xfer.rd_len,val);
            }
            /* 接收到len-1长度的数据,发送NACK和stop并接收下一个数据 */
              else if(i2c_cfg[index].xfer.rd_len == 1){
                  
                i2c_ack_config(i2c_peri, I2C_ACK_DISABLE);  
                i2c_stop_on_bus(i2c_peri);                  
                i2c_cfg[index].xfer.flag |= FLAG_STOP;
                
                val = i2c_data_receive(i2c_peri);
                printf("i2c:len :0x%x  rev val 0x%x\n", i2c_cfg[index].xfer.rd_len,val);  
                --i2c_cfg[index].xfer.rd_len ;
                if(rngBufPut(i2c_cfg[index].i2c_rd, &val, 1) != 1)
                      ;  
            }
            else
            { 
                 val = i2c_data_receive(i2c_peri); 
                 if(rngBufPut(i2c_cfg[index].i2c_rd, &val, 1) != 1) 
                         ; 
                 --i2c_cfg[index].xfer.rd_len ;
                 
            }

                        ;
        } 
        //判断是否发送了start信号
        if(SET == i2c_interrupt_flag_get(i2c_peri, I2C_INT_FLAG_SBSEND)){
            //判断传输方向
            if(i2c_cfg[index].xfer.direction == DIR_RD){
                 //方向为接收  此处写I2C_DATA
                i2c_master_addressing(i2c_peri, i2c_cfg[index].xfer.xfer_addr, I2C_RECEIVER);           
            } else {
                 //方向为发送  此处写I2C_DATA
                i2c_master_addressing(i2c_peri, i2c_cfg[index].xfer.xfer_addr, I2C_TRANSMITTER);
            }

        } //I2C_DATA是否为空  1为空
        if(i2c_interrupt_flag_get(i2c_peri, I2C_INT_FLAG_TBE) == SET){
            /* write完成,发送restart */
            if(i2c_cfg[index].xfer.wr_len == 0 && i2c_cfg[index].xfer.rd_len != 0){
                i2c_cfg[index].xfer.direction = DIR_RD;
               
                i2c_start_on_bus(i2c_peri);

            /* 收发完成,stop */
            } else if(i2c_cfg[index].xfer.wr_len == 0 && i2c_cfg[index].xfer.rd_len == 0){
               
                #ifdef I2C_PEC
                i2c_pec_transfer(i2c_peri);
                #endif
                i2c_stop_on_bus(i2c_peri);
                
                i2c_cfg[index].xfer.flag |= FLAG_STOP;
                
               

            /* write */
            } else if(!rngIsEmpty(i2c_cfg[index].i2c_wr)){
                rngBufGet(i2c_cfg[index].i2c_wr, &val, 1);
                
                i2c_data_transmit(i2c_peri, val);
               
                --i2c_cfg[index].xfer.wr_len;

            }           
        }
       
    }
}

读写:

int SMBusBlockRead(unsigned int index, unsigned char slaveAddr, unsigned char cmd, unsigned char *buffer, unsigned int len)
{
    int i=0;
    unsigned char val;
    struct I2C_Config *pI2C = &i2c_cfg[index];

    while(i2c_flag_get(pI2C->i2c_peri, I2C_FLAG_I2CBSY) && (i++<SMBUS_TIMEOUT_US))udelay(1);
    
    if(i>=SMBUS_TIMEOUT_US)
        return ACK_SMBUS_TIMEOUT; 
    i2c_prepare_transfer(index);
    
    MUTEX_TAKE(pI2C->mutex);
    
    pI2C->xfer.mode = MODE_MASTER;
    
    pI2C->xfer.xfer_addr = slaveAddr;
    
    pI2C->xfer.direction = DIR_RDWR;
       
        //cmd+buffer
      pI2C->xfer.wr_len = 1;    
      pI2C->xfer.rd_len = len;    
      rngBufPut(pI2C->i2c_wr, (unsigned char *)&cmd, 1);

  
    
    i2c_start_on_bus(pI2C->i2c_peri);
#if 0
    //cmd+buffer
    while((rngNBytes(pI2C->i2c_rd)<len) && (i++<SMBUS_TIMEOUT_US))udelay(1);

    if(i>=SMBUS_TIMEOUT_US)
        return -1;    
#endif
    //等待传输结束后取数据
    while(!(i2c_cfg[index].xfer.flag & FLAG_STOP)){
        if(i2c_cfg[index].xfer.flag & FLAG_TIMEOUT){
            MUTEX_GIVE(pI2C->mutex);
            return ACK_SMBUS_TIMEOUT;
        }
    }

    rngBufGet(pI2C->i2c_rd, buffer, len);
    
    i2c_stop_transfer(index);
    
    MUTEX_GIVE(pI2C->mutex);

    return ACK_OK;
}

int SMBusBlockWrite(unsigned int index, unsigned char slaveAddr, unsigned char cmd, unsigned char *buffer, unsigned int len)
{
    int i=0;
    struct I2C_Config *pI2C = &i2c_cfg[index];

    while(i2c_flag_get(pI2C->i2c_peri, I2C_FLAG_I2CBSY) && (i++<SMBUS_TIMEOUT_US))udelay(1);
    
    if(i>=SMBUS_TIMEOUT_US)
        return ACK_SMBUS_TIMEOUT;  
    
    i2c_prepare_transfer(index);
    
    MUTEX_TAKE(pI2C->mutex);
    
    pI2C->xfer.mode = MODE_MASTER;
    
    pI2C->xfer.xfer_addr = slaveAddr;
    
    pI2C->xfer.direction = DIR_WR;
    //cmd+buffer
    pI2C->xfer.wr_len = len+1;
    
    pI2C->xfer.rd_len = 0;

    rngBufPut(pI2C->i2c_wr, (unsigned char *)&cmd, 1);
    
    rngBufPut(pI2C->i2c_wr, buffer, len);
    
    i2c_start_on_bus(pI2C->i2c_peri);

    while(!(i2c_cfg[index].xfer.flag & FLAG_STOP)){
        if(i2c_cfg[index].xfer.flag & FLAG_TIMEOUT){
            MUTEX_GIVE(pI2C->mutex);
            return ACK_SMBUS_TIMEOUT;
        }
    }
        
    i2c_stop_transfer(index);
    
    MUTEX_GIVE(pI2C->mutex);
    
    return ACK_OK;
}
ACK_STATUS SMBusBlockRW(unsigned int index, unsigned char slaveAddr, unsigned char cmd, unsigned char *rbuffer, unsigned int rlen, unsigned char *wbuffer, unsigned int wlen)
{
    int i=0;
    struct I2C_Config *pI2C = &i2c_cfg[index];

    while(i2c_flag_get(pI2C->i2c_peri, I2C_FLAG_I2CBSY) && (i++<SMBUS_TIMEOUT_US))udelay(1);
    
    if(i>=SMBUS_TIMEOUT_US)
        return ACK_SMBUS_TIMEOUT;  
    
    i2c_prepare_transfer(index);
    
    MUTEX_TAKE(pI2C->mutex);
    
    pI2C->xfer.mode = MODE_MASTER;
    
    pI2C->xfer.xfer_addr = slaveAddr;
    
    pI2C->xfer.direction = DIR_RDWR;
    //cmd+buffer
    pI2C->xfer.wr_len = 1+wlen;
    
    pI2C->xfer.rd_len = rlen;
    
    rngBufPut(pI2C->i2c_wr, (unsigned char *)&cmd, 1);
    
    rngBufPut(pI2C->i2c_wr, (unsigned char *)wbuffer, wlen);

    i2c_start_on_bus(pI2C->i2c_peri);

    //等待传输结束后取数据
    while(!(i2c_cfg[index].xfer.flag & FLAG_STOP)){
        if(i2c_cfg[index].xfer.flag & FLAG_TIMEOUT){
            MUTEX_GIVE(pI2C->mutex);
            return ACK_SMBUS_TIMEOUT;
        }
    }
    
    rngBufGet(pI2C->i2c_rd, rbuffer, rlen);
    
    i2c_stop_transfer(index);
    
    MUTEX_GIVE(pI2C->mutex);
    
    return ACK_OK;
}

参考:https://www.cnblogs.com/BitArt/archive/2013/05/28/3103917.html
参考: 《GD32E507用户手册》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值