I2C设备驱动

合集下载

51单片机的I2C底层驱动程序(IO口模拟)

51单片机的I2C底层驱动程序(IO口模拟)

51单片机的I2C底层驱动程序(IO口模拟)/*Title:I2C for 80C51Author:yuyouliang51单片机(本人使用STC89C52单片机,12T模式)的I2C驱动程序,使用逻辑分析仪对该协议进行分析,发现波形比较美观,SCL 的频率在70KHz左右(11.0592M晶振),低于标准的100K,可以适应大多数的I2C器件。

如果感觉速度过快或过慢,可以自行修改延时。

希望可以给读者一个参考,给读者一些帮助!*//*i2c.h文件 */#ifndef __I2C_H_#define __I2C_H_sbit SCL = P2^1;sbit SDA = P2^0;void start_i2c(); //启动I2C总线:SCL高电平期间,SDA由高变低void stop_i2c(); //停止I2C总线:SCL高电平期间,SDA由低变高void send_i2c(unsigned char c); //主机发送一个字节,先发送最高位unsigned char receive_i2c(); //主机接收一个字节,先接收最高位void master_ack(bit ack); //主机非应答信号(填参数0)或应答信号(填参数1)void slave_ack(); //等待从机应答信号#endif/* i2c.c文件 */#include#include#include#define nop() _nop_()void start_i2c() //启动I2C总线:SCL高电平期间,SDA由高变低{SDA=1;SCL=1;nop();nop();nop();nop();SDA=0;SCL=0;}void stop_i2c() //停止I2C总线,SCL高电平期间,SDA由低变高{SDA=0;SCL=1;nop();nop();nop();nop();SDA=1;}void slave_ack() //等待从机应答信号,如果从机迟迟没有应答,则结束总线。

Linux下I2C驱动介绍

Linux下I2C驱动介绍

1、I2C概述I2C是philips公司提供的外设总线,I2C有两条数据线,一条是串行数据线SDA、一条是时钟线SCL,使用SDA和SCL实现了数据的交换,便于布线。

I2C总线方便用在EEPROM、实时钟、小型LCD等与CPU外部的接口上。

2、Linux下的驱动思路Linux系统下编写I2c驱动主要有两种方法:一种是把I2C当做普通字符设备来使用;另一种利用Linux下驱动的体系结构来实现。

第一种方法:优点:思路比较直接,不用花费大量时间去了解Linux系统下I2C体系结构缺点:不仅对I2C设备操作要了解,还有了解I2C的适配器操作不仅对I2C设备器和设备操作需要了解,编写的驱动移植性差,内核提供的I2C设备器都没有用上。

第二种方法:第一种的优点就是第二种的缺点,第一种的缺点就是第二种的优点。

3、I2C框架概述Linux的I2C体系结构分为3部分:1)I2C核心I2C核心提供了I2C总线驱动和设备驱动的注册和注销的方法,I2C 通信方法(algorithm)上层,与具体适配器无关的代码,检测设备上层的代码等。

2)I2C总线驱动I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可以直接受CPU来控制。

3)I2C设备驱动I2C设备驱动是对I2C硬件体系结构中设备端的实现,设备端挂在受CPU控制的适配器上,通过I2C适配器与CPU交换数据。

Linux下的I2C体系结构:1)Linux下的I2C体系结构4、I2C设备驱动编写方法首先让我们明白适配器驱动的作用是让我们能够通过它发出标准的I2C时序,在linux内核源代码中driver/I2C/buss包含一些适配器的驱动,例如s3c2410的驱动I2C-s3c2410.c,适配器被加载到内核中,接下的任务就是实现设备驱动的编写。

编写设备驱动的方法主要分为两种方法:第一种:利用设备提供的I2C-dev.c来实现I2C适配器设备文件,然后通过上层应用程序来操作I2C设备器来控制I2C设备。

详细讲解RT-Thread I2C设备驱动框架及相关函数

详细讲解RT-Thread I2C设备驱动框架及相关函数

详细讲解RT-Thread I2C设备驱动框架及相关函数本应用笔记以驱动I2C接口的6轴传感器MPU6050为例,说明了如何使用I2C设备驱动接口开发应用程序,并详细讲解了RT-Thread I2C设备驱动框架及相关函数。

1 本文的目的和结构1.1 本文的目的和背景I2C(或写作i2c、IIC、iic)总线是由Philips公司开发的一种简单、双向二线制(时钟SCL、数据SDA)同步串行总线。

它只需要两根线即可在连接于总线上的器件之间传送信息,是半导体芯片使用最为广泛的通信接口之一。

RT-Thread中引入了I2C设备驱动框架,I2C 设备驱动框架提供了基于GPIO模拟和硬件控制器的2种底层硬件接口。

1.2 本文的结构本文首先描述了RT-Thread I2C设备驱动框架的基本情况,然后详细描述了I2C设备驱动接口,并使用I2C设备驱动接口编写MPU6050的驱动程序,并给出了在正点原子STM32F4探索者开发板上验证的代码示例。

2 I2C设备驱动框架简介在使用MCU进行项目开发的时候,往往需要用到I2C总线。

一般来说,MCU带有I2C 控制器(硬件I2C),也可以使用MCU的2个GPIO自行编写程序模拟I2C总线协议实现同样的功能。

RT-Thread提供了一套I/O设备管理框架,它把I/O设备分成了三层进行处理:应用层、I/O 设备管理层、底层驱动。

I/O设备管理框架给上层应用提供了统一的设备操作接口和I2C 设备驱动接口,给下层提供的是底层驱动接口。

