i2c学习笔记

本文将从以下三个方面进行:

  1. 概述i2c协议;
  2. linux i2c的软件框架与核心实现;
  3. 怎样编写i2c驱动;
  4. 用户态编程使用i2c驱动。

概述

I2C协议是嵌入式系统中广泛使用的一类通信协议,主要用于CPU和各种外设之间的低速数据通信,如camera、eeprom、HDMI控制线等。
Linux kernel使用I2C framework抽象、管理相应的资源,并以各种形式,向各类使用者提供API。作为总线(bus)的一种,I2C framework的实现体现了linux设备模型的精髓,值得研究与学习。
I2C是一个能够支持多个设备的总线,包含一条双向串行数据线SDA,一条串行时钟线SCL。i2c支持三种速率模式, 普通模式:100kHz;快速模式:400kHz;高速模式:3.4MHz。
在这里插入图片描述

i2c协议

  1. 空闲状态
    i2c总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。

  2. 起始位与停止位的定义
    起始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。
    停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。
    在这里插入图片描述

  3. 数据发送与应答
    在起始信号后,发送端发送8bit数据,接收端在第9个时钟发送ACK应答信号。
    在这里插入图片描述
    在SCL低电平时,SDA上的电平进行改变;在SCL高电平时,SDA上的电平状态必须保持稳定,接收端在SCL高电平时读取数据。

  4. i2c读写时序

  • i2c写数据时序
    在起始信号后,主机发送一个7bit的从机地址和一个读写位(0:写,1:读),对应地址的从机发送一个ACK,主机开始写入8bit数据,从机ACK,结束信号。
    在这里插入图片描述
  • i2c读数据时序
    在起始信号后,主机发送一个7bit的从机地址和一个读写位(0:写,1:读),对应地址的从机发送一个ACK,从机发送8bit数据,主机发送ACK,结束信号。
    在这里插入图片描述

RTC-RX8010协议

rx8010指定寄存器写入时序:

  1. 主机发送起始信号
  2. 主机发送从机rx8010地址和读标志位
  3. rx8010发送ACK
  4. 主机发送欲写入的寄存器地址
  5. rx8010发送ACK
  6. 主机发送写入数据
  7. rx8010发送ACK
  8. [可选]继续写入数据可重复6、7步骤,寄存器地址会自动增加
  9. 主机发送停止信号

在这里插入图片描述
在这里插入图片描述

rx8010指定寄存器读取时序:

  1. 主机发送起始信号
  2. 主机发送从机rx8010地址和写标志位
  3. rx8010发送ACK
  4. 主机发送欲读取的寄存器地址
  5. rx8010发送ACK
  6. 主机发送起始信号(restart)
  7. 主机发送从机rx8010地址和读标志位
  8. rx8010发送寄存器数据
  9. 主机发送ACK则rx8010继续发送数据(寄存器自动增加),主机发送NACK则rx8010停止发送数据
  10. 主机发送停止信号
    在这里插入图片描述

linux i2c驱动框架分析

linux i2c驱动是一种基于总线的驱动,主要分为三个部分:设备驱动、核心层(总线驱动)、适配器驱动(设备)。
设备驱动:实现在driver/i2c/i2c-dev.c中,主要完成对应用提供write、read等接口,绑定client并传递给核心层。
核心层:又可称为总线层,定义在driver/i2c-core.c中,主要完成设备驱动与设备的绑定,提供通用的数据传输接口。linux系统提供,无需修改。
适配器层:又称控制器驱动层,定义在driver/busses,具体完成i2c控制器的驱动,实现发送数据的方法,创建client。SOC厂家提供,一般可无需修改,但是创建client需要设备信息,可通过mach-xxx.c或设备树提供。
在这里插入图片描述

i2c适配器层platform总线:

函数调用结构:
在这里插入图片描述

i2c驱动开发

将i2c核心层和适配器层编译进内核

在编译linux的.config文件或menuconfig中使能i2c总线编译。

make menuconfig
	Device Drivers
		I2C support	##--->i2c-core.c			
			I2C Hardware Bus support  
				xxx I2C Controller ##--->适配器层驱动                                                  

查看i2c总线是否编译加载:

ls /sys/bus/i2c
  devices  drivers  ##--->说明核心层(bus)已被加载
cat /sys/bus/i2c/devices/i2c-0/name
  xxxxx ##--->对应平台的i2c控制器platform设备,说明适配器层已被加载
ls /sys/bus/platform/drivers 
	xxxx_i2c ###--->对应i2c控制器platform驱动

重要数据结构与函数

数据结构

  1. struct i2c_driver
    表示是一个从设备的驱动。
{
/* Standard driver model interfaces */
int (*probe)(struct i2c_client *, const struct i2c_device_id *); 
int (*remove)(struct i2c_client *);
struct device_driver driver; ///<继承了父类
    const struct of_device_id *of_match_table; ///<用于做对比,设备树
const struct i2c_device_id *idtable; ///<用于做比对,非设备树
}

对应函数:

/*注册设备*/
int i2c_register_driver(struct module *owner, struct i2c_driver *driver);
/*注销设备*/

void i2c_del_driver(struct i2c_driver *driver);

2. `struct i2c_client`
表示一个从设备
```c
{
	unsigned short addr; ///<从设备地址,来自于设备树中<reg>
	char name[I2C_NAME_SIZE]; ///<用于和i2c driver进行匹配,来自于设备树中的compatible
	struct i2c_adapter *adapter; ///<指向所属的适配器
	struct device dev; ///<继承了父类
}
  1. struct i2c_adapter
    表示一个i2c控制器
{
const struct i2c_algorithm  *algo; ///<算法
	int (*master_xfer) (struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
struct device dev; ///<继承了父类,也会被加入i2c bus
int nr; ///<编号,如i2c-2 中的2
}
  1. struct i2c_msg
    表示一个i2c消息
{
struct addr; ///<从设备地址
struct flag; ///<读、写标志,发送数据类型标志,如10bit地址、16bit寄存器模式等
__u16 len; ///<消息长度
__u8 *buf;///< 消息数据地址
}

发送\接收信息函数:

int i2c_master_send(const struct i2c_client *client, const char *buf, int count);
int i2c_master_recv(const struct i2c_client *client, char *buf, int count);
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);

i2c子系统开发-设备驱动设计的重要函数(linux/i2c.h)

数据接收与发送

int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned n);

适配器增加与删除

int i2c_add_adapter(struct i2c_adapter *);
void i2c_del_adapter(struct i2c_adapter *);
int i2c_add_numbered_adapter(struct i2c_adapter *);

驱动注册与删除

int i2c_register_driver(struct module *, struct i2c_driver *);
void i2c_del_driver(struct i2c_driver *);

设备增加与注销

i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);

void i2c_unregister_device(struct i2c_client *);

i2c总线驱动层

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值