Linux系统驱动(十七)IIC总线驱动

一、IIC总线

管脚输出模式:开漏模式

两根线:SCL串行时钟线、SDA串行数据线

信号:
起始信号:SCL高电平期间,SDA产生一个下降沿
结束信号:SCL高电平期间,SDA产生一个上升沿
非应答信号:在第九个时钟周期SDA是高电平
应答信号:在第九个时钟周期SDA是低电平

读写协议:

速率问题:
100KHz(低速) 400KHz(全速) 3.4MHz(高速)
本次使用的开发板:
100KHz(低速) 400KHz(全速) 1MHz(快速)
控制器支持最大速率1M,但是从机不一定支持

特点:
同步,串行,具有应答机制的半双工的总线协议

  • 注:从机地址7、8、10位
  • 寄存器有可能8位和16位(高8位在前应答、低8位在后应答)
    IIC控制器和模拟IIC

IIC在多主机多从机通信时,如果设置为推挽,可能会出现短路
外接上拉电阻还可以提高外围驱动能力,因为电路板的电流非常微弱

输入 上拉输入 下拉输入 模拟输入
推挽输出 开漏输出 复用推挽 复用开漏

二、IIC子系统

在这里插入图片描述
核心层
linux5.10.61/drivers/i2c/
在这里插入图片描述
总线驱动层
linux5.10.61/drivers/i2c/bussess----该目录下是各厂商的总线驱动层
在这里插入图片描述
如果在该目录下没有找到与自己板子匹配的文件,可以使用grep命令寻找与自己板子相关的内容在那个文件中
-n 显示行号
-R 递归地读取每个目录下的所有文件,并且会跟随所有的符号链接
在这里插入图片描述
可以看出应该打开 i2c-stm32f7.c 文件
在这里插入图片描述

(一)将总线驱动和核心层选配到内核中

1.配置总线驱动:make menuconfig

-> Device Drivers
 -> I2C support     
  -> I2C Hardware Bus support    
   <*>STMicroelectronics STM32F7 I2C support
2.配置核心层驱动:make menuconfig

-> Device Drivers
 -> I2C support     
  -*- I2C support  

(二)IIC设备驱动的API

1.分配并初始化对象
 struct i2c_driver {
        int (*probe)(struct i2c_client *client, const struct i2c_device_id *id);
        //匹配成功执行的函数
        int (*remove)(struct i2c_client *client);
        //分离的时候执行的函数
        struct device_driver driver;
        //父类
        const struct i2c_device_id *id_table;
        //1.idtable匹配方式
    }
 struct device_driver {
        const char  *name; //name在i2c驱动中不能用于匹配了,但是必须填充
        const struct of_device_id *of_match_table; //2.设备树匹配方式
    }
2.注册
 #define i2c_add_driver(driver) \
  i2c_register_driver(THIS_MODULE, driver)
3.注销
 void i2c_del_driver(struct i2c_driver *driver);
4.一键注册注销的宏
 module_i2c_driver(变量名);

IIC只有两种匹配方式,idtable和设备树匹配,name在IIC中不能用于匹配,但是必须填充

(三)IIC驱动代码示例

#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>

int si7006_probe(struct i2c_client *client, 
    const struct i2c_device_id *id)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
int si7006_remove(struct i2c_client *client)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

struct of_device_id oftable[] = {
    { .compatible = "hqyj,si7006" },
    { }
};
struct i2c_driver si7006 = {
    .probe = si7006_probe,
    .remove = si7006_remove,
    .driver = {
        .name = "si7006",
        .of_match_table = oftable,
    } 
};
module_i2c_driver(si7006);
MODULE_LICENSE("GPL");

(四)设备树节点

在这里插入图片描述

i2c1: i2c@40012000 {
	compatible = "st,stm32mp15-i2c";
	reg = <0x40012000 0x400>;
	interrupt-names = "event", "error";
	interrupts-extended = <&exti 21 IRQ_TYPE_LEVEL_HIGH>,
			      <&intc GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&rcc I2C1_K>;
	resets = <&rcc I2C1_R>;
	#address-cells = <1>;//2.#号开头对子节点成员的修饰
	#size-cells = <0>;
	dmas = <&dmamux1 33 0x400 0x80000001>,
	       <&dmamux1 34 0x400 0x80000001>;
	dma-names = "rx", "tx";
	power-domains = <&pd_core>;
	st,syscfg-fmp = <&syscfg 0x4 0x1>;
	wakeup-source;
	i2c-analog-filter;
	status = "disabled";  //1.控制器是否使能
};

1. 检查IIC是否使能

在这里插入图片描述
cd /proc/device-tree/soc/i2c/

2. 查看帮助文档编写自己的设备树节点

在这里插入图片描述

  • 注:一般管脚休眠状态一般将其设置为anlog模拟输入状态,使其处于低功耗状态

在这里插入图片描述

在这里插入图片描述

  • 注:描述子节点信息就将属性写在子节点中
&i2c1{
    pinctrl-names  = "default","sleep";
    pinctrl-0   = <&i2c1_pins_b>;      //设置default工作状态的管脚复用
    pinctrl-1   = <&i2c1_sleep_pins_b>; //设置sleep休眠状态管脚复用
    clock-frequency = <400000>;     //指定i2c总线速率为400k,缺省值就是100K
    i2c-scl-rising-time-ns = <185>; //scl上升沿的时间
    i2c-scl-falling-time-ns = <20>; //scl下降沿的时间
 status = "okay"; //将控制器使能
    si7006@40{
        compatible = "hqyj,si7006"; //和驱动匹配的字符串
        reg = <0x40>; //从机地址
    };
};
  • 注:总线驱动层将设备树中的属性进行解析

(五)消息的封装和发送

1. 消息封装和发送结构体

(1)i2c_client结构体

,drives由该结构体描述,即该结构体继承于drives
当i2c的驱动和设备树匹配成功时会创建i2c_client结构体,并将i2c_client结构体变量的地址传递给了probe函数。

struct i2c_client{
(2)i2c_msg结构体

消息结构体,总线驱动和设备驱动传输数据的格式。


2. 消息结构体封装

根据协议

有多少个起始信号就有多少个消息,消息的长度以字节来表示

3. 消息结构体的发送

i2c_transfer

4. 读写的函数封装

三、代码示例

(一)读取电子串号和固件版本号


(二)读取温湿度

在这里插入图片描述

  • 注:内核空间不允许浮点运算,因此读取到数据后需要将其在用户空间转换

  • 注:IIC控制si7006设备包含几个部分:

  • 管脚复用

  • 时钟频率

  • 从机地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值