Linux GPIO 模拟I2C

I2C速率

NormalSpeed:100Kbps

Fast  Speed:          400Kbps

High  Speed: 3.5Mbps

I2C数据信号

Linux GPIO 模拟I2C_第1张图片

1、  空闲状态

I2C总线空闲时,SDA和SCL两条信号线同时处于高电平。

因此,通常I2C都会有外接上拉电阻,在I2C空闲时,SCL和SDA处于高电平状态。

这里空闲不是指睡眠状态,在睡眠状态SCLSDA是低电平的

2、  启动信号

SCL保持高电平,SDA从高到低变化;

Linux GPIO 模拟I2C_第2张图片

3、  停止信号

SCL保持高电平,SDA从低到高变化;

Linux GPIO 模拟I2C_第3张图片

4、  数据传送

读取SDA电平时,SCL保持高电平

SDA电平变化时,SCL保持低电平

Linux GPIO 模拟I2C_第4张图片

5、  应答信号

应答位,即ACK,I2C总线8位字节传送完成后,有接收器发送一个ACK信号。

即SCL在第9位时,SDA被接收器拉为低电平,发送器读取SDA为低电平时,即应答有效。

每传送一字节都需要应答信号。

Linux GPIO 模拟I2C_第5张图片

I2C数据传送

Linux GPIO 模拟I2C_第6张图片

1、  地址格式

I2C采用7位地址寻址,加上读写标志位。

所以通常slave address = slave chip address << 1;

2、  传送过程

启动信号Slave Address + R/W --> ACK --> Data --> ACK --> Data --> ACK -->*******--> 停止信号

示例代码

 代码:

//设置你自己的要配置的GPIO
#define SCL		GPIO_SCL
#define SDA		GPIO_SDA
#define DELAY     5
/* GPIO 初始化配置 */
/* I2C的gpio 如果外部有上拉电阻的话,就配置成None Pull,如果没有上拉电阻,就配置成Pull-UP */
void gpio_i2c_init(void)
{
	s3c_gpio_cfgpin(SCL, S3C_GPIO_INPUT);
	s3c_gpio_cfgpin(SDA, S3C_GPIO_INPUT);
	s3c_gpio_setpull(SCL, S3C_GPIO_PULL_UP);
	s3c_gpio_setpull(SDA, S3C_GPIO_PULL_UP);
	s5p_gpio_set_drvstr(SCL, S5P_GPIO_DRVSTR_LV4);
	s5p_gpio_set_drvstr(SDA, S5P_GPIO_DRVSTR_LV4);
}
/* 启动信号 */
void i2c_start(void)
{	  
	gpio_direction_output(SDA, 1);  
	gpio_direction_output(SCL, 1);
	udelay(DELAY);
	
	gpio_set_value(SDA, 0);
	udelay(DELAY);    
    	  
	gpio_set_value(SCL, 0);
	udelay(DELAY);
}
/* 停止信号 */
void i2c_stop(void)
{ 
	gpio_set_value(SCL, 0);
	gpio_set_value(SDA, 0);
	udelay(DELAY);
    
	gpio_set_value(SCL, 1);
	udelay(DELAY);
	gpio_set_value(SDA, 1);
	udelay(DELAY);
}
/* 发送ACK */
void i2c_send_ack(u8 ack)
{
	if(ack)
		gpio_direction_output(SDA, 1); 
	else 
		gpio_direction_output(SDA, 0);
	udelay(DELAY);
	
	gpio_set_value(SCL, 1);
   	udelay(DELAY);
   	
	gpio_set_value(SCL, 0);
	udelay(DELAY);	
}
/* 接收ACK */
u8 i2c_receive_ack(void)
{
	u8 rc = 0;
	
	gpio_direction_input(SDA);
	gpio_set_value(SCL, 1);
	udelay(DELAY);
	
	if(gpio_get_value(SDA)) {
		rc = 1;
	}
	gpio_set_value(SCL, 0);
	gpio_direction_output(SDA, 1);				
	return rc;
}

/* 发送字节 */
u8 i2c_send_byte(u8 send_byte)
{
	u8 rc = 0;
	u8 out_mask = 0x80;
	u8 value;
	u8 count = 8;
	while(count > 0) {                
		value = ((send_byte & out_mask) ? 1 : 0);   
		if (value == 1) {    					      		
			gpio_set_value(SDA, 1);     
		}    
		else {      					     	
			gpio_set_value(SDA, 0);
		}    
		udelay(DELAY);
		                          
		gpio_set_value(SCL, 1);   				    
		udelay(DELAY);
		             
		gpio_set_value(SCL, 0);     
		udelay(DELAY);
		          
		out_mask >>= 1;      
		count--;       
	}
	
	gpio_set_value(SDA, 1);  
	rc = i2c_receive_ack();
	return rc;
}
/* 发送字节 */
void i2c_read_byte(u8 *buffer, u8 ack)
{
	u8 count = 0x08;
	u8 data = 0x00;
	u8 temp = 0;
	
	gpio_direction_input(SDA); 
	while(count > 0) {
		gpio_set_value(SCL, 1);
		udelay(DELAY);
		temp = gpio_get_value(SDA);    	
		data <<= 1;
		if (temp)
			data |= 0x01;
		gpio_set_value(SCL, 0);
		udelay(DELAY);
		count--;
    }
	i2c_send_ack(ack);//0 = ACK    1 = NACK
	*buffer = data;			
}
/* 使用方法*/
static int gpio_i2c_read_data(struct i2c_client *client,
		u16 reg, u8 *values, u16 length)
{
	u8 *reg_u8;
	u8 rc;
	int i,j;
	reg_u8 = (u8 *)&reg;

	printk("gpio_i2c_read_data:length:%d\n",length);
	
	gpio_i2c_init();//初始化GPIO

	i2c_start();//启动信号
	rc = i2c_send_byte((client->addr << 1) | 0x00);//Slave Address 写数据
	if(rc) {
		printk("i2c_send_byte no ack 1\n");
		return -1;
	}	
	for(j = 0; j < 2; j++)	{
		rc = i2c_send_byte(reg_u8[j]);//发送data
		if(rc) {
			printk("i2c_send_byte no ack 2\n");
			return -1;
		}	
	}
	i2c_stop();//停止信号
	
	udelay(200);
	
	i2c_start();//启动信号
	rc = i2c_send_byte( (client->addr << 1) | 0x01 );//发送从机地址 读命令
	if(rc)	{
		printk("i2c_send_byte no ack 3\n");
		return -1;
	}
	for(i = 0; i < length; i++)	{
 		i2c_read_byte(values++, !(length - i -1));//读取数据
	}
	i2c_stop();//停止信号
	gpio_i2c_init();
	
	return length;
}


你可能感兴趣的:(Linux GPIO 模拟I2C)