微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 手机设计讨论 > MTK手机平台交流 > linux平台上GPIO模拟I2C

linux平台上GPIO模拟I2C

时间:10-02 整理:3721RD 点击:

      GPIO模拟I2C是嵌入式中较为常用的一种应用。各个地方有各种不同的做法,按照我自己的个人理解,最好是把I2C的各种状态分割开来,比如起始条件终止条件,读数据和写数据,然后根据具体的使用场合组合起来。

      这里需要注意两点:一是SCL的波形并不规律,不能将它理解为方波,它本身只是一段段独立的波形。二是每段操作时,之前和之后的SCL和SDA波形是可以忽略的;通常情况下I2C开始之前和I2C结束之后,两者都是有上拉的高电平,而在正常工作时两者不受控制的情况下都是默认低电平。三是I2C是要默认外部上拉的,但是不能有内部上拉也就是必须内部下拉,否则会出现I2C传输时的错误。

[cpp] view plaincopy

  • (1)基础宏定义  
  •   
  • #define GPIO_SCL             S3C2410_GPF3  
  • #define GPIO_SDA             S3C2410_GPF0  
  • #define GPIO_SDA_OUTP   S3C2410_GPF0_OUTP  //设定SDA输出  
  • #define GPIO_SDA_INP      S3C2410_GPF0_INP     //设定SDA输入  
  • #define GPIO_SCL_OUTP   S3C2410_GPF3_OUTP  //设定SCL输出  
  •   
  • void I2C_SCL_OUTP( void )  
  • {  
  •       s3c2410_gpio_cfgpin(GPIO_SCL,GPIO_SCL_OUTP);  
  • }  
  •   
  • void I2C_SCL_Output(u8 value)  
  • {  
  •       if(value)  
  •       {                                                  
  •             s3c2410_gpio_setpin(GPIO_SCL,value);   
  •       }  
  •       else  
  •       {  
  •             s3c2410_gpio_setpin(GPIO_SCL,value );   
  •       }   
  • }  
  •   
  •    
  •   
  • void I2C_SDA_Mode(u8 v_mode)   //SDA输出方向  
  • {  
  •        if(v_mode)  
  •        {                                                  
  •               s3c2410_gpio_cfgpin(GPIO_SDA, GPIO_SDA_OUTP);     
  •        }  
  •        else  
  •        {  
  •               s3c2410_gpio_cfgpin(GPIO_SDA, GPIO_SDA_INP);     
  •        }  
  • }  
  •   
  • void I2C_SDA_Output(u8 value)  
  • {  
  •        if(value)  
  •        {                                                  
  •                s3c2410_gpio_setpin(GPIO_SDA,value);   
  •        }  
  •        else  
  •        {  
  •                 s3c2410_gpio_setpin(GPIO_SDA,value );   
  •        }  
  • }  
  •   
  • u8 I2C_SDA_Read(void)    //SDA读数据  
  • {  
  •        return s3c2410_gpio_getpin(GPIO_SDA);   
  • }  
  •   
  • (2)基础段  
  •   
  • void I2C_Init(void)  
  • {   
  •       I2C_SDA_Output(1);  
  •       I2C_SCL_Output(1);      //默认拉高  
  • }  
  •   
  • void I2C_Wait(void)  
  • {  
  •       u16 i;  
  •       for(i=0;i<200;i++);  
  • }  
  •   
  • void I2C_Start(void)   
  • {  
  •       I2C_SDA_Output(1);  
  •       I2C_SCL_Output(1);  
  •       I2C_Wait();  
  •       I2C_SDA_Output(0);  
  •       I2C_Wait();  
  •       I2C_SCL_Output(0);  
  • }  
  • void I2C_Stop(void)   
  • {  
  •       I2C_SDA_Output(0);  
  •       I2C_Wait();  
  •       I2C_SCL_Output(1);  
  •       I2C_Wait();  
  •       I2C_SDA_Output(1);  
  • }  
  •   
  • (3)读写单个字节的段  
  •   
  • u8 I2C_Send_Byte(u8 bytedata)   
  • {  
  •       u8 i,ack;  
  •       I2C_SDA_Mode(1);  //SDA输出  
  •       I2C_SCL_OUTP();  
  •       for (i = 0; i < 8; i++)   
  •       {  
  •               if (bytedata & 0x80)   
  •               {  
  •                      I2C_SDA_Output(1);  
  •               }  
  •               else  
  •               {  
  •                     I2C_SDA_Output(0);  
  •               }  
  •               bytedata <<= 1;  
  •                
  •               I2C_SCL_Output(1);  
  •               udelay(3);  
  •               I2C_SCL_Output(0);  
  •               udelay(1);  
  •        }      
  •      
  •         I2C_SDA_Output(1);  //release  
  •         udelay(3);  
  •          
  •         I2C_SDA_Mode(0);  //设定SDA输入  
  •         I2C_SCL_Output(1);     
  •         udelay(3);  
  •         ack = I2C_SDA_Read();   //读应答  
  •         I2C_SDA_Mode(1);   
  •         I2C_SCL_Output(0);   
  •         udelay(3);  
  •          
  •         return ack;     
  • }  
  •   
  • u8 I2C_Receive_Byte(void)   
  • {  
  •        u8 i;  
  •        u8 bytedata = 0x00;  
  •        u8 temp;  
  •    
  •        I2C_SDA_Mode(0);   
  •        for ( i = 0; i < 8; i++)  
  •        {  
  •              I2C_SCL_Output(1);  
  •              udelay(3);  
  •   
  •    
  •   
  •              bytedata <<= 1;  
  •              temp = I2C_SDA_Read();   
  •              printk("reda SDA'value is:%d/n",temp);  
  •    
  •              if (temp)  
  •                    bytedata |= 0x01;   
  •              printk("  bytedata is:%x/n",bytedata);  
  •              I2C_SCL_Output(0);  
  •              udelay(1);  
  •        }  
  •        I2C_SDA_Mode(1);   
  •        return bytedata;  
  • }  
  •   
  • (4)读写单个字节的I2C应用函数  
  •   
  • u8 I2C_Byte_Write(u8 device_ID,u8 address,u8 bytedata)  
  • {     
  •        u8 ack;  
  •        printk("device_ID is:%x/n",device_ID);  
  •        printk("address is:%x/n",address);  
  •        printk("date is:%x/n",bytedata);  
  •        I2C_Start();   
  •        ack=I2C_Send_Byte(device_ID);  
  •        printk("ack is:%d/n",ack);  
  •        if(ack)   
  •   
  •              I2C_Stop();  
  •        I2C_Send_Byte(address);  
  •        I2C_Send_Byte(bytedata);  
  •        I2C_Stop();  
  •        I2C_Wait();   
  •        return 0;  
  • }  
  •   
  • u8 I2C_Byte_Read(u8 device_ID,u8 address)  
  • {     
  •        u8 bytedata;  
  •   
  •        I2C_Start();  
  •        I2C_Send_Byte(device_ID);  
  •        I2C_Send_Byte(address);  
  •        I2C_Start();  
  •        I2C_Send_Byte(device_ID+1);  
  •        bytedata = I2C_Receive_Byte();  //读单个字节,不需要再发应答  
  •        I2C_Stop();      
  •        return bytedata;  
  • }  
  •   
  • (5)类似可以完成读写多个字节的函数,暂不补充。  