应用程序通过I/O设备模块提供的标准接口访问底层设备,底层设备的变更不会对上层应用产生影响,这种方式使得应用程序具有很好的可移植性,应用程序可以很方便的从一个MCU移植到另外一个MCU。

本文以6轴惯性传感器MPU6050为例,使用RT-Thread I2C设备驱动框架提供的GPIO模拟I2C控制器的方式,阐述了应用程序如何使用I2C设备驱动接口访问I2C设备。

i2c_rtc_rx8025驱动总结

i2c_rtc_rx8025驱动总结

ARM : at91-sam9x5ekLinux内核:linux-2.6.39时钟芯片:rx8025 SA/NB第一种方法:Rx8025驱动程序在该linux内核中已经包含,路径为:drivers/rtc/rtc-rx8025.c所以在内核中增加驱动只需要配置即可:1.执行make ARCH=arm menuconfig 进入菜单选项,选择RTC配置,选中EPSONRX-8025SA/NB,同时一定要去掉cpu自带的时钟。

2.i2c support 需要选中I2C Hardware Bus support中GPIO-based bitbanging I2C,否则,即使rtc驱动正确,也不能使用,提示:drivers/rtc/hctosys.c: unable to open rtc device (rtc0)。

问题源自,驱动配置正确,I2C驱动没有加载正确,udevd不能创建rtc0设备节点3.在arch/arm/mach-at91/board-sam9x5ek.c中添加信息,注意此处的name名称要与驱动程序中id_table中的名称保持一致。

而在linux某些匹配机制中,设备名称是与驱动名称相一致。

如果名称不能正确匹配,系统是不会执行probe函数的。

另外需要注意的是i2c地址,手册上给出的地址一般都是带有读写位的,而程序中的地址需要把最后一位的读写位去掉,取前面的7位。

Rx8025的地址为0x64,相应的程序中的地址应该为0x32。

否则会提示对寄存器的操作失败。

4.驱动正确配置后,生成相应的文件/dev/i2c-0/dev/rtc0/sys/bus/i2c/drivers/rtc-rx8025/sys/bus/i2c/drivers/0-0032。

I2C设备与驱动的关联

I2C设备与驱动的关联

I2C设备与驱动的关联作者:leeoo 联系方式:neu_linuxer@在Linux操作系统中,驱动程序的加载分为两种:内核启动时自动加载和用户手动加载;硬件设备也可以采用两种方式添加到系统中:在系统启动前及系统运行时的热插拨。

下面,我们以arm体系结构下的at91处理器中的I2C控制器为例,介绍一下硬件设备及相关的驱动程序是如何绑定及松绑的。

1.平台驱动注册过程1.1 at91_i2c_init()函数在文件drivers/i2c/busses/i2c-at91.c中,定义了结构体struct platform_driver并进行了初始化,通过使用module_init()宏进行声明,当模块被加载到内核时会调用 at91_i2c_init()函数。

在此函数中,调用了platform_driver_register()函数来完成注册。

static struct platform_driver at91_i2c_driver = {.probe = at91_i2c_probe,.remove = __devexit_p(at91_i2c_remove),.suspend = at91_i2c_suspend,.resume = at91_i2c_resume,.driver = {.name = "at91_i2c",.owner = THIS_MODULE,},};static int __init at91_i2c_init(void){return platform_driver_register(&at91_i2c_driver);}1.2 platform_driver_register()函数在文件drivers/base/platform.c中,实现并导出了platform_driver_register()函数,以便使其他模块中的函数可以调用此函数。

i2c驱动传入probe的参数解释

i2c驱动传入probe的参数解释

I2C驱动传入probe的参数解释在进行I2C设备的驱动开发过程中,常常会涉及到I2C驱动的probe 函数。

probe函数是Linux内核驱动中的一种特殊函数,它在驱动被加载并且设备被检测到时被调用,用于初始化设备并注册设备驱动。

在编写I2C驱动的probe函数时,通常需要传入不同的参数进行配置和初始化。

本文将对I2C驱动传入probe的参数进行解释和说明,帮助读者更好地理解和使用I2C设备驱动。

1. struct i2c_client *client在I2C驱动的probe函数中,通常需要传入一个指向structi2c_client结构体的指针作为参数。

这个结构体是I2C设备在内核中的表示,包含了I2C设备的位置区域、总线信息、驱动信息等。

通过这个参数,我们可以获取I2C设备的各种信息,并进行相应的初始化和配置。

2. const struct i2c_device_id *id另一个常见的参数是一个指向const struct i2c_device_id结构体的指针,用于指定要注册的设备驱动的ID信息。

这个结构体中通常包含了设备的厂商ID、设备类型、设备名称等信息,用于匹配加载指定的设备驱动。

在probe函数中,我们可以使用这个参数来判断当前检测到的I2C设备是否匹配当前的驱动,从而进行相应的初始化和注册操作。

3. int (*probe)(struct i2c_client *client, const struct i2c_device_id *id)最后一个重要的参数是probe函数本身。

这个参数是一个函数指针,用于指定实际的probe函数的位置区域。

在probe函数中,我们可以根据传入的client和id参数,进行设备的初始化、资源的申请、注册设备驱动等操作。

通过这个函数指针参数,内核可以在加载驱动并检测到设备时正确地调用对应的probe函数。

I2C驱动传入probe的参数包括指向I2C设备结构体的指针、指向设备ID信息的指针以及probe函数的函数指针。

TI-I2C驱动

TI-I2C驱动

TI-I2C驱动一、与I2C驱动相关的文件分成两部分:1)应用层接口部分:程序在svn中的路径如下:在https://dareglob-971006/svn/eocOS/branches/eocOS_v4/branches/bsp/user/i2c目录下,i2ctest.c文件,提供了lm75a_temp_read()方法,用来读取LM75A设备温度寄存器中的温度信息的功能。

