Linux下的模拟i2c

       内核默认支持模拟i2c,那应该怎么用呢,参考i2c-gpio.txt « i2c « bindings « devicetree « Documentation - kernel/git/torvalds/linux.git - Linux kernel source tree   是不是跟平常用的硬件i2c dts配置很类似呢

aliases {
	i2c8 = &i2c8;
}

i2c8:i2c8 {
	compatible = "i2c-gpio";
	gpios = <&pio 23 0 /* sda */
		     &pio 24 0 /* scl */
		>;
	i2c-gpio,sda-open-drain;
	i2c-gpio,scl-open-drain;
	i2c-gpio,delay-us = <2>;	/* ~100 kHz */
	#address-cells = <1>;
	#size-cells = <0>;

	rv3029c2@56 {
		compatible = "rv3029c2";
		reg = <0x56>;
	};
};

       如果平台也有i2c8,需要将平台对应的i2c屏蔽掉,同时引脚配置成普通gpio模式,主要引脚还是要上拉哦。

       i2c8的应该根据实际的主板情况配置而来,因为系统可能默认有了i2c0,i2c1等,如果这里不指定第几条总线,系统原本的硬件i2c注册会有问题。 

同时加上

CONFIG_I2C_GPIO=y
CONFIG_I2C_ALGOBIT=y

i2c8 = &i2c8这个有什么作用呢,看pdeev->id默认是-1,然后获取i2c属性或者具体的总线。

#define PLATFORM_DEVID_NONE     (-1)
int of_device_add(struct platform_device *ofdev)
{
...
	ofdev->id = PLATFORM_DEVID_NONE;
...
}
static int i2c_gpio_probe(struct platform_device *pdev)
{
...
	adap->nr = pdev->id;
	ret = i2c_bit_add_numbered_bus(adap);
...
}

int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
...
	if (adap->nr == -1) /* -1 means dynamically assign bus id */
		return i2c_add_adapter(adap);
...
}

int i2c_add_adapter(struct i2c_adapter *adapter)
{
	struct device *dev = &adapter->dev;
	int id;

	if (dev->of_node) {
		id = of_alias_get_id(dev->of_node, "i2c");
		if (id >= 0) {
			adapter->nr = id;
			return __i2c_add_numbered_adapter(adapter);
		}
	}
...
}

drivers/i2c/busses/i2c-gpio.c 注册i2c总线

drivers/i2c/algos/i2c-algo-bit.c  实现模拟i2c协议

const struct i2c_algorithm i2c_bit_algo = {
	.master_xfer	= bit_xfer,
	.functionality	= bit_func,
};

static int __i2c_bit_add_bus(struct i2c_adapter *adap,int (*add_adapter)(struct i2c_adapter *))
{
	adap->algo = &i2c_bit_algo;
	ret = add_adapter(adap);
}

int i2c_bit_add_numbered_bus(struct i2c_adapter *adap)
{
	return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter);
}
EXPORT_SYMBOL(i2c_bit_add_numbered_bus);

使用平台的有点差异(sprd/mtk),要获取sda的电平,先要设置成输入状态,按如下修改

 static int i2c_gpio_getsda(void *data)
 {
        struct i2c_gpio_platform_data *pdata = data;
-
-       return gpio_get_value(pdata->sda_pin);
+       int state;
+       gpio_direction_input(pdata->sda_pin);
+       state=gpio_get_value(pdata->sda_pin);
+       gpio_direction_output(pdata->sda_pin,1);
+       return state;
 }

是不是瞬间就搞定了呢,i2c驱动用硬件的i2c驱动就行了。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在STM32中,可以通过GPIO模拟I2C总线,实现I2C通信的功能。GPIO模拟I2C总线的原理是使用GPIO口的开漏输出模式模拟I2C总线的SCL和SDA信号。 以下是实现GPIO模拟I2C总线的步骤: 1. 初始化GPIO口为开漏输出模式 ```c GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // 配置GPIO口的引脚 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 配置GPIO速度 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; // 配置为开漏输出模式 GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化GPIO口 ``` 在上面的代码中,我们将GPIOB的第6和第7个引脚配置为开漏输出模式,并且输出电平为高电平。 2. 实现I2C总线的Start信号 ```c void I2C_Start(void) { SDA_H; SCL_H; delay_us(4); SDA_L; delay_us(4); SCL_L; } ``` 在上面的代码中,我们首先将SDA和SCL信号线的输出电平都设置为高电平,然后将SDA信号线的电平拉低,等待一段时间后再将SCL信号线的电平拉低,即产生了I2C总线的Start信号。 3. 实现I2C总线的Stop信号 ```c void I2C_Stop(void) { SDA_L; delay_us(4); SCL_H; delay_us(4); SDA_H; delay_us(4); } ``` 在上面的代码中,我们将SDA信号线的电平拉低,等待一段时间后将SCL信号线的电平拉高,然后再将SDA信号线的电平拉高,即产生了I2C总线的Stop信号。 4. 实现I2C总线的数据传输 ```c bool I2C_WriteByte(uint8_t data) { uint8_t i; for(i=0; i<8; i++) { if(data & 0x80) { SDA_H; } else { SDA_L; } delay_us(4); SCL_H; delay_us(4); SCL_L; data <<= 1; } SDA_H; delay_us(4); SCL_H; delay_us(4); bool ack = SDA_Read(); SCL_L; delay_us(4); return ack; } uint8_t I2C_ReadByte(bool ack) { uint8_t i; uint8_t data = 0; SDA_H; for(i=0; i<8; i++) { data <<= 1; SCL_H; delay_us(4); if(SDA_Read()) { data |= 0x01; } SCL_L; delay_us(4); } if(ack) { SDA_L; } else { SDA_H; } SCL_H; delay_us(4); SCL_L; delay_us(4); return data; } ``` 在上面的代码中,我们使用了两个函数I2C_WriteByte和I2C_ReadByte来实现I2C总线的数据传输。其中,I2C_WriteByte函数用于向I2C总线发送一个字节的数据,I2C_ReadByte函数用于从I2C总线接收一个字节的数据。 在I2C_WriteByte函数中,我们首先将要发送的数据的每一位都依次写入SDA信号线,然后将SCL信号线的电平拉高,等待一段时间后再将其拉低,即完成了一次数据传输。在函数的最后,我们还需要接收从I2C设备发送的应答信号。 在I2C_ReadByte函数中,我们首先将SDA信号线的输出电平设置为高电平,然后依次接收从I2C设备发送的每一位数据,最后发送一个应答信号ack,用于告知I2C设备是否正确接收了数据。 需要注意的是,以上代码中的SDA_H、SDA_L、SCL_H、SCL_L和SDA_Read函数需要根据具体情况进行定义。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值