【驱动】06.IIC子系统
【嵌入式八股】一、语言篇https://www.nowcoder.com/creation/manager/columnDetail/mwQPeM
【嵌入式八股】二、计算机基础篇https://www.nowcoder.com/creation/manager/columnDetail/Mg5Lym
【嵌入式八股】三、硬件篇https://www.nowcoder.com/creation/manager/columnDetail/MRVDlM
【嵌入式八股】四、嵌入式Linux篇(本专栏)https://www.nowcoder.com/creation/manager/columnDetail/MQ2bb0
IIC子系统
硬件原理
IIC协议
看【硬件篇-接口协议】部分IIC相关
SMBUS协议
SMBus: System Management Bus,系统管理总线。 SMBus是基于I2C协议的,SMBus要求更严格,SMBus是I2C协议的子集。
应用编程
I2C-Tools的访问I2C设备的2种方式
官方留的应用层直接控制的接口
I2C-Tools可以通过SMBus来访问I2C设备,也可以使用一般的I2C协议来访问I2C设备。 使用一句话概括I2C传输:APP通过I2C Controller与I2C Device传输数据。 在APP里,有这几个问题:
- 怎么指定I2C控制器?
- i2c-dev.c提供为每个I2C控制器(I2C Bus、I2C Adapter)都生成一个设备节点:/dev/i2c-0、/dev/i2c-1等待
- open某个/dev/i2c-X节点,就是去访问该I2C控制器下的设备
- 怎么指定I2C设备?
- 通过ioctl指定I2C设备的地址
- ioctl(file, I2C_SLAVE, address)
- 如果该设备已经有了对应的设备驱动程序,则返回失败
- ioctl(file, I2C_SLAVE_FORCE, address)
- 如果该设备已经有了对应的设备驱动程序
- 但是还是想通过i2c-dev驱动来访问它
- 则使用这个ioctl来指定I2C设备地址
- 怎么传输数据?
- 两种方式
- 一般的I2C方式:ioctl(file, I2C_RDWR, &rdwr)
- SMBus方式:ioctl(file, I2C_SMBUS, &args)
使用GPIO模拟I2C的驱动程序
内核驱动
通用驱动i2c-dev分析
看看官方留的应用层直接控制的接口对应的驱动
i2c-dev.c注册过程分析
就是字符设备那一套
file_operations函数分析
i2cdev_ioctl: I2C_SLAVE/I2C_SLAVE_FORCE
用于传地址
i2cdev_ioctl: I2C_RDWR
读写方式1
i2cdev_ioctl: I2C_SMBUS
读写方式2
编写设备驱动之i2c_driver
编写设备驱动之i2c_client
问题:Linux IIC子系统设备树中没有写那个IIC adapter,驱动怎么对应上呢:question:
四种方法
1.在用户态生成
示例:
// 在I2C BUS0下创建i2c_client
# echo ap3216c 0x1e > /sys/bus/i2c/devices/i2c-0/new_device
// 删除i2c_client
# echo 0x1e > /sys/bus/i2c/devices/i2c-0/delete_device
2.编写代码
-
i2c_new_device:会创建i2c_client,即使该设备并不存在
static struct i2c_board_info sfe4001_hwmon_info = { I2C_BOARD_INFO("max6647", 0x4e), }; int sfe4001_init(struct efx_nic *efx) { (...) efx->board_info.hwmon_client =i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info); (...) }
-
i2c_new_probed_device
-
它成功的话,会创建i2c_client,并且表示这个设备肯定存在
-
I2C设备的地址可能发生变化,比如AT24C02的引脚A2A1A0电平不一样时,设备地址就不一样
-
可以罗列出可能的地址
-
i2c_new_probed_device使用这些地址判断设备是否存在
static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; static int usb_hcd_nxp_probe(struct platform_device *pdev) { (...) struct i2c_adapter *i2c_adap; struct i2c_board_info i2c_info; (...) i2c_adap = i2c_get_adapter(2); memset(&i2c_info, 0, sizeof(struct i2c_board_info)); strscpy(i2c_info.type, "isp1301_nxp", sizeof(i2c_info.type)); isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info, normal_i2c, NULL); i2c_put_adapter(i2c_adap); (...) }
-
-
i2c_register_board_info
- 内核没有
EXPORT_SYMBOL(i2c_register_board_info)
- 使用这个函数的驱动必须编进内核里去
- 内核没有
3.使用设备树生成
在某个I2C控制器的节点下,添加如下代码:
ap3216c@1e {
compatible = "lite-on,ap3216c";
reg = <0x1e>;
};
**4.(不推荐):由i2c_driver.detect函数来判断是否有对应的I2C设备并生成i2c_client **
I2C_Adapter驱动框架讲解与编写
它知道怎么发数据,不知道要发什么数据。要发的数据通过i2c_driver经ic_core过来
关心第几条IIC总线nr,IIC 算法i2c_algorithm,master_xfer函数
一般来说芯片厂商都写好了
master_xfer:这是最重要的函数,它实现了一般的I2C传输,用来传输一个或多个i2c_msg
编写i2c_adapter驱动程序
设备树
在设备树里构造I2C Bus节点:
i2c-bus-virtual {
compatible = "100ask,i2c-bus-virtual";
};
platform_driver
分配、设置、注册platform_driver结构体。
核心是probe函数,它要做这几件事:
- 根据设备树信息设置硬件(引脚、时钟等)
- 分配、设置、注册i2c_apdater
i2c_apdater
i2c_apdater核心是master_xfer函数,它的实现取决于硬件,大概代码如下:
static int xxx_master_xfer(struct i2c_adapter *adapter,
struct i2c_msg *msgs, int num)
{
for (i = 0; i < num; i++) {
struct i2c_msg *msg = msgs[i];
{
// 1. 发出S信号: 设置寄存器发出S信号
CTLREG = S;
// 2. 根据Flag发出设备地址和R/W位: 把这8位数据写入某个DATAREG即可发出信号
// 判断是否有ACK
if (!ACK)
return ERROR;
else {
// 3. read / write
if (read) {
STATUS = XXX; // 这决定读到一个数据后是否发出ACK给对方
val = DATAREG; // 这会发起I2C读操作
} else if(write) {
DATAREG = val; // 这会发起I2C写操作
val = STATUS; // 判断是否收到ACK
if (!ACK)
return ERROR;
}
}
// 4. 发出P信号
CTLREG = P;
}
}
return i;
}
具体芯片的I2C_Adapter驱动分析
总体框架
I2C驱动框架
对 IIC 总线的理解、调用函数以及常见面试问题 - AlanTu - 博客园 (cnblogs.com)
06-IIC子系统开发之设备驱动框架层功能分析_哔哩哔哩_bilibili
Linux定义了系统的IIC驱动体系结构,在Linux系统中,IIC驱动由3部分组成,即IIC核心、IIC总线驱动和IIC设备驱动。这3部分相互协作,形成了非常通用、可适应性很强的IIC框架。
I2C Core就是I2C核心层,它的作用:
- 提供统一的访问函数,比如i2c_transfer、i2c_smbus_xfer等
- 实现
I2C总线-设备-驱动模型
,管理:I2C设备(i2c_client)、I2C设备驱动(i2c_driver)、I2C控制器(i2c_adapter)
IIC子系统的重要结构体
先有个整体框架
APP
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
查阅整理上千份嵌入式面经,将相关资料汇集于此,主要包括: 0.简历面试 1.语言篇 2.计算机基础 3.硬件篇 4.嵌入式Linux【本专栏】 (建议PC端查看)