2)内核驱动部分:内核位于svn中的路径如下:https://dareglob-971006/svn/eocOS/branches/eocOS_v4/branches/bsp/kernel(1)总线驱动:i2c-davinci.c:在内核目录中driver/i2c/busses目录下,适用于TI的I2C总线驱动程序。

I2C总线驱动是对I2C硬件体系结构中适配器端的实现。

(2)I2C驱动代码核心:i2c-core.c:在内核目录中driver/i2c/目录下,是I2C代码的核心,用于沟通虚拟文件系统与底层实现。

该文件提供了I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。

(3)I2C设备驱动:lm75.c:在内核目录中driver/hwmon目录下,是针对LM75A以及其他能兼容的温度传感器的设备驱动。

I2C设备驱动是对I2C硬件体系结构中设备端的实现,设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。

二、I2C简要工作流程1)在总线驱动初始化时候,当通过Linux内核源代码/driver/base/platform.c文件中定义platform_driver_register()函数注册platform_driver结构体时,其中probe指针指向的davinci_i2c_probe()函数将被调用,以初始化适配器硬件。

2)而davinci_i2c_remove()函数则完成与davinci_i2c_probe()相反的功能。

I2C设备驱动介绍

I2C设备驱动介绍

I2C设备驱动介绍I2C(Inter-Integrated Circuit)是一种串行通信协议,用于连接并使多个外部设备与主控制器进行通信。

在嵌入式系统中,I2C设备驱动起着至关重要的作用,负责将操作系统与I2C总线上的设备进行通信,促进数据的传输和交互。

1.初始化:驱动程序需要初始化I2C控制器,包括设置时钟频率、地址范围等。

2.设备注册:设备驱动需要在操作系统中注册I2C设备,以便操作系统能够识别和管理设备。

3.读写操作:驱动程序需要实现读写设备寄存器的功能,包括发送开始和停止信号、以及发送、接收数据等。

4.错误处理:驱动程序需要处理I2C通信过程中可能出现的错误,例如传输失败、设备无响应等情况。

5.中断处理:驱动程序需要支持I2C设备的中断机制,以便及时处理设备的状态变化或数据传输完成的中断信号。

6.电源管理:驱动程序需要支持设备的电源管理功能,包括设备的唤醒、睡眠等操作。

7.设备控制:驱动程序需要实现设备特定的控制功能,例如设置传感器的采样率、配置设备的工作模式等。

8. 虚拟文件系统接口:在Linux系统中,驱动程序通常通过虚拟文件系统接口(如/dev)与用户空间进行交互,提供读写设备寄存器的功能。

1.确定设备:首先,开发者应该确定需要驱动的I2C设备。

这可能包括传感器、EEPROM、显示器等。

2.确定硬件连接:确定I2C设备与主控制器之间的硬件连接和电气特性。

这包括设备的I2C地址、I2C总线上的物理接口等。

3.编写驱动程序:在操作系统中,开发者可以根据设备的文档或芯片厂商提供的驱动程序框架,编写自己的I2C设备驱动程序。

驱动程序需要实现上述提到的功能,并且根据设备的特点进行相应的适配和优化。

4.编译和测试:完成驱动程序的编写后,需要将其编译成与操作系统内核匹配的模块或静态链接库。

然后,通过加载驱动模块或重新编译内核来使驱动程序生效。

最后,进行测试,确保驱动程序在各种场景下的正常运行。

Linux I2C设备驱动编写

Linux I2C设备驱动编写

Linux I2C设备驱动编写(一)在Linux驱动中I2C系统中主要包含以下几个成员:如果一个I2C适配器不支持I2C通道,那么就将master_xfer成员设为NULL。

如果适配器支持SMBUS 协议,那么需要去实现smbus_xfer,如果smbus_xfer指针被设为NULL,那么当使用SMBUS协议的时候将会通过I2C通道进行仿真。

master_xfer指向的函数的返回值应该是已经成功处理的消息数,或者返回负数表示出错了。

functionality指针很简单,告诉询问着这个I2C主控器都支持什么功能。

在内核的drivers/i2c/i2c-stub.c中实现了一个i2c adapter的例子,其中实现的是更为复杂的SMBUS。

SMBus 与I2C的区别通常情况下,I2C和SMBus是兼容的,但是还是有些微妙的区别的。

时钟速度对比:在电气特性上他们也有所不同,SMBus要求的电压范围更低。

I2C driver具体的I2C设备驱动,如相机、传感器、触摸屏、背光控制器常见硬件设备大多都有或都是通过I2C 协议与主机进行数据传输、控制。

结构体如下:如同普通设备的驱动能够驱动多个设备一样,一个I2C driver也可以对应多个I2C client。

以重力传感器AXLL34X为例,其实现的I2C驱动为:这里要说明一下module_i2c_driver宏定义(i2c.h):module_driver():理解上述宏定义后,将module_i2c_driver(adxl34x_driver)展开就可以得到:这一句宏就解决了模块module安装卸载的复杂代码。

这样驱动开发者在实现I2C驱动时只要将i2c_driver结构体填充进来就可以了,无需关心设备的注册与反注册过程。

I2C client即I2C设备。

I2C设备的注册一般在板级代码中,在解析实例前还是先熟悉几个定义:下面还是以adxl34x为例:这样ADXL34X的i2c设备就被注册到了系统中,当名字与i2c_driver中的id_table中的成员匹配时就能够出发probe匹配函数了。

I2C设备驱动介绍

I2C设备驱动介绍

