您的位置:首页 > 运维架构 > Linux

linux平台上GPIO模拟I2C

2011-05-30 12:31 381 查看
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   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[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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: