Linux I2C驱动完全分析(一)

发布者:李国永最新更新时间:2021-11-22 来源: eefocus关键字:Linux  I2C  驱动 手机看文章 扫描二维码
随时随地手机看文章

其实老早就想写这个I2C的了,期间有各种各样的事情给耽误了。借着五一放假的时间把这个写出来,供同志们参考。以后会花一些时间深入研究下内核,虽然以前对内核也有所了解,但是还不系统。I2C的硬件结构并不复杂,一个适配器加几个设备而已。Linux下驱动的体系结构看着挺复杂,实际也是比较简单的。在本文中我还是使用实际的例子,结合硬件和软件两个方面来介绍。希望能给初学的同志们一些帮助,另外抛砖引玉,希望高手能给一些指点。话不多说,开整!~


本文用到的一些资源:


   1. Source Insight软件


   2. mini2440原理图。 下载地址http://wenku.baidu.com/view/0521ab8da0116c175f0e48fe.html


   3. S3C2440 datasheet


   4. AT24C08 datasheet


   5. Bq27200 datasheet


   6. kernel 2.6.31中的At24.c ,Bq27x00_battery.c和i2c-s3c2410.c


   7. mini2440的板文件mach-mini2440.c


   8. 参考资料:《linux设备驱动开发详解(第2版)》 by 宋宝华


本文的结构:


第一部分:At24C08驱动


   1. mini2440中at24c08的电气连接


   2. Linux中I2C驱动框架分析


   3. I2C总线驱动代码分析


   4. at24c08驱动代码分析


第二部分:Bq27200驱动


   1. Bq27200的典型应用电路


   2. 主要分析一下ba27x00的代码,对比at24c08来加深理解。


---------------------我是分割线----------------------


第一部分


1. mini2440中at24c08的电气连接及其板文件


如下图。

                                

24C08的I2C接口是与2440的IICSCL/IICSDA直接相连的。在2440内部集成了一个I2C控制器,可以通过寄存器来控制它。先来和这四个寄存器混个脸熟吧,后面分析时还会经常用到这四个寄存器。

在mini2440的板文件中可以找到关于at24c08的内容,如下:


/*

 * I2C devices

 */

static struct at24_platform_data at24c08 = {

.byte_len = SZ_8K / 8,

.page_size = 16,

};


static struct i2c_board_info mini2440_i2c_devs[] __initdata = {

{

I2C_BOARD_INFO("24c08", 0x50),

.platform_data = &at24c08,

},

};


static void __init mini2440_init(void)

{

   ... ...

   i2c_register_board_info(0, mini2440_i2c_devs,

ARRAY_SIZE(mini2440_i2c_devs));

   ... ...

}


可以看出,在mini2440的init函数中注册了一个i2c的设备,这个设备我们使用了一个结构体i2c_board_info来描述。这个结构体定义在i2c.h文件中。如下:


struct i2c_board_info {

char type[I2C_NAME_SIZE];

unsigned short flags;

unsigned short addr;

void *platform_data;

struct dev_archdata *archdata;

int irq;

};


其中的platform_data又指向一个at24_platform_data结构体。


以上只是at24c08的部分,在板文件中还可以看到关于2440内部i2c控制器的部分,如下:


static struct platform_device *mini2440_devices[] __initdata = {

 ... ...

 &s3c_device_i2c0,

 ... ...

};


static void __init mini2440_init(void)

{

 ... ...

 platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));

 ... ...

}


其中s2c_device_i2c0定义在arch/arm/plat-s3c/Dev-i2c0.c中(在同一目录下还可以看到很多Dev-开头的c文件,都是2440内部集成的各种设备),仔细看下面的代码再对比2440的datasheet就可以很清楚的知道:


   * 控制器的IO起始地址为S3C_PA_IIC =0x54000000,大小是4K,中断号是43 = IRQ_IIC      S3C2410_IRQ(27)


* 控制器名是"s3c2410-i2c"



2. Linux中I2C驱动框架分析


这部分是本文的重点部分。根据上面的电气连接关系我们可以看出,我们要想操作24c08,必须要做两方面的驱动。


第一方面: 2440中I2C控制器的驱动,有了这部分驱动,我们才可以操作控制器来产生I2C的时序信号,来发送数据和接收数据。


第二方面: 24C08的驱动,有了这部分驱动,才能使用控制器正确操作芯片,来读取和存放数据。


在Linux系统中,对上边第一方面的实现叫做I2C总线驱动,对第二方面的实现叫做I2C设备驱动。一般来说,如果CPU中集成了I2C控制器并且Linux内核支持这个CPU,那么总线驱动方面就不用我们操心了,内核已经做好了。但如果CPU中没有I2C控制器,而是外接的话,那么就要我们自己实现总线驱动了。对于设备驱动来说,一般常用的驱动也都包含在内核中了,如果我们用了一个内核中没有的芯片,那么就要自己来写了。