I2C设备驱动介绍I2C(Inter-Integrated Circuit)是一种简单的串行通信协议,用于在微控制器和外部设备之间传输数据。

它是由飞利浦公司(现在的恩智浦)于1982年推出的,现在已成为一种广泛应用的通信接口。

总线驱动是与I2C总线硬件相关的组件,它负责控制总线的时钟频率和数据传输速度。

它还提供了与硬件相关的函数,如初始化总线、发送数据和接收数据。

设备驱动是与特定设备相关的组件,它负责控制设备的初始化和配置,并提供与设备相关的功能函数。

设备驱动还负责将数据从总线读取到设备或从设备写入总线。

用户接口是设备驱动和应用程序之间的接口,通常是通过设备文件或命令行界面实现的。

用户接口提供了一组API函数,允许应用程序通过设备驱动与I2C设备进行通信。

1.初始化:驱动程序负责初始化I2C总线和设备,包括设置速率、地址和模式等。

2.读操作:驱动程序负责从设备读取数据,并将其传输到应用程序。

它可以使用主动读取或中断读取的方式来获取数据。

3.写操作:驱动程序负责将数据从应用程序写入设备,并通过I2C总线将其传输。

它可以使用主动写入或中断写入的方式发送数据。

4.错误处理:驱动程序需要能够检测和处理I2C传输中的错误,例如总线冲突、超时和校验错误等。

5.设备控制:驱动程序提供了控制设备状态和功能的功能函数。

6.多设备支持:驱动程序可以支持多个I2C设备,并提供适当的接口来选择和操作特定的设备。

1.可移植性:驱动程序应该是可移植的,适用于不同的硬件平台和操作系统。

2.灵活性:驱动程序应该具有足够的灵活性,以允许根据不同的应用需求进行配置和定制。

3.可靠性:驱动程序应该能够处理各种异常情况,并提供合适的错误处理机制。

4.性能:驱动程序应该能够实现高速数据传输,并尽可能减少处理延迟。

5.易用性:驱动程序应该提供简单易用的接口,以便应用程序能够方便地使用和控制I2C设备。

总之,I2C设备驱动是控制和管理I2C设备的关键组成部分。

LinuxI2C驱动整理(以RK3399Pro+Kernel4.4为例)

LinuxI2C驱动整理(以RK3399Pro+Kernel4.4为例)

LinuxI2C驱动整理(以RK3399Pro+Kernel4.4为例)⼀. Linux I2C驱动架构Linux内核⾥,I2C驱动框架可以分为两层,adapter驱动和deivce驱动。

Adapter驱动也可以理解为I2C总线驱动,指的是SOC⾥的I2C控制器驱动。

⼀个SOC可能包含多个I2C控制器,⽽每个控制器的使⽤⽅式是相同的(寄存器参数、收发数据的⽅法等),因此多个控制器可以共⽤⼀套adapter驱动;Deivce驱动,对应的是SOC外围的I2C设备,不同类型I2C设备需要开发不同的设备驱动,同⼀类型的I2C设备可以使⽤⼀种驱动,但是每⼀个I2C设备都由⼀个唯⼀的client来描述。

⼆. Adapter配置DTSI⽂件(kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi)描述了RK3399Pro所有的I2C控制器信息:i2c0: i2c@ff3c0000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff3c00000x00x1000>;clocks = <&pmucru SCLK_I2C0_PMU>, <&pmucru PCLK_I2C0_PMU>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c0_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c1: i2c@ff110000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1100000x00x1000>;clocks = <&cru SCLK_I2C1>, <&cru PCLK_I2C1>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c1_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c2: i2c@ff120000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1200000x00x1000>;clocks = <&cru SCLK_I2C2>, <&cru PCLK_I2C2>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c2_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c3: i2c@ff130000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1300000x00x1000>;clocks = <&cru SCLK_I2C3>, <&cru PCLK_I2C3>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c3_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c5: i2c@ff140000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1400000x00x1000>;clocks = <&cru SCLK_I2C5>, <&cru PCLK_I2C5>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c5_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c6: i2c@ff150000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1500000x00x1000>;clocks = <&cru SCLK_I2C6>, <&cru PCLK_I2C6>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c6_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c7: i2c@ff160000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1600000x00x1000>;clocks = <&cru SCLK_I2C7>, <&cru PCLK_I2C7>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c7_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c4: i2c@ff3d0000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff3d00000x00x1000>;clocks = <&pmucru SCLK_I2C4_PMU>, <&pmucru PCLK_I2C4_PMU>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c4_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c8: i2c@ff3e0000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff3e00000x00x1000>;clocks = <&pmucru SCLK_I2C8_PMU>, <&pmucru PCLK_I2C8_PMU>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c8_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};可以看出,该SOC共有9个I2C控制器,分别为I2C0~I2C8, 每个控制器对应了不同的寄存器基地址(例如I2C0对应0xff3c0000),它们的compatible匹配属性都是"rockchip,rk3399-i2c",也就是对应了同⼀个adapter驱动。

i2c_register_driver函数详解

i2c_register_driver函数详解

i2c_register_driver函数详解一、概述i2c_register_driver函数是Linux内核中用于注册I2C设备驱动的函数之一。

它用于将设备驱动程序注册到内核,以便其他模块可以使用该驱动程序来与I2C设备进行通信。

二、函数原型int i2c_register_driver(struct i2c_driver *driver);三、函数参数说明* driver:指向i2c_driver结构体的指针,该结构体包含了设备驱动的相关信息,如设备名称、设备ID等。

四、函数返回值如果函数成功注册驱动程序,则返回0;否则返回-E...等错误代码。

五、函数功能详解i2c_register_driver函数将指定的i2c_driver结构体注册到内核中,使其成为可用的I2C设备驱动。

