22_Linux 3.4.2 IIC驱动

22_Linux 3.4.2 IIC驱动

1、框架介绍

1.1、连接图

在这里插入图片描述

1.2、IIC读写操作原理

黑色->主到从、红色->从到主
写:1_START、2_设备地址(7位) | 方向(1位)、3_回应、4_数据(8位) | 回应、5_P(结束)
读:1_START、2_设备地址(7位) | 方向(1位)、3_回应、4_数据(8位) | 回应、5_数据 | 回应、6_P(结束)
方向:0->写 1->读
在这里插入图片描述
START:SCL保持高电平、SDA从高变低。
P(停止):SCL保持高电平、SDA从低变高。
主设备发出START信号之后,用9个CLK来传输8位数据
第9个CLK是回应信号ACK(SDA为低电平)。
SCL低电平时,SDA可以变化;SCL高电平时,SDA保持不变。

写操作:
在这里插入图片描述
读操作:
在这里插入图片描述

1.3、数据的双向传输

1 主设备发送时,从设备不发送:可以通过SCL区分
2 主设备发送时,从设备的“发送引脚”不影响数据发送,反之相同
发送引脚连接三极管如图:
ACK:SDA为低电平
A B SDA
0 0 1(由上拉电阻决定)
0 1 0
1 0 0
1 1 0
在这里插入图片描述
① 不影响SDA,不驱动三极管;②想输出高电平,不驱动;③想输出低电平,驱动
例:主——(8bit)—>从
① 前8个CLK
从设备不要影响,不驱动三极管
主设备决定数据
② 第9个CLK,由从设备决定数据
主设备不驱动三极管,SDA高
从设备决定数据:
SDA高:NO ACK
SDA低:ACK

1.4、2440的IIC控制器

1 设置IICCON来设置时钟
2 设置分频系数把时钟降低为想要的频率
3 设置IICSTAT发出START信号
4 将数据写入IICDS中,之后就自动的设置时钟、将数据通过SDA发送出去
5 第9个CLK来检查IICSTAT查询是否有ACK信号:
有ACK表示数据成功发出,继续发下一个数据:再次将数据写入IICDS中…
无表示数据发送失败
6 发完数据不想再发了,就设置IICSTAT来发送P信号停止发送
在这里插入图片描述
在这里插入图片描述
在第9个CLK发生中断,中断处理过程,SCL为低,谁都不能使用IIC:
① 对于写:
若无ACK:出错结束(发出P信号)
若有ACK:
若任有数据,写入IICDS,清中断
若无,结束
② 对于读:
回应一个ACK信号:
还想再读:清中断,启动传输
不想读了:结束
重点:发生IIC中断时,SCL被拉低。阻止继续使用IIC,清中断后才能继续使用。
S3C2440读写数据流程:
写(发送):
① IICDS = val
② 发完,产生中断,拉低SCL
③ 中断程序里,判断状态,IICDS = val,IIC继续工作②
读(接收):
① 发起传输,接收数据
② 产生中断,SCL被拉低
③ 中断程序中,判断,设置好之后,value= IICDS,IIC继续工作,继续接收新数据—>②

IIC控制器传输信号:
在这里插入图片描述
IIC传输原理:
在这里插入图片描述
主机发送地址时:
由于i2c设备不同,地址数量也不同。在1k2k都只有一页地址,4k有2页。。。
在这里插入图片描述
发送地址时:
P2 P1 P0表示不同的页数;A2 A1 A0为硬件引脚。
在这里插入图片描述
例如:AT24C02只有一个page,8位的地址可以访问到;
AT24C08有4个page,在Start信号之后,再发出设备地址时可以指定访问那一页。
在这里插入图片描述

1.5、字符设备驱动框架

在这里插入图片描述

1.6、IIC驱动框架

在这里插入图片描述

1.7、IIC总线设备驱动模型

在这里插入图片描述

2、框架编写代码

bus-drv-dev模型及写程序,设备的4种构建方法