Linux中I2C体系结构如下图所示(图片来源于网络)。图中用分割线分成了三个层次:用户空间(也就是应用程序),内核(也就是驱动部分)和硬件(也就是实际物理设备,这里就是2440中的i2c控制器和at24c08)。这个够清晰了吧?我们现在就是要研究中间那一层。

 由上图我们还可以看出哪些信息呢?


1). 可以看到几个重要的组成部分,它们是:Driver,Client,i2c-dev,i2c-core,Algorithm,Adapter。这几个部分在内核中都有相应的数据结构,定义在i2c.h文件中,尽量避免粘贴打断代码来凑数,就不贴出来了。简要概括一下每个结构体的意义。


Driver --> struct i2c_driver 


这个结构体对应了驱动方法,重要成员函数有probe,remove,suspend,resume。


还包括一个重要的数据结构: struct i2c_device_id *id_table; 如果驱动可以支持好几个设备,那么这里面就要包含这些设备的ID


Client --> struct i2c_client


应用程序是选择性失明的,它只能看到抽象的设备文件,其他部分都是看不见的。图中只有Client与应用程序有联系,所以我们可以大胆得出结论:这个Client是对应于真实的物理设备,在本文就是at24c08。 所以很显然这个结构体中的内容应该是描述设备的。包含了芯片地址,设备名称,设备使用的中断号,设备所依附的控制器,设备所依附的驱动等内容。


Algorithm -->struct i2c_algorithm


Algorithm就是算法的意思。在这个结构体中定义了一套控制器使用的通信方法。其中关键函数是master_xfer()。我们实际工作中的重要一点就是要实现这个函数。


int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);

Adapter --> struct i2c_adapter


这个结构体对应一个控制器。其中包含了控制器名称,algorithm数据,控制器设备等。


 2). 可以看出,i2c-core起到了关键的承上启下的作用。事实上也是这样,我们将从这里展开来分析。源代码位于drivers/i2c/i2c-core.c中。在这个文件中可以看到几个重要的函数。


*增加/删除i2c控制器的函数

int i2c_add_adapter(struct i2c_adapter *adapter)

int i2c_del_adapter(struct i2c_adapter *adap)


*增加/删除设备驱动的函数

int i2c_register_driver(struct module *owner, struct i2c_driver *driver)

void i2c_del_driver(struct i2c_driver *driver)


 *增加/删除i2c设备的函数

struct i2c_client *

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

void i2c_unregister_device(struct i2c_client *client)


注:在2.6.30版本之前使用的是i2c_attach_client()和i2c_detach_client()函数。之后attach被merge到了i2c_new_device中,而detach直接被unresister取代。实际上这两个函数内部都是调用了device_register()和device_unregister()。源码如下:


 *I2C传输、发送和接收函数

int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);


int i2c_master_send(struct i2c_client *client,const char *buf ,int count);


int i2c_master_recv(struct i2c_client *client, char *buf ,int count);


其中send和receive分别都调用了transfer函数,而transfer也不是直接和硬件交互,而是调用algorithm中的master_xfer()函数,所以我们要想进行数据传输,必须自己来实现这个master_xfer()函数,这是总线驱动开发的重点之一。下面以read()系统调用的流程来简单梳理一下:

关键字:Linux  I2C  驱动 引用地址:Linux I2C驱动完全分析(一)

上一篇:mini2440-i2c驱动分析
下一篇:mini2440 linuxi2c驱动

推荐阅读最新更新时间:2024-11-20 10:45

单段隔离型功率因数校正LED驱动
  功率因数校正,就是将畸变电流校正为正弦电流,并使之与电压同相位,从而使功率因数接近于1。提高功率因数对于降低能源消耗,减小电源设备的体积和重量,缩小导线截面积,减弱电源设备对外辐射和传导干扰都具有重大意义。故而有功率因数校正的LED驱动器越来越受欢迎。本文将以安森美半导体的两款单段隔离功率因数校正LED驱动器NCP1652A及NCL30001为例,介绍高能效的单段功率因数校正LED驱动器的设计方法及应用方案。   单段隔离型功率因数校正LED驱动器解决方案有:基于NCL30000的离线型高功率因数Triac可调光LED驱动器;用于高压LED灯串的基于NCP1044升压式转换器的LED单段功率因数校正驱动方案;基于NCL165