在注册驱动程序之前,需要确保驱动程序已经正确编译并包含在内核中。

在注册驱动程序时,i2c_register_driver函数会执行以下操作:1. 检查驱动程序是否符合内核的要求,如设备ID、设备名称等是否正确。

2. 将驱动程序的信息添加到内核的设备列表中,以便其他模块可以找到并使用该驱动程序。

3. 注册成功后,内核会为该驱动程序分配相应的资源,如内存、端口等,并建立与I2C总线的连接。

六、使用示例```c#include <linux/module.h>#include <linux/i2c.h>struct i2c_driver my_driver;int main(){int ret;ret = i2c_register_driver(&my_driver);if (ret) {printk(KERN_ERR "Failed to register driver: %d\n", ret);return ret;}// 其他操作...return 0;}```在上述示例中,首先定义了一个i2c_driver结构体变量my_driver,用于存储驱动程序的相关信息。

rk linux下i2c总线驱动读写原理

rk linux下i2c总线驱动读写原理

RK Linux下I2C总线驱动读写原理RK Linux,一个开源的、强大的、可定制的操作系统,广泛应用于各种嵌入式系统。

I2C总线是一种常用的通信协议,常用于连接低速外围设备,如传感器、EEPROM等。

在RK Linux下,I2C总线驱动的读写原理是什么呢?首先,我们来了解下I2C总线的基本概念。

I2C总线是一种双线串行通信总线,由数据线SDA和时钟线SCL组成。

通过这两根线,多个设备可以在同一总线上进行通信。

每个设备都有一个唯一的地址,主机可以通过发送设备的地址来选择与之通信的设备。

在RK Linux下,I2C总线驱动的读写操作主要依赖于内核提供的API。

这些API 包括i2c_read()、i2c_write()等,它们提供了与I2C设备通信的接口。

那么,这些API是如何实现读写操作的呢?在内核中,I2C驱动程序负责管理I2C总线上所有的设备和它们的通信。

当需要从设备读取数据时,驱动程序首先会向设备发送读请求。

设备接收到请求后,会将数据写入SDA线。

驱动程序会持续监听SDA线,一旦接收到数据,就会将其保存并通知应用程序。

同样地,当需要向设备写入数据时,驱动程序会向设备发送写请求。

设备接收到请求后,会准备好接收数据。

驱动程序会将数据写入SDA线,设备接收到数据后,会将数据保存到内部寄存器中。

需要注意的是,I2C总线的读写操作都是通过驱动程序来完成的。

应用程序只需要调用内核提供的API即可与I2C设备进行通信。

这样设计的好处是应用程序可以专注于自己的业务逻辑,而不需要关心底层的通信细节。

同时,这也使得应用程序与具体的I2C设备无关,具有更好的可移植性和扩展性。

i2c,lcd usb驱动

i2c,lcd usb驱动

----杨军(2012 年 4 月 5 日)一、 uboot 启动流程第一阶段启动流程: cpu/arm920t/start.S(汇编阶段)进入 SVC-->关闭看门狗-->关闭中断-->进入 cpu_init_crit()--->(临时设置栈指针 SP)-->调整 CPU 的频率 clock_init() -->把完整的 {初始化 CPU 和 SDRAM 1.刷新出去 I/D cache 2.关闭 MMU 和 cache(一定关闭数据 CACHE,指令 CACHE 无所谓) 3.调用 lowlevel_init}UBOOT 代码从 FLASH 搬移到 SDRAM 中 CopyCode2Ram() -->清除 BSS、设置堆栈-->跳入真正的 C 函数 start_armboot第二阶段启动流程:使能 I/D cache,配置 GPIO 端口【board_init()】 -->:注册倒计时定时器,初始化一个早期串口-->输出 UBOOT 第一条打印 -->NOR/NAND FLASH 初始化-->把环境参数读到 SDRAM-->建立设备管理链表-->重新初始化串口为全功能串口-->网卡初始化-->进入 main_loop()大循环 第一二两个阶段合到一起的描述(这个过程要求面试的时候直接能够说的出来): UBOOT 的启动流程:首先初始化 CPU(进 SVC,关看门狗,关中断,调整 CPU 频率)和 RAM(SDRAM 和 DDR 都需要初始化一次), 将 FLASH 上的 BUOOT拷贝到 RAM 中,清除 BSS 和设置堆栈指针,跳转到 C 函数,接着初始化外设(GPIO 口设置,串口初始化,完整功能的 FLASH,, 网卡初始化),进入一个大的循环检测用户是否有按键按下,如有按下: 停止倒计时,等待用户的后续输入;若 规定时间里面 没有按下,执行 bootcmd 所保存的指令(经常这时是加载内核),然后启动内核二、 内核启动过程head.S arch\arm\boot\Compressed(解压内核)—》head.S arch\arm\Kernel(初始化工作)—》head-common.S arch\arm\Kernel(start_kernel 执行内核) start_kernel() [init/main.c] //vmlinux 的第一个 C 函数 -->setup_arch() 处理 UBOOT 传递过来的 TAG 参数(内存其实位置和大小,bootgars) 把 bootargs 参数各项进行拆解(后续代码可以用__setup()接收参数,例如: __setup("init=", init_setup);) 建立 4KB/页的内存管理,丢弃之前 arch/arm/kernel/head.S 中建立的 1MB/段的内存映射关系-->console_init(); //VMLINUX 的第一行打印输出 -->rest_init()Rest_init()函数分析:内核压缩过程:三、 I2C 驱动Random Read 时序图Byte Write 时序图:I2C 协议:1. i2c 协议特点: ============================================================================================== 1.1 它是飞利浦公司生产的一种串口协议 1.2 1.3 它是两根线传输的 SDA,SCl 数据时钟线 两根线上必须要由上拉电阻1.4 1.5 1.6可以挂多个设备,采用的是主从模式 I2c 的时钟都是由主机产生的 半双工通信方式 (SPI 全双工的,四根线,串行的)1.7 速度问题,低速模式:100K/s 全速模式:400k/s 高速模式:3.4M/s (SPI 的速度一般在 10M 左右) 1.8 真正的多主机总线(解释)1.9 串行 8 位双向传输,先传高位再传低位I2C 驱动分析:四、 LCD 驱动TFT LCD 的 TTL 信号 信号名称 VSYNC HSYNC HCLK VD[23:0] LEND PWREN Framebuffer 概述: 用户可以将 FramBuffer 看成是显卡内存的一个映像,将其映射到进程地址空 间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。