==================================================================================================================================

==================================================================================================================================

第二种方式也可以用

[cpp] view plaincopy

  • #ifdef I2C_USE_GPIO  
  • #define GPIO_I2C_DEBUG  
  •   
  • #define GPIO_I2C_SDA_PIN   GPIO_I2C1_SCA_PIN  
  • #define GPIO_I2C_SCA_PIN   GPIO_I2C1_SDA_PIN  
  • #define GPIO_SDA_OUTP   mt_set_gpio_dir(GPIO_I2C_SDA_PIN,GPIO_DIR_OUT)  //设定SDA输出  
  • #define GPIO_SDA_INP      mt_set_gpio_dir(GPIO_I2C_SDA_PIN,GPIO_DIR_IN)     //设定SDA输入  
  • #define GPIO_SCL_OUTP   mt_set_gpio_dir(GPIO_I2C_SCA_PIN,GPIO_DIR_OUT)  //设定SCL输出  
  •   
  • #define I2C_SDA_Output(value)  mt_set_gpio_out(GPIO_I2C_SDA_PIN,value)  
  • #define I2C_SCL_Output(value)  mt_set_gpio_out(GPIO_I2C_SCA_PIN,value)  
  •   
  • #define DELAY_TIME   0xc0  
  •   
  • u8 I2C_SDA_Read(void)    //SDA读数据  
  • {  
  •        return mt_get_gpio_in(GPIO_I2C_SDA_PIN);   
  • }  
  •   
  •   
  • void I2C_Init(void)  
  • {   
  •     mt_set_gpio_mode(GPIO_I2C_SDA_PIN,GPIO_MODE_00);  
  •     mt_set_gpio_mode(GPIO_I2C_SCA_PIN,GPIO_MODE_00);  
  •   
  •     GPIO_SDA_OUTP;  
  •     GPIO_SCL_OUTP;  
  •       
  •       I2C_SDA_Output(1);  
  •       I2C_SCL_Output(1);      //默认拉高  
  • }  
  •   
  • #define I2C_START_TRANSMISSION \  
  •     { \  
  •         volatile u8 idx; \  
  •         GPIO_SCL_OUTP; \  
  •         GPIO_SDA_OUTP; \  
  •         I2C_SDA_Output(1); \  
  •         for (idx = 0; idx < DELAY_TIME; idx++); \  
  •         I2C_SCL_Output(1); \  
  •         for (idx = 0; idx < DELAY_TIME; idx++); \  
  •         I2C_SDA_Output(0); \  
  •         for (idx = 0; idx < DELAY_TIME; idx++); \  
  •         I2C_SCL_Output(0); \  
  •     }  
  •   
  •     #define I2C_STOP_TRANSMISSION \  
  •     { \  
  •         volatile u8 idx; \  
  •         GPIO_SCL_OUTP; \  
  •         GPIO_SDA_OUTP; \  
  •         I2C_SCL_Output(0); \  
  •         I2C_SDA_Output(0); \  
  •         for (idx = 0; idx < DELAY_TIME; idx++); \  
  •         I2C_SCL_Output(1); \  
  •         for (idx = 0; idx < DELAY_TIME; idx++); \  
  •         I2C_SDA_Output(1); \  
  •     }  
  •   
  • static kal_uint8 I2C_Send_Byte(kal_uint8 send_byte)  
  • {  
  •     volatile signed char i = 0;  
  •     volatile kal_uint16 j = 0;  
  •     kal_uint8 ack = 0;  
  •   
  •     for (i = 7; i >= 0; i--)  
  •     {  
  •         if (send_byte&(1 << i))  
  •         {  
  •             I2C_SDA_Output(1);  
  •         }  
  •         else  
  •         {  
  •             I2C_SDA_Output(0);  
  •         }  
  •         for (j = 0; j < DELAY_TIME; j++);  
  •         I2C_SCL_Output(1);  
  •         for (j = 0; j < DELAY_TIME; j++);  
  •         GPIO_SDA_OUTP; /* only for delay */  
  •         for (j = 0; j < DELAY_TIME; j++);  
  •         I2C_SCL_Output(0);  
  •         for (j = 0; j < DELAY_TIME; j++);  
  •     }  
  •     GPIO_SDA_INP;  
  •     for (j = 0; j < DELAY_TIME; j++);  
  •     I2C_SCL_Output(1);  
  •     for (j = 0; j < DELAY_TIME; j++);  
  •     ack = I2C_SDA_Read();  
  •     for (j = 0; j < DELAY_TIME; j++);  
  •     I2C_SCL_Output(0);  
  •     for (j = 0; j < DELAY_TIME; j++);  
  •     GPIO_SDA_OUTP;  
  •   
  •     return ack;  
  • }  
  •   
  •   
  • static kal_uint8 I2C_Receive_Byte(void)  
  • {  
  •     volatile signed char i = 0;  
  •     volatile kal_uint16 j = 0;  
  •     kal_uint8 get_byte = 0;  
  •   
  •     GPIO_SDA_INP;  
  •   
  •     for (j = 0; j < DELAY_TIME; j++);  
  •   
  •     for (i = 7; i >= 0; i--) {    // data bit 7~0  
  •         I2C_SCL_Output(1);  
  •         for (j = 0; j < DELAY_TIME; j++);  
  •         if (I2C_SDA_Read()) {  
  •             get_byte |= (1 << i);  
  •         }  
  •         for (j = 0; j < DELAY_TIME; j++);  
  •         I2C_SCL_Output(0);  
  •         for (j = 0; j < DELAY_TIME; j++);  
  •     }  
  •   
  •     // don't care bit, 9th bit  
  •     GPIO_SDA_OUTP;  
  •     I2C_SDA_Output(1);  
  •     for (j = 0; j < DELAY_TIME; j++);  
  •     I2C_SCL_Output(1);  
  •     for (j = 0; j < DELAY_TIME; j++);  
  •     I2C_SCL_Output(0);  
  •   
  •     return get_byte;  
  • }     
  •   
  •   
  •   
  • static kal_uint16 I2C_Receive_word(void)  
  • {  
  •     volatile signed char i = 0;  
  •     volatile kal_uint32 j = 0;  
  •     kal_uint16 get_byte = 0;  
  •   
  •     for (i = 15; i >= 8; i--)  
  •     {  
  •         GPIO_SDA_INP;  
  •         for (j = 0; j < DELAY_TIME; j++);  
  •         I2C_SCL_Output(1);  
  •         for (j = 0; j < DELAY_TIME; j++);  
  •         if (I2C_SDA_Read()) get_byte |= (1 << i);  
  •         for (j = 0; j < DELAY_TIME; j++);  
  •         I2C_SCL_Output(0);  
  •         for (j = 0; j < DELAY_TIME; j++);  
  •     }  
  •     I2C_SDA_Output(0);  
  •     GPIO_SDA_OUTP;  
  •     for (j = 0;j < DELAY_TIME; j++);  
  •     I2C_SCL_Output(1);  
  •     for (j = 0;j < DELAY_TIME; j++);  
  •     GPIO_SDA_OUTP; /* just for delay */  
  •     for (j = 0;j < DELAY_TIME; j++);  
  •     I2C_SCL_Output(0);  
  •     for (j = 0;j < DELAY_TIME; j++);  
  •     for (; i >= 0; i--)  
  •     {  
  •         GPIO_SDA_INP;  
  •         for (j = 0; j < DELAY_TIME; j++);  
  •         I2C_SCL_Output(1);  
  •         for (j = 0; j < DELAY_TIME; j++);  
  •         if (I2C_SDA_Read()) get_byte |= (1 << i);  
  •         for (j = 0; j < DELAY_TIME; j++);  
  •         I2C_SCL_Output(0);  
  •         for (j = 0; j < DELAY_TIME; j++);  
  •     }  
  •     I2C_SDA_Output(1);  
  •     GPIO_SDA_OUTP;  
  •     for (j = 0;j < DELAY_TIME; j++);  
  •     I2C_SCL_Output(1);  
  •     for (j = 0;j < DELAY_TIME; j++);  
  •     GPIO_SDA_OUTP; /* just for delay */  
  •     for (j = 0;j < DELAY_TIME; j++);  
  •     I2C_SCL_Output(0);  
  •     for (j = 0;j < DELAY_TIME; j++);  
  •   
  •     return get_byte;  
  • }  
  •   
  • u8 I2C_Byte_Write(u8 * a_puBuff , u8 len , u8 i2c_addr)  
  • {     
  •        kal_uint8 fail_try_no = 4;  
  •     volatile signed char i = 0 ;  
  •     u8 ack_flag = 0;  
  •     while (--fail_try_no > 0)  
  •     {  
  •         ack_flag = 0;  
  •         I2C_START_TRANSMISSION;  
  •         if (I2C_Send_Byte(i2c_addr)) continue;  
  •         for(i = 0 ;i < len;i++){  
  •             if (I2C_Send_Byte(a_puBuff)){  
  •                 ack_flag = 1;  
  •                 break;  
  •             }   
  •         }  
  •         if(ack_flag)  
  •             continue;  
  •         break;  
  •     }  
  •     I2C_STOP_TRANSMISSION;  
  •        return 0;  
  • }  
  •   
  • u8 I2C_Bytes_Read(u8 *a_puBuff, u8 reglen ,u8 *byteget,u8 bytelen,u8 i2c_addr)  
  • {     
  •   
  •     kal_uint16 get_byte = 0xFFFF;  
  •     kal_uint8 fail_try_no = 4;  
  •     volatile kal_uint32 i = 0;  
  •     u8 ack_flag = 0;  
  •   
  •     while (--fail_try_no > 0)  
  •     {  
  •         ack_flag = 0;  
  •         I2C_START_TRANSMISSION;  
  •         if (I2C_Send_Byte(i2c_addr)) continue;  
  •          
  •         //send reg  
  •            for(i = 0 ;i < reglen;i++){  
  •             if (I2C_Send_Byte(a_puBuff)){  
  •                 ack_flag = 1;  
  •                 break;  
  •             }   
  •         }  
  •         if(ack_flag)  
  •             continue;  
  •          
  •         I2C_START_TRANSMISSION;  
  •         if (I2C_Send_Byte(i2c_addr | 1)) continue;  
  •          
  •         if(bytelen == 1)  
  •             byteget[0] = get_byte = I2C_Receive_Byte();  //读单个字节,不需要再发应答  
  •         else if(bytelen > 1)  
  •         {  
  •             get_byte=I2C_Receive_word();  
  •              byteget[1] = get_byte & 0x00ff;  
  •              byteget[0] = (get_byte & 0xff00) >> 8;  
  •          }  
  •         break;  
  •     }  
  •     I2C_STOP_TRANSMISSION;  
  •   
  •     printk("----%s---read data %x---\n",__func__,get_byte);  
  •   
  •     return get_byte;  
  •   
  • }     
  •   
  • int iWriteRegI2C(u8 *a_pSendData , u16 a_sizeSendData, u16 i2cId)  
  • {  
  •     I2C_Byte_Write(a_pSendData,a_sizeSendData,i2cId);  
  •     return 0;  
  • }  
  •   
  • int iReadRegI2C(u8 *a_pSendData , u16 a_sizeSendData, u8 * a_pRecvData, u16 a_sizeRecvData, u16 i2cId)  
  • {  
  •     I2C_Bytes_Read(a_pSendData,a_sizeSendData,a_pRecvData,a_sizeRecvData,i2cId);  
  •      return 0;  
  • }  
  • #endif  

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top