linux模拟i2c时延时函数,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();

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值