Mini2440之i2c驱动(2)

Mini2440之i2c驱动(2)
上面我们利用 i2cdev.c 实现了 mini2440 的 i2c 驱动, 这一篇我们利用内核级驱动来实现。 在内核级有两种方式, 一种是 LEGACY 方式, 一种是 new style 方式, 但是当我写完 LEGACY 方式 i2c 驱动的时候,发现里面的函数在我的 2.6.32.2 内核下编译不过去,主要是那几个函 数已经不存在了,也就是内核不支持了,而在 linux2.6.27 内核下是可以编译过去的,有兴 趣的而且用的是 linux2.6.27 内核的可以帮我测试下驱动是否正确。LEGACY 方式驱动的代 码我会在最后贴出。下面主要是讲 new style 方式的 i2c 驱动。 首先要明白我们写的是 i2c 设备驱动,而不是 i2c 适配器驱动。关于 i2c 驱动体系 架构方面我就不多讲了, 网上很多, 可以参照宋宝华老师的书, 也可以看看下面的一个博客: /u1/51562/showart_1403925.html,作为 i2c 设备驱动,主要有两个结 构体,struct i2c_driver,struct_i2c client, new style 方式的 i2c_driver 结构体如下所示: static struct i2c_driver at24c08b_driver = { .driver = { .name = "at24c08b", .owner = THIS_MODULE, }, .probe = at24c08b_probe, .remove = __devexit_p(at24c08b_remove), .id_table = at24c08b_id, }; 其中__devexit_p 的作用如下(下面一段话是跟踪__devexit_p 在内核中找到的) : /* Functions marked as __devexit may be discarded at kernel link time, depending on config options. Newer versions of binutils detect references from retained sections to discarded sections and flag an error. Pointers to __devexit functions must use __devexit_p(function_name), the wrapper will insert either the function_name or NULL, depending on the config options. 相信大家都看的懂(⊙_⊙)。 首先看一下初始化函数: static int __init at24c08b_init(void) { printk(KERN_NOTICE"at24c08b is insmod\n"); return i2c_add_driver(&at24c08b_driver); } 在调用 i2c_add_driver 函数的时候会调用 at24c08b_driver 中的 at24c08b_probe 函数进行 i2c 设备的探测,为什么呢,可以自己进行内核源代码的跟踪,我也弄的不是很清楚,写完这篇 我会好好的去补习一下 linux 设备模型方面的知识,从底层的 kobject,kset,ktypes,sysyfs 到上 面的 bus,driver,device。 总之,i2c_add_driver 会将驱动注册到总线上,并进行设备的探测,那么怎么探测的呢,也要 分析 i2c 体系架构,主要是用 i2c_match_id 函数进行探测的,i2c_match_id 函数主要是比较 client 的名字和 i2c_device_id 中名字。本驱动的 i2c_device_id 如下: static const struct i2c_device_id at24c08b_id[] = { { "at24c08b", 0 }, {} }; MODULE_DEVICE_TABLE(i2c, at24c08b_id);

I2C设备驱动介绍

I2C设备驱动介绍

盈量而知芯,方行天下
I2C子系统
盈量而知芯,方行天下
I2C子系统
在Linux内核源代码中的drivers目录下包含一个i2c目录,而在i2c目录下又包含如下文件和 文件夹: • i2c-core.c : 这个文件实现了I2C核心的功能以及/proc/bus/i2c*接口。 • i2c-dev.c : 实现了I2C适配器设备文件的功能,每一个I2C适配器都被分配一个设备。通过 适配器访问设备时的主设备号都为89,次设备号为0~255。应用程序通过 “i2c-%d” (i2c-0, i2c-1, ..., i2c-10, ...)文件名并使用文件操作接口open()、write()、read()、ioctl()和close()等来 访问这个设备。i2c-dev.c并没有针对特定的设备而设计,只是提供了通用的read()、write() 和ioctl()等接口,应用层可以借用这些接口访问挂接在适配器上的I2C设备的存储空间或寄 存器并控制I2C设备的工作方式。 • chips文件夹 : 这个目录中包含了一些特定的I2C设备驱动,如Dallas公司的DS1337实时钟 芯片、EPSON公司的RTC8564实时钟芯片和I2C接口的EEPROM驱动等。 • busses文件夹:这个文件中包含了一些I2C总线的驱动,如S3C2410的I2C控制器驱动为i2cs3c2410.c。 • algos文件夹 : 实现了一些I2C总线适配器的algorithm。 此外,内核中的i2c.h这个头文件对i2c_driver、i2c_client、i2c_adapter和i2c_algorithm这 4个数据结构进行了定义。理解这4个结构体的作用十分关键,分别给出了它们的定义。
I2C子系统
struct i2c_client { unsigned short flags; /* div., see below */ unsigned short addr; /* chip address - NOTE: 7bit */ /* addresses are stored in the */ /* _LOWER_ 7 bits */ char name[I2C_NAME_SIZE]; struct i2c_adapter *adapter; /* the adapter we sit on */ struct i2c_driver *driver; /* and our access routines */ struct device dev; /* the device structure */ int irq; /* irq issued by device */ struct list_head detected; };

