linux平台上GPIO模拟I2C

来源:互联网 发布:网络机顶盒软件2017 编辑:程序博客网 时间:2024/05/21 10:48
      GPIO模拟I2C是嵌入式中较为常用的一种应用。各个地方有各种不同的做法,按照我自己的个人理解,最好是把I2C的各种状态分割开来,比如起始条件终止条件,读数据和写数据,然后根据具体的使用场合组合起来。

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

(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)类似可以完成读写多个字节的函数,暂不补充。

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

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

第二种方式也可以用

#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   0xc0u8 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~0I2C_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 bitGPIO_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[i])){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[i])){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


原创粉丝点击