回顾:
I2C总线:
概念:两线式串行总线
SDA
SCL
一个时钟周期传输一个bit位
画简易的连接图
问:CPU如何访问I2C总线上的某个外设?
问:CPU如何通过I2C总线实现与外设进行数据交互?
问:SDA与SCL之间如何配合?
答:I2C总线协议上
START信号:
STOP信号:
设备地址:
读写信号:
ACk信号:
数据交互以AT24C02读写为例:
SCL为低电平,数据线上的数据可以进行改变;
SCL为高电平,数据线的数据保持稳定;
linux内核I2C驱动框架
这里写链接内容
软件内容:
I2C设备驱动:
管理的硬件:I2C外设本身;不管理I2C硬件控制器;关注用户要进行操作的数据特定含义(片内地址、片内数据)
不关注这些数据如何通过I2C控制器进行数据传输!
利用内核提供的SMBUS接口将数据丢给I2C总线驱动,由I2C总线驱动来实现硬件的传输!
SMBUS接口:
由内核来实现:
一组内核函数;
供I2C设备驱动使用,用于将数据丢给I2C总线驱动;
本质就是I2C设备驱动和I2C总线驱动的数据交互桥梁
I2C总线驱动:
管理硬件:I2C控制器
关注数据如何通过I2C总线进行传输;不关注传输的数据的特定含义
总结:利用内核的I2C驱动框架来实现驱动,重点关注I2C设备驱动的实现过程;
I2C设备驱动实现过程:
采用内核分离思想,采用设备-总线-驱动模型;
围绕着struct i2c_client (装载硬件信息)和struct i2c_driver(装载软件信息)!
struct i2c_client的使用:
1,驱动不会直接对struct i2c_client进行分配初始化和注册
2,需要通过struct i2c_board_info对接struct i2c_client进行操作!
struct i2c_board_info的使用:
1,分配初始化
struct i2c_board_info at24c02[] = {
.type = “at24c02”,//用于匹配
.addr = 0x30,//设备地址
.platform_data//装载自定义的其他硬件
.irq = 中断号
}
2,注册
i2c_register_board_info(i2c外设所在的总线编号,at24c02,ARRAY_SIZE(at24c02));
3,注意:
以上 i2c_board_info的分配初始化和注册一律在平台代码中完成;必须以静态形式编译到内核中!一旦完成 i2c_board_info的分配初始化和注册,内核会帮你分配初始化和注册i2c_client!
struct i2c_driver如何使用?
struct i2c_driver{
int (*probe)(struct i2c_client *client,const struct i2c_device_id *id);
int (remove)(struct i2c_client );
const struct i2c_device_id *id_talbe;
}
作用:用于描述和装载软件信息
成员:
probe接口:软件和硬件一旦匹配成功,内核调用些函数
形参client,指向匹配成功的硬件节点i2c_client,所以可以通过这个指针来获取 I2C外设的设备地址client->adr;
remove接口:卸载软件节点,内核调用
形参client,指向匹配成功的硬件节点i2c_client,所以可以通过这个指针来获取 I2C外设的设备地址client->adr;
id_talbe:关键利用其中的name字段,这个字段用于匹配!
使用步骤:
1,分配初始化i2c_driver软件节点对象
static struct i2c_driver at2402_drv = {
.driver = {
.name = “tarena” //不重要,不是靠他来匹配的
}
.probe = at24c02_probe,
.remove = at24c02_remove,
.id_table = …
}
2,注册软件节点的drv链表,进行匹配
i2c_add_driver(&at24c02_drv);
3,卸载
i2c_del_driver(&at24c02_drv);
4,注意:i2c_driver可以动态加载!
5,probe函数是否被成功调用,预示着i2c设备驱动的完整性!!
案例:利用I2C驱动框架来实现AT24C02的设备驱动!!
mach-cw210.c已经完成对i2c_board_info的分配初始化和注册,也就是完成了对i2c_client的分配初始化和注册。
了解DS18B20的硬件特性:
每一个DS18B20内部都集成了一个64bit的ROM,存储唯一的序列号,表示设备唯一!
DS18B20转换:将温度模拟信息转换成温度的数字信号,将模拟量转成数字量(给CPU使用)
内部集成了9个字节的RAM:
byte0:存放温度值的低字节
byte1:存放温度值的高字节
….
byte0,byte1认为是存放温度值的寄存器
总结:对应每一个bit位的温度模拟量的值为1/16 = 0.0625摄氏度,例如如果读取到byte0,byte1的值为0000 0000 1010 0010 = 0x00A2,那么这个数字量对应的实际温度值 = 0x00A2*0.0625 = 10.125摄氏度
如果CPU要想获取DS18B20实际采集的温度值,实际CPU是读取DS18B20内部的byte0和byte1的值即可!
问题:CPU如何通过一根数据线读取内部内存的byte0和byte1中的数据呢?
答:
通过芯片手册可知,DS18B20访问遵循三个步骤:
1,CPU发送初始化复位信号
2,CPU发送ROM命令
3,CPU发送功能性命令
问:CPU如何发送初始化复位信号?
答:
1,配置GPIO为输出,输出0
2,udelay(500)
3,配置GPIO为输入口
4,udelay(30)
5,获取GPIO的状态
问:CPU如何发送ROM命令?
SKIP ROM命令:如果总线上只有一个设备,就无需做设备的匹配工作,直接跳过匹配,命令字为0xCC!
总结:CPU发送ROM命令,其实就是CPU通过一根数据线发送命令字,例如0xCC(1100,1100),这个是先发低位而I2C是先高位!!!!
问:CPU如何通过一个数据线把1,0发送给设备,并且保证设备接收到1,0这些数据呢?
1:32 P