[电源管理]
单段隔离型功率因数校正LED<font color='red'>驱动</font>器
STM32 I2C 死锁问题
背景 其实这篇文章在很久之前就写过解决方法了。在经过不断的实践和深究后发现,硬件 I2C 死锁的问题在ST的官方手册中的勘误手册(errata)中早就提供解决方案,只是我没有重视官方的文档,一直在网络寻求帮助。 即使已经有官方的解决方案,但是还有很多人(包括以前的我)在怀疑 STM32 系列的 I2C 有硬件 BUG。这也告诉我们:网上资源虽丰富,但还是得通过“金睛火眼”来辨别。 讲真的,为了解决 I2C 问题,我在网上看了 N 多篇的文章、Blog 和帖子,还没看到几个人说 “STM32 硬件 I2C 没问题”,反而是看到很多类似这样的:“都听说STM32 硬件 I2C 有问题,一试,发现还真是有问题,改用 IO 模拟吧
[单片机]
STM32 <font color='red'>I2C</font> 死锁问题
三种可控硅调光LED电源驱动方案的比较
全球各大半导体厂商和专业电源制造商都在积极投入研发和推出了部分专用IC芯片,以迎接LED照明替代白炽灯时代的到来。   已率先推出适合可控硅调光的专用LED驱动IC的NXP、National和IWATT半导体厂商,在这个技术领域起到了很好的技术推动作用。   NXP的芯片型号为:SSL2101和SSL2102;   National的芯片型号为:LM3445;   IWATT的芯片型号为:IW3610;   应该说,上述厂家的技术思路上各有千秋,但总的原则是:简单,稳定,有一定的通用性。技术上,主要是遵循了要让可控硅调光器保持导通,再进行PWM变换的原则,并增加了变频控制和QR方式,以达到人眼适合的指数调光和高效率的目的。
[电源管理]
STM32 I2C基础内容
I²C:全称为Inter-Integrated Circuit(内部集成电路),是一种串行通讯总线,常用于嵌入式电子产品中。 I²C是飞利浦公司在1980年为了让各种低速设备(飞利浦芯片)连接起来而研发的一种通信总线。目前,I²C依然是最常见的通信总线之一,现在绝大部分MCU都内部集成了I²C控制器,STM32也不例外,至少有一个I²C控制器,有的型号甚至多达6个。 1 STM32 I2C基础内容 I²C总线协议有多个版本,有的STM32遵循的是第2版本,有的是第3版本。所以,不同型号的 STM32 中I²C 可能存在一些差异,但基本功能相似。 1. 主从模式特性 主模式特性: 时钟生成 起始位和停止位生成 从模式特性:
[单片机]
STM32 <font color='red'>I2C</font>基础内容
基于STM32的TM1629的驱动代码
某年写个番禺龙美游戏机IO板用到了STM32F103VBT6及TM1629.写下了一个驱动程序。希望能帮助到有需要的朋友。不多说了,代码如下: #ifdef GAME #include stm32f10x.h #include stdio.h //TM1629片选 //STB #define TM1629_STB GPIOC #define TM1629_CSA GPIOC, GPIO_Pin_0 #define TM1629_CSB GPIOC, GPIO_Pin_1 #define TM1629_CSC GPIOC, GPIO_Pin_2 #define TM1629_CSD GPIOC, GPIO_Pin_3 //TM1
[单片机]
IMX257 BEEP驱动程序实现
1.确定相关寄存器基址 确定IOMUX地址 0x43fa_c000 0x43fa_ffff GPIO1的地址 0x53fc_c000 0x53fc_ffff MUX_CTL寄存器偏移地址 0x011c PAD-CTL 寄存器偏移 0x0314 GPIO寄存器偏移地址 2.编译测试 本驱动程序亲测成功: 附上驱动程序代码: 1 #include linux/cdev.h 2 #include linux/module.h 3 #include linux/types.h 4 #include linux/fs.h 5 #include linux/errno.h 6 #in
[单片机]
IMX257 BEEP<font color='red'>驱动</font>程序实现
基于PCI总线的双DSP系统及WDM驱动程序设计
摘要:介绍了PCI总线控制芯片PCI2040的功能及内部结构,分析了基于PCI总线的双DSP通信的硬件结构及实现方法,并描述了利用Windows2000 DDK开发WDM设备驱动程序的方法及PCI双DSP通信驱动程序主要模块的设计方法和编程注意要点。 关键词:PCI总线 PCI2040 DSP DDK WDM TI公司专门推出了PCI2040桥芯片是专门针对PCI总线和DSP接口用的,本文利用它和DSP来处理视频信号,并用双端口RAM实现DSP之间的数据传输。 1 硬件设计 1.1 PCI总线控制芯片PCI2040 PCI总线是一种不依附于某个具体处理器的局部总线,它支持32位或64位的总线宽度,频率通常是33MHz,
[应用]
日立存储下一代磁头开发又有新突破,有效推动千兆驱动器发展
日立环球存储科技(Hitachi Global Storage Technologies)在一个技术会议上报道了其在开发硬盘下一代的记录磁头上所取得的进展。该公司指出新一代的记录磁头在大约4年内可以为4千兆的桌面系统和千兆笔记本硬盘驱动器铺平道路。 日立环球存储科技宣称在实验室利用垂直平面电流模式巨磁阻磁头(CPP-GMR)设计首个工作版本中领先了对手一步。该公司将在东京正交磁记录会议上报道这项进展,这项技术可以在30到50纳米的范围内制造新磁头,信噪比达30到40dB。日立环球存储科技的首席技术员John Best指出,“这是我们能接受的误码率下我们需要的信噪比。” 现在还不是很清楚该公司可以从它的这项技术中获取多少商业上的
[新品]
小广播
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved