Linux模拟i2c_demo

         一般相应的硬件都会连接到相应的硬件i2c上,但有时会用到模拟i2c(sda和scl引脚弄反,通

信异常,非标准i2c等),这里给出了相应的例子。

这里假设i2c的频率是100k(周期为10us),SCL对应的引脚号是pin11,SDA对应的引脚号是pin22,

#define   UDELAY          {udelay(5);}
#define   MDELAY          {mdelay(5);}
#define   SCL                  pin11
#define   SDA                  pin22
#define   ONE                  1
#define   ZERO                 0
#define   USESOFTIIC
typedef u8 u8;
static struct i2c_client *i2c_client;
static void i2c_start(void) { //起始信号 SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据
    gpio_set_value(SDA, 1);
    gpio_set_value(SCL, 1);
    UDELAY;
    gpio_set_value(SDA, 0);
    UDELAY;
    gpio_set_value(SCL, 0);

}

static void i2c_stop (void){//停止信号  SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据
    gpio_set_value(SDA, 0);
    gpio_set_value(SCL, 1);
    UDELAY;
    gpio_set_value(SDA, 1);
    UDELAY;
}

static void i2c_sendack(u8 ack){ //发送应答信号 入口参数:ack (0x0:ACK 0x01:NAK)
    if(ack)
    	gpio_set_value(SDA, 1);
    else
    	gpio_set_value(SDA, 0);
    gpio_set_value(SCL, 1);
    UDELAY;
    gpio_set_value(SCL, 0);
    UDELAY;
}

static  u8 i2c_recvack(void){//接收应答信号
    u8 cy;
    gpio_set_value(SDA, 1);
    UDELAY;
    gpio_direction_input(SDA);
    gpio_set_value(SCL, 1);
    UDELAY;
    cy=gpio_get_value(SDA);
    gpio_set_value(SCL, 0);
    UDELAY;
    gpio_direction_output(SDA,1);
    UDELAY;
    return cy;
}

static int i2c_sendbyte(u8 data){//向IIC总线发送一个字节数据
    u8 i;
    u8 ack;
    u8 cy[8];
    u8 bit;

    for (i=0; i<8; i){
	bit=data&0x80;
        if(bit)
		cy[i]=ONE;
        else
		cy[i]=ZERO;
        data<<=1;
    }
    for (i=0; i<8; i){
    	gpio_set_value(SDA,cy[i]);
    	gpio_set_value(SCL, 1);
        UDELAY;
        gpio_set_value(SCL, 0);
        UDELAY;
    }
    ack=i2c_recvack();
       return ack;
}

static u8 i2c_recvbyte(void){//从IIC总线接收一个字节数据
    u8 i;
    u8 dat = 0;

    gpio_set_value(SDA,1);
    gpio_direction_input(SDA);
    UDELAY;
    for (i=0; i<8; i){
        dat <<= 1;
        gpio_set_value(SCL, 1);
        UDELAY;
        dat |= gpio_get_value(SDA);
        gpio_set_value(SCL, 0);
        UDELAY;
    }
    gpio_direction_output(SDA,1);
    return dat;
}
static void i2c_init(void){
       int ret;
       ret = gpio_request(SDA, "I2C_SDA");
       ret = gpio_request(SCL, "I2C_SCL");
       gpio_direction_output(SCL, 1);
       gpio_direction_output(SDA, 1);
}

相应的读写寄存器接口

static int i2c_write_reg(u8 reg,u8 value){
       int ret1,ret2,ret3;
       i2c_start();
       ret1=i2c_sendbyte(i2c_client->addr<<1);
       ret2=i2c_sendbyte(reg);
       ret3=i2c_sendbyte(value);
       i2c_stop();
       if(ret1||ret2||ret3){
               pr_err("i2c_write error ret1=%d,ret2=%d,ret3=%d",ret1,ret2,ret3);
               return -ENXIO;
       }
       return 0;
}
static u8 i2c_read_reg(u8 reg){
       int ret1,ret2,ret3,ret4;
       i2c_start();
       ret1=i2c_sendbyte(i2c_client->addr<<1);
       ret2=i2c_sendbyte(reg);
       i2c_stop();
 
       i2c_start();
       ret3=i2c_sendbyte((i2c_client->addr<<1)+1);
       ret4=i2c_recvbyte();
       i2c_sendack(0x1);
       i2c_stop();
       if(ret1||ret2||ret3){
               pr_err("i2c_write error ret1=%d,ret2=%d,ret3=%d,ret4=%d",ret1,ret2,ret3,ret4);
               return -ENXIO;
       }
       return ret4;
}

一般我们都有硬件的i2c驱动,我们在probe函数里将i2c设备的信息保存下(i2c_client=client,

主要是获取从机地址),然后调用下i2c_init拉高i2c信号的电平,然后替换相应的读写接口,

就可以实现驱动了模拟和硬件i2c驱动兼容了。

static int xxxx_probe(struct i2c_client *client,const struct i2c_device_id *id){
	i2c_client=client;
	i2c_init();
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值