i2c学习笔记
本文将从以下三个方面进行:
- 概述i2c协议;
- linux i2c的软件框架与核心实现;
- 怎样编写i2c驱动;
- 用户态编程使用i2c驱动。
概述
I2C协议是嵌入式系统中广泛使用的一类通信协议,主要用于CPU和各种外设之间的低速数据通信。Linux kernel使用I2C framework抽象、管理相应的资源,并以各种形式,向各类使用者提供API。作为总线(bus)的一种,I2C framework的实现体现了linux设备模型的精髓,值得研究与学习。
I2C是一个能够支持多个设备的总线,包含一条双向串行数据线SDA,一条串行时钟线SCL。i2c支持三种速率模式, 普通模式:100kHz;快速模式:400kHz;高速模式:3.4MHz。
i2c协议
-
空闲状态
i2c总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。 -
起始位与停止位的定义
起始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。
停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。 -
数据发送与应答
在起始信号后,发送端发送8bit数据,接收端在第9个时钟发送ACK应答信号。
在SCL低电平时,SDA上的电平进行改变;在SCL高电平时,SDA上的电平状态必须保持稳定,接收端在SCL高电平时读取数据。 -
i2c读写时序
- i2c写数据时序
在起始信号后,主机发送一个7bit的从机地址和一个读写位(0:写,1:读),对应地址的从机发送一个ACK,主机开始写入8bit数据,从机ACK,结束信号。 - i2c读数据时序
在起始信号后,主机发送一个7bit的从机地址和一个读写位(0:写,1:读),对应地址的从机发送一个ACK,从机发送8bit数据,主机发送ACK,结束信号。
RTC-RX8010协议
rx8010指定寄存器写入时序:
- 主机发送起始信号
- 主机发送从机rx8010地址和读标志位
- rx8010发送ACK
- 主机发送欲写入的寄存器地址
- rx8010发送ACK
- 主机发送写入数据
- rx8010发送ACK
- [可选]继续写入数据可重复6、7步骤,寄存器地址会自动增加
- 主机发送停止信号
rx8010指定寄存器读取时序:
- 主机发送起始信号
- 主机发送从机rx8010地址和写标志位
- rx8010发送ACK
- 主机发送欲读取的寄存器地址
- rx8010发送ACK
- 主机发送起始信号(restart)
- 主机发送从机rx8010地址和读标志位
- rx8010发送寄存器数据
- 主机发送ACK则rx8010继续发送数据(寄存器自动增加),主机发送NACK则rx8010停止发送数据
- 主机发送停止信号
linux i2c驱动框架分析
linux i2c驱动的三个核心文件:
设备驱动:i2c-dev.c
提供用户接口(read、write等);
实现策略:知道发什么数据,但是不知道怎么发。
核心驱动:i2c-core.c
注册i2c总线;
给驱动编写提供接口。
总线驱动:i2c-xxx.c (xxx为对应的plat)
初始化硬件(i2c控制器);
实现操作方法:知道怎么发数据,不知道发什么数据。
i2c子系统开发-设备驱动设计的重要函数(linux/i2c.h)
数据接收与发送
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);
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总线驱动层