2.1、定义一个i2c_board_info, 里面有:名字, 设备地址

	然后i2c_register_board_info(busnum, ...)   (把它们放入__i2c_board_list链表)
    			list_add_tail(&devinfo->list, &__i2c_board_list);
	链表何时使用:
	i2c_register_adapter > i2c_scan_static_board_info > i2c_new_device    				
	
    使用限制:必须在 i2c_register_adapter 之前 i2c_register_board_info
	所以:不适合我们动态加载insmod

2.2、直接i2c_new_device, i2c_new_probed_device

	1、i2c_new_device        : 认为设备肯定存在,地址50改为60
	
	2、i2c_new_probed_device :对于"已经识别出来的设备"(probed_device),才会创建("new")
i2c_new_probed_device
			probe(adap, addr_list[i])   /* 确定设备是否真实存在 */
			info->addr = addr_list[i];
			i2c_new_device(adap, info);

2.3、从用户空间创建设备

	创建设备
	echo at24c08 0x50 > /sys/class/i2c-adapter/i2c-0/new_device
	导致i2c_new_device被调用
	
	删除设备
	echo 0x50 > /sys/class/i2c-adapter/i2c-0/delete_device
	导致i2c_unregister_device

2.4、前面的3种方法都要事先确定适配器(I2C总线,I2C控制器)

如果我事先并不知道这个I2C设备在哪个适配器上,怎么办?去class表示的所有的适配器上查找,有上一些I2C设备的地址是一样,怎么继续分配它是哪一款?用detect函数。

static struct i2c_driver at24cxx_driver = {
	.class  = I2C_CLASS_HWMON, /* 表示去哪些适配器上找设备 */
	.driver	= {
		.name	= "100ask",
		.owner	= THIS_MODULE,
	},
	.probe		= at24cxx_probe,
	.remove		= __devexit_p(at24cxx_remove),
	.id_table	= at24cxx_id_table,
	.detect     = at24cxx_detect,  /* 用这个函数来检测设备确实存在 */
	.address_list	= addr_list,   /* 这些设备的地址 */
};

去"class表示的这一类"I2C适配器,用"detect函数"来确定能否找到"address_list里的设备",
如果能找到就调用i2c_new_device来注册i2c_client, 这会和i2c_driver的id_table比较,
如果匹配,调用probe。

i2c_add_driver	
	i2c_register_driver
		driver_register:
		a. at24cxx_driver放入i2c_bus_type的drv链表
		   并且从dev链表里取出能匹配的i2c_client并调用probe
		
		b. 对于每一个适配器,调用__process_new_driver
		   对于每一个适配器,调用它的函数确定address_list里的设备是否存在
		   如果存在,再调用detect进一步确定、设置,然后i2c_new_device
		/* Walk the adapters that are already present */
		i2c_for_each_dev(driver, __process_new_driver);
			__process_new_driver
				i2c_do_add_adapter
					/* Detect supported devices on that bus, and instantiate them */
					i2c_detect(adap, driver);
						for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
							err = i2c_detect_address(temp_client, driver);
										/* 判断这个设备是否存在:简单的发出S信号确定有ACK */
										if (!i2c_default_probe(adapter, addr))
											return 0;
										
										memset(&info, 0, sizeof(struct i2c_board_info));
										info.addr = addr;	
										
										// 设置info.type
										err = driver->detect(temp_client, &info);
										
										i2c_new_device

3、编写设备驱动

在这里插入图片描述

4、用户态直接访问

不自己写驱动直接访问
Device Drivers
I2C support
<*> I2C device interface

nfs 30000000 192.168.1.123:/work/nfs_root/uImage_i2c; bootm 30000000
在这里插入图片描述
i2c-dev已经把0x50这个设备在内核中使用了,再来装载的话就不会成功:
在这里插入图片描述

5、编写总线驱动程序

Device Drivers
I2C support
I2C Hardware Bus support
< > S3C2410 I2C Driver

nfs 30000000 192.168.1.123:/work/nfs_root/uImage_noi2cbus; bootm 30000000
在这里插入图片描述
测试:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值