I2C驱动E2PROM

I2C驱动E2PROM

I2C驱动E2PROM*By Neil Chiao ( neilchiao at ) 1、I2C总线原理I2C是一种常用的串行总线,由串行数据线SDA 和串线时钟线SCL组成。

系统的I2C模块分为I2C总线控制器和I2C设备。

I2C总线控制器是CPU提供的控制I2C总线接口,它控制I2C总线的协议、仲裁、时序。

I2C设备是指通过I2C总线与CPU相连的设备,如EEPROM。

使用I2C通信时必须指定主从设备。

一般来说,.I2C总线控制器被配置成主设备,与总线相连的I2C设备如AT24C02作为从设备。

1.1、IIC读写EEPROM 原理IIC总线的开始/停止信号如图1所示。

开始信号为:时钟信号线SCL为高电平,数据线SDA从高变低。

停止信号为:时钟信号线SCL为高电平,数据线SDA从低变高。

图1 IIC Start-Stop Signal 1.1.1 IIC总线Byte WriteIIC总线写数据分几种格式,如字节写和页写。

字节写传送格式如图2所示。

开始信号之后,总线开始发数据,第一个Byte是IIC的设备地址,第二个Byte是设备内的地址(如EEPROM中具体的某个物理地址),然后就是要传送的真正的数据DATA。

NOTE:IIC总线在传送每个Byte后,都会从IIC总线上的接收设备得到一个ACK信号来确认接收到了数据。

其中,第一个Byte的设备地址中,前7位是地址码,第8位是方向位(“0”为发送,“1”为接收)。

IIC的中断信号有:ACK,Start,Stop。

图2 IIC Byte Write Write功能的实际实现原理如图3所示:(1)设置GPIO的相关引脚为IIC输出;(2)设置IIC(打开ACK,打开IIC中断,设置CLK等);(3)设备地址赋给IICDS ,并设置IICSTAT,启动IIC发送设备地址出去;从而找到相应的设备即IIC总线上的EEPROM。

(4)第一个Byte的设备地址发送后,从EEPROM得到ACK信号,此信号触发中断;(5)在中断处理函数中把第二个Byte(设备内地址)发送出去;发送之后,接收到ACK 又触发中断;(6)中断处理函数把第三个Byte(真正的数据)发送到EEPROM中;(7)发送之后同样接收到ACK并触发中断,中断处理函数判断,发现数据传送完毕。

介绍i2c驱动开发的书籍

介绍i2c驱动开发的书籍

介绍i2c驱动开发的书籍【实用版】目录1.I2C 总线简介2.I2C 驱动开发的重要性3.推荐的 I2C 驱动开发书籍4.总结正文I2C(Inter-Integrated Circuit)总线是一种串行通信总线,它是由 Philips 公司(现在的 NXP 半导体公司)在 1980 年代开发的。

I2C 用于在微控制器(MCU)和周边设备(如 EEPROM、LCD 显示器、传感器等)之间进行低速通信。

由于其简单、灵活和易于实现的特点,I2C 总线已成为嵌入式系统中常用的通信方式。

在嵌入式系统开发中,I2C 驱动开发是关键环节之一。

驱动开发是指编写用于控制和管理硬件设备的软件模块。

对于 I2C 总线来说,驱动开发涉及到对 I2C 协议的理解和实现,以及对 I2C 设备地址、数据传输和错误处理等方面的掌握。

熟练掌握 I2C 驱动开发技能,可以帮助开发者轻松实现 MCU 与周边设备的通信,提高系统的稳定性和可靠性。

为了帮助开发者更好地学习 I2C 驱动开发,这里推荐几本相关的书籍:1.《I2C 原理与应用》(作者:Johnson M.Hollerith)这本书详细介绍了 I2C 总线的原理、协议和应用,以及如何使用 I2C 进行通信。

书中提供了丰富的实例和代码,对于初学者来说,是一本很好的入门书籍。

2.《嵌入式系统 I2C 编程》(作者:Dave Lipton)这本书从实际应用出发,讲述了 I2C 在嵌入式系统中的应用。

书中包含了大量的实例和代码,涵盖了 I2C 驱动开发的方方面面,适合有一定基础的读者深入学习。

3.《Linux 设备驱动程序》(作者:Robert Love)这本书虽然不是专门针对 I2C 驱动开发的,但它是学习 Linux 设备驱动程序的经典之作。

书中详细介绍了设备驱动程序的基本概念、Linux 设备驱动程序的框架和开发流程等,对于想要深入学习 I2C 驱动开发的读者来说,是一本很有价值的参考书。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

I2C驱动框架—suspend
• • • • • • • • • • • • • • • • • • • • static int ak4187_resume(struct i2c_client *client) { struct ak4187 *ts = i2c_get_clientdata(client); int err; if (ts->power) { err = ts->power(1); if (err < 0) printk(KERN_ERR "ak4187_resume power on failed\n"); } err = ak4187_device_init(ts); if (err) { dev_err(&client->dev, "Initialize error = %d \n", err); return err; } ts->is_suspended = 0; enable_irq(client->irq); dev_info(&client->dev, "ak4187_resume\n"); return 0; }
总结
I2C适配器、设备、核心 • I2C适配器驱动—设备在总线上能够正常通信,实 现设备的数据传输 • I2C设备驱动—实现对应设备的驱动,提供用户程 序接口 • I2C核心—是一条纽带,将设备适配器和设备驱动 连接起来。 它以通用的、与平台无关的的接口实 现了I2C中设备驱动与适配器的沟通
I2C子系统
• 1. I2C核心、I2C适配器驱动和I2C设备驱 动的关系
• 2பைடு நூலகம் 编写I2C设备驱动的方法
第一部分-- I2C体系结构
(1)I2C适配器驱动
• 一个i2c适配器驱动通常需要两个模块来描 述,一个是i2c_adapter和一个 i2c_algorithm • 内部主要是通过i2c_algorithm结构体包含 master_xfer函数的操作来完成数据传输的 • I2c_msg
• }
• static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) • { • int ret = 0;int retry=0; • char test_data = 1; • const char irq_table[2] = {IRQ_TYPE_EDGE_FALLING,IRQ_TYPE _EDGE_RISING}; • struct goodix_ts_data *ts; • struct goodix_i2c_rmi_platform_data *pdata;
I2C适配器作用
• I2C适配器驱动—设备在总线上能够正常通 信,实现设备的数据传输
(2)I2C核心
• I2C核心主要是提供了API用于供I2C设备驱 动来调用以实现和总线的通信(从而进一 步实现和设备和CPU之间通信)。
I2C核心
I2C核心作用
• I2C核心—是一条纽带,将I2C设备适配器 和设备驱动连接起来。 它以通用的、与平 台无关的的接口实现了I2C中设备与适配器 的沟通
I2C驱动框架—探测及初始化
• • • • • • •
ts = kzalloc(sizeof(*ts), GFP_KERNEL); if (ts == NULL) { ret = -ENOMEM; goto err_alloc_data_failed; ……. Request_irq(); Init_timer();
I2C驱动框架—模块初始化
• static int __init ak4187_init(void) • { • ak4187_wq = create_singlethread_workqueue("ak4187_wq"); if (!ak4187_wq) • return -ENOMEM; • • return i2c_add_driver(&ak4187_driver); • } • static void __exit ak4187_exit(void) • { i2c_del_driver(&ak4187_driver); • if (ak4187_wq) • destroy_workqueue(ak4187_wq);
I2C驱动框架—suspend
• • • • • • • • • • • • • • • • • static int ak4187_suspend(struct i2c_client *client, pm_message_t mesg) { struct ak4187 *ts = i2c_get_clientdata(client); int err=0; ts->is_suspended = 1; disable_irq(client->irq); cancel_work_sync(&ts->work); err = i2c_smbus_write_byte_data(ts->client, AK4187_SETUP_ADDRESS, AK4187_SETUP_SLEEP0); if (err) { dev_err(&client->dev, "Suspend error = %d \n", err); } if (ts->power) { err = ts->power(0); if (err < 0) printk(KERN_ERR "ak4187_resume power off failed\n"); } return 0;
(3)I2C设备驱动
• I2C设备驱动—实现对应设备的驱动,完成设 备的特定动作,也提供用户程序接口 • 另外,I2c-dev.c针对适配器生成一个主设 备号位89的设备文件,实现设备驱动的文 件操作接口,针对字符设备使用。
I2C设备驱动
第二部分--编写I2C设备驱动
• i2c设备驱动一般在./kernel/driver/chips/文 件夹下,(因为大多设备也属于输入设备, 有的会放在输入设备下,如触摸屏驱动 在.kernel/driver/input/touchscreen/下)。 • 设备驱动是对设备端的实现,设备要挂载 到对应总线上才能和CPU通信.
• • • • • • • • • • • • •
static struct i2c_driver AK4187_driver = { .probe = goodix_ts_probe, .remove = goodix_ts_remove, #ifndef CONFIG_HAS_EARLYSUSPEND .suspend = goodix_ts_suspend, .resume = goodix_ts_resume, #endif .id_table = goodix_ts_id, .driver = { .name = GOODIX_I2C_NAME, .owner = THIS_MODULE, }, };
• struct ak4187 { • struct input_dev *input; • struct hrtimer timer; • struct timer_list ts_timer; • struct work_struct work; • struct ts_event tc; • u8 intervalData[AK4187_INTDATA_NUM]; • • • • • • • • • • struct i2c_client *client; struct early_suspend early_suspend; spinlock_t lock; int irq; int is_suspended; int AK4187_First_Pendown; //Junger@0803 void (*clear_penirq)(void); int (*power)(int on); }; static struct ak4187 *gl_ts;
I2C适配器驱动
适配器驱动主要完成: 1)适配器i2c_adapter的初始化(时钟初始化、 申请I2C的I/O地址和中断号) 2)驱动适配器从硬件上产生各种信号和处理 I2C中断
部分适配器代码
static int tcc_i2c_doxfer(struct tcc_i2c *i2c, struct i2c_msg *msgs, int num) • { • int ret, i; • for (i = 0; i < num; i++) { • spin_lock_irq(&i2c->lock); • i2c->msg = &msgs[i]; • i2c->msg->flags = msgs[i].flags; • i2c->msg_num = num; • i2c->msg_ptr = 0; • i2c->msg_idx = 0; • i2c->state = STATE_START; • spin_unlock_irq(&i2c->lock); • • • • • • • • • • • • if (i2c->msg->flags & I2C_M_RD) { ret = recv_i2c(i2c); if (ret != 1) printk("recv_i2c failed! - addr(0x%02X)\n", i2c->msg->addr); } else { ret = send_i2c(i2c); if (ret != 1) printk("send_i2c failed! - addr(0x%02X)\n", i2c->msg->addr); } } return ret; }
相关文档
最新文档