i2c,lcd usb驱动

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 看成是显卡内存的一个映像,将其映射到进程地址空 间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。 垂直同步信号 水平同步信号 像素时钟信号 数据信号 行结束信号 电源开关信号 描述

驱动分析:
五、 USB 驱动
1、说说你对 USB 的认识 USB 的版本 1.0.,1.1,2.0,3.0 物理接口与拓扑结构 拓扑结构 星型 除去跟集线器外,最多可以层叠(一个接一个)5 个集线器,每个 USB 电缆最大长度是 5m,所以 USB 总线最大距离为 30m (接 上 5 个集线器)。一条 USB 总线上可以外接 127 个设备,包括根集线器和其他集线器。 电气特性: USB 电缆:Vbus, GND, D+,D- (差分信号,双绞线),最长 5m D+,D-信号状态: 单端 0(SE0)、静止态(1 和 0),差分态(1 和 0: Vd+ -Vd- >200mV: 1, Vd+ -Vd- <200mV, 0) 电压和电流: Vbus:(高电压: 5V 正负 5%, 4.75~5.25V, 低电压模式:4.4V~5.25V), USB HUB 工作电压是高电压(最小 4.75V) 电流(控制器 500mA,自供电 100mA, usb3.0 900mA) 2. USB 的传输类型: a. 控制传输:可靠,时间有保证,比如:USB 设备的识别过程速度低,配置,设置寄存器 b. 批量传输: 可靠, 时间没有保证, 比如:U 盘

c. 中断传输:可靠,实时,比如:USB 鼠标 实质是定时查询,非以前的中断概念 d. 实时传输:不可靠,实时,比如:USB 摄像头 https://www.360docs.net/doc/e82181380.html,B 主机控制器

UHCI、OHCI、EHCI HCI 表示“host controller interface” UHCI、OHCI 属于 USB1.1 的主机控制器规范,而 EHCI 是 USB2.0 的主机控制器规范 UHCI 硬件简单,软件复杂 OHCI 硬件复杂,软件简单 4.设备枚举过程: 1). 2). 3). 4). 5). 6). 7). 8).
获取设备描述符 复位 设置地址 再次获取设备描述符 获取配置描述符 获取接口,端点描述符 获取字符串描述符 选择设备配置
5.所有的 USB 传输,都是从 USB 主机这方发起;USB 设备没有"主动"通知 USB 主机的能力。而设备不能主动向主机发送任何
信息。 问 4. USB 设备刚接入 PC 时,还没有编号;那么 PC 怎么把"分配的编号"告诉它? 答 4. 新接入的 USB 设备的默认编号是 0,在未分配新编号前,PC 使用 0 编号和它通信。 6.为什么一接入 USB 设备,PC 机就能发现它? 答 5. PC 的 USB 口内部,D-和 D+接有 15K 的下拉电阻,未接 USB 设备时为低电平 USB 设备的 USB 口内部,D-或 D+接有 1.5K 的上拉电阻;它一接入 PC,就会把 PC USB 口的 D-或 D+拉高,从硬件的角度通知 PC 有新设备接入 7. USB 总线驱动程序的作用 a. 识别 USB 设备 b. 查找并安装对应的设备驱动程序 c. 提供 USB 读写函数 8. usb 设备枚举过程
USB 设备枚举的数据传输过程 以下是一个程序枚举数据传输的全过程 1: (1) 主机检测到有设备插上,总线复位
当设备与主机连接时,主机就会检测到一个连接条件,并且 D+的数据线被拉至 Vse 以上 2.5 微秒(30 个全速数据比特周期),主
机就开始进行总线复位。 (2) 主机读取设备描述符
主机使用默认地址(地址 0)读取设备描述符,在这里主机使用地址 0 对设备的设备描述符进行读取。由于 PDIUSBD12 的端点 0
的缓冲区只有 16 个字节,所以单片机就先发送 16 个字节的设备描述符。当主机接收到这 16 个字节的字符后,就认为真正有 设 备连接了,即发送 1 个 0 字节的数据包到设备作为状态应答。

(3) 地址分配 在地址分配阶段里,主机分配给设备一个地址。在以后的通信里设备就只对这个地址的信息作出应答。 (4) 主机从新的地址获取设备描述符
分配好了设备地址后,主机就从新的地址获取设备描述符。由于受 PDIUSBD12 芯片的限制,设备分 2 次把设备描述符经过端点
0 发送出去,第一次发送 16 个字节,第 2 次发送 2 个字节。最后主机发送 0 字节的数据包作为状态应答。 (5) 主机读取配置描述符

主机读取完设备描述符后就读取设备的配置描述符 (6) 读取描述符集合 主机除了读取设备描述符和配置描述符外,还要读取接口描述符和端口描述符。在这里主机使用再次读取配置的方法来读取配 置描述符、接口描述符和端点描述符的集合。 (7) 设置配置 主机读取完描述符后,就需要对设备进行配置,使得设备从地址状态进入配置状态。 (8) 读取配置状态 主机设置完配置以后,设备即可使用。主机有时会对设备的配置状态进行读取。 (9) 读取接口状态 在配置完成后,主机会对接口的状态进行读取,这和读取配置一样也是可选的。
程序枚举数据传输的全过程 1: 当我们通过 usb 协议大体了解了 usb 描述符和标准请求后,我们就有了解 usb 枚举过程的基础,在看完 usb 枚举过程之后,我 们要明白一个问题,就是主机是怎么认识 usb 设备的 首先,主机是 usb 通信的发起者,usb 设备只能被动接受命令。 下面的枚举过 程通过 bushound 可以探测到,对于 bushound 的使用,一搜一片。 usb 控制器与集线器都在机箱里,集线器检测到了新设备信号,它先要和 usb 控制器商量一下,下面是商量的内容: 1.主机的集线器检测新设备
电脑主机的主板上都会有几个集线器,每个集线器都会有多个 usb 口,usb 口就是我们肉眼看到的机箱外部的 usb 插口。主机 集线器 轮巡每个端口的信号电压,当有新设备接入 usb 口时就会察觉。原因在于集线器端口的两根信号线的每一根都有一个
15K? 的下拉电阻,每一个设备在 D+线上都有一个 1.5K? 的上拉电阻。当总线将主机和设备接通后,设备的上拉电阻使信号 线上的电位升高,此时主集线器就会检测到这个信号。 2.报告集线器事件
当检测到接入信号后,集线器用中断来报告给主机 usb 控制器(简称主机),控制器知道后,给集线器发送一个 Get_Status 请求,
集线器告诉主机新设备是什么时候连接到主机上的。 3.重新设置新设备 当主机确定此时有新设备后,主机给集线器发送一个 Set_Feature 请求,集线器使得 usb 数据线处于 reset 状态至少 10ms 4.重发 Get_Status 请求
主机重发 Get_Status 请求以检查设备是否真的处于重启态。当集线器释放重启态后,设备进入默认态,此时可以通过端点 0 进
行控制传输了,使用默认地址 0x0 与主机通信。 5.集线器通过 D+/D-信号线在空闲时电压的高低来断定 usb 此时是全速还是低速。 好了,控制器与集线器商量了一会,心里有底了,现在可以询问设备了 1.主机向端点 0 发送获取设备描述符请求,在有限时间内等待 usb 设备回答,不管 usb 设备此时返回多少字节,主机只读前 8 个字节 ,如果等待几 ms 设备没有反应,会持续三次
2.主机发送 Set_Address 请求给设备,同时为设备分配一个新地址。设备读到这个请求后,返回给主机确认信息,同时保存新地
址,下面开始用新地址通信。 3.主机重发获取设备描述符请求给设备,这次会读取全部的 usb 设备描述符,了解设备的 VID,PID 等信息。一次读不全,会 重复发送该请求。 4.主机发送获取字符串描述符,获得厂商,产口描述,型号等信息。 5.到这儿主机右下角就会弹出发现新硬件,接着弹出厂商,产品描述,型号等 6.主机设备描述符和设备配置信息在自己的驱动 库中查找是否有合适的驱动,win98 以上的 windows 系统(不包括 98)支持 HID

设备,打印机,扫描仪等,如果搜不到,会弹出对话框,提示安装设备驱动。
7.驱动加载以后,主机发送设置配置请求为设备选一个合适的配置。如果配置成功,usb 进入配置状态,设备可以和主机上应用
软件通信了。
不做实际的固件开发,上面的过程有些地方很难理解,读完之后只需有一个大体印象,当 usb 枚举失败之后,通过 bushound
我们就知道到在哪一个阶段出了问题。

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设备。 第二种:为I2C设备独立编写一个设备驱动 注意:第二种方法不能用设备提供的I2C-dev.c 5、I2C系统下的文件架构 在linux下driver下面有个I2C目录,在I2C目录下包含以下文件和文件夹 1)I2C-core.c 这个文件实现I2C核心功能以及/proc/bus/I2C*接口 2)I2C-dev.c 实现I2C适配器设备文件的功能,每个I2C适配器被分配一个设备,通过 适配器访问设备的时候,主设备号是89,此设备号是0-255. I2C-dev.c并没有针对特定设备而设计,只提供了read() write()和ioctl()等接口,应用层可以通过这些接口访问挂在适配器上的I2C设备存储空间和寄存器,并控制I2C设备的工作方式。 3)Chips 这个文件下面包含特定的I2C设备驱动。 4)Busses 这个文件包含一些I2C总线驱动。 5)Algos文件夹下实现了I2C总线适配器的algorithm 6、重要结构体 1)在内核中的I2C.h这个头文件中对I2C_driver;I2C_client;I2C_adapter和I2C_algorithm 这个四个结构体进行了定义。理解这4个结构体的作用十分关键。 i2c_adapter结构体 struct i2c_adapter { struct module *owner; //所属模块 unsigned int id; //algorithm的类型,定义于i2c-id.h, unsigned int class; const struct i2c_algorithm *algo; //总线通信方法结构体指针 void *algo_data;//algorithm数据 struct rt_mutex bus_lock; //控制并发访问的自旋锁 int timeout; int retries; //重试次数 struct device dev; //适配器设备 int nr; char name[48]; //适配器名称 struct completion dev_released; //用于同步 struct list_head userspace_clients; //client链表头

iic设备驱动程序.doc

IIC设备驱动程序 IIC设备是一种通过IIC总线连接的设备,由于其简单性,被广泛引用于电子系统中。在现代电子系统中,有很多的IIC设备需要进行相互之间通信 IIC总线是由PHILIPS公司开发的两线式串行总线,用于连接微处理器和外部IIC设备。IIC设备产生于20世纪80年代,最初专用与音频和视频设备,现在在各种电子设备中都广泛应用 IIC总线有两条总线线路,一条是串行数据线(SDA),一条是串行时钟线(SCL)。SDA负责数据传输,SCL负责数据传输的时钟同步。IIC设备通过这两条总线连接到处理器的IIC总线控制器上。一种典型的设备连接如图: 与其他总线相比,IIC总线有很多重要的特点。在选择一种设备来完成特定功能时,这些特点是选择IIC设备的重要依据。 主要特点: 1,每一个连接到总线的设备都可以通过唯一的设备地址单独访问 2,串行的8位双向数据传输,位速率在标准模式下可达到100kb/s;快速模式下可以达到400kb/s;告诉模式下可以达到3.4Mb/s 3,总线长度最长7.6m左右 4,片上滤波器可以增加抗干扰能力,保证数据的完成传输 5,连接到一条IIC总线上的设备数量只受到最大电容400pF的限制 6,它是一个多主机系统,在一条总线上可以同时有多个主机存在,通过冲突检测方式和延时等待防止数据不被破坏。同一时间只能有一个主机占用总线 IIC总线在传输数据的过程中有3种类型的信号:开始信号、结束信号、和应答信号 >>开始信号(S): 当SCL为高电平时,SDA由高电平向低电平跳变,表示将要开始传输数据 >>结束信号(P):当SCL为高电平时,SDA由低电平向高电平跳变,表示结束传输数据 >>响应信号(ACK): 从机接收到8位数据后,在第9个周期,拉低SDA电平,表示已经收到数据。这个信号称为应答信号 开始信号和结束信号的波形如下图:

Linux下I2C驱动架构全面分析概要

Linux下I2C驱动架构全面分析 I2C概述 I2C是philips提岀的外设总线. I2C只有两条线,一条串行数据线:SDA, —条是时钟线SCL,使用SCL , SDA这两根信号线就实现了设备之间的数据交互,它方便了工程师的布线。 因此,I2C总线被非常广泛地应用在EEPROM,实时钟,小型LCD等设备与CPU的接口中。 linux下的驱动思路 在linux系统下编写I2C驱动,目前主要有两种方法,一种是把I2C设备当作一个普通的字符设备来处理,另一种是利用linux下I2C驱动体系结构来完成。下面比较下这两种方法: 第一种方法: 优点:思路比较直接,不需要花很多时间去了解linux中复杂的I2C子系统的操作方法。 缺点: 要求工程师不仅要对I2C设备的操作熟悉,而且要熟悉I2C的适配器(I2C控制器)操作。要求工程师对I2C的设备器及I2C的设备操作方法都比较熟悉,最重要的是写岀的程序可以移植性差。 对内核的资源无法直接使用,因为内核提供的所有I2C设备器以及设备驱动都是基于I2C 子系统的格式。 第一种方法的优点就是第二种方法的缺点, 第一种方法的缺点就是第二种方法的优点。 I2C架构概述 Linux的I2C体系结构分为3个组成部分: I2C核心:I2C核心提供了I2C总线驱动和设备驱动的注册,注销方法,I2C通信方法 (” algorithm 上层的,与具体适配器无关的代码以及探测设备,检测设备地址的上层代码等。 I2C总线驱动:I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可由CPU控制,甚至可以直接集成在CPU内部。 I2C设备驱动:I2C设备驱动(也称为客户驱动)是对I2C硬件体系结构中设备端的实现,设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。

Linux驱动之i2c用户态调用

一、概述 I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL.正因为这样,它方便了工程人员的布线. 二、用户态实现设备驱动 在Linux内核代码文件i2c-dev.c中实现了I2C适配器设备文件的功能,针对每个适配器生成一个主设备号为89的设备节点(次设备号为0-255),I2c-dev.c并没有针对特定的设备而设计,只是提供了通用的read(),write(),和ioctl()等文件操作接口,在用户空间的应用层就可以借用这些接口访问挂接在适配器上的I2C设备的存储空间或寄存器,并控制I2C设备的工作方式。 i2c适配器的设备节点是/dev/i2c-x,其中x是数字。由于适配器编号是动态分配的(和注册次序有关),所以想了解哪一个适配器对应什么编号,可以查看/sys/class/i2c-dev/目录下的文件内容。 三、用户态调用 3.1、i2c-dev 用户空间操作i2c,需要包含以下头文件。 打开适配器对应的设备节点

i2c-dev为打开的线程建立一个i2c_client,但是这个i2c_client并不加到i2c_adapter的client链表当中。他是一个虚拟的临时client,当用户打开设备节点时,它自动产生,当用户关闭设备节点时,它自动被释放。 3.2、ioctl() 查看include/linux/i2c-dev.h文件,可以看到i2c支持的IOCTL命令1.#define I2C_RETRIES0x0701 /*设置收不到ACK时的重试次数*/ 2.#define I2C_TIMEOUT0x0702/*设置超 时时限的jiffies*/ 3.#define I2C_SLAVE0x0703/ *设置从机地址*/ 4.#define I2C_SLAVE_FORCE0x0706/*强制设置从机地 址*/ 5.#define I2C_TENBIT0x0704/* 选择地址位长:=0for7bit,!=0for10bit*/ 6.#define I2C_FUNCS0x0705/* 获取适配器支持的功能*/ 7.#define I2C_RDWR0x0707 /*Combin ed R/W transfer(one STOP only)*/ 8.#define I2C_PEC0 x0708/* !=0to use PEC with SMBus*/ 9.#define I2C_SMBUS0x0720 /*SMBus transfer*/

linux下iic(i2c)读写AT24C02

https://www.360docs.net/doc/e82181380.html,/jammy_lee/ https://www.360docs.net/doc/e82181380.html, linux下iic(i2c)读写AT24C02 linux驱动2010-02-09 16:02:03 阅读955 评论3 字号:大中小订阅 linux内核上已有iic的驱动,因此只需要对该iic设备文件进行读写则能够控制外围的iic器件。这里以AT24C02为对象,编写一个简单的读写应用程序。iic设备文件在我的开发板上/dev/i2c/0 ,打开文件为可读写。AT24C02的器件地址为0x50 ,既是iic总线上从器件的地址,每次只读写一字节数据。 /************************************************************/ //文件名:app_at24c02.c //功能:测试linux下iic读写at24c02程序 //使用说明: (1) // (2) // (3) // (4) //作者:jammy-lee //日期:2010-02-08 /************************************************************/ //包含头文件 #include #include #include #include #include #include #include

#include #include #include //宏定义 #define Address 0x50 //at24c02地址 #define I2C_RETRIES 0x0701 #define I2C_TIMEOUT 0x0702 #define I2C_SLAVE 0x0703 //IIC从器件的地址设置 #define I2C_BUS_MODE 0x0780 typedef unsigned char uint8; uint8 rbuf[8] = {0x00}; //读出缓存 uint8 wbuf[8] = {0x01,0x05,0x06,0x04,0x01,0x01,0x03,0x0d}; //写入缓存int fd = -1; //函数声明 static uint8 AT24C02_Init(void); static uint8 i2c_write(int fd, uint8 reg, uint8 val); static uint8 i2c_read(int fd, uint8 reg, uint8 *val); static uint8 printarray(uint8 Array[], uint8 Num); //at24c02初始化 static uint8 AT24C02_Init(void) { fd = open("/dev/i2c/0", O_RDWR); //允许读写 if(fd < 0) { perror("Can't open /dev/nrf24l01 \n"); //打开iic设备文件失败 exit(1);

I2C接口的输入与输出驱动的

I2C接口的输入与输出驱动的PCF8574- pcf8574采用I2C接口,有8个准双向口,可以和外部电路连接,来实现输入输出功能,可以用来对口线进行扩展 有几点需要注意 1.某位作为输入的时候,必须首先置为高电平 2.地址是0100 A2 A1 A0 R/W 3.最多可以扩展8片 4.低电流损耗,静态电流10uA,驱动电流比较大,而且有索存功能,能够驱动LED 发光管 5.带有外部中断输出,低电平有效 我作了一个电路,其中P7-P4作为输入检测开关状态,P3-P0作为输出来驱动LED 灯 程序如下 #include "reg51.h" #define SETBIT(VAR,Place) (VAR|=(1<

unsigned char IC_Re_Time; unsigned char IC_Err_Flag; void Timer0_Init(void) { TMOD=0x00;//timer0工作定时器方式0,13位技术 TH0=0x1e;//5ms TL0=0x0c;//5ms TR0=1;//启动时钟0 ET0=1;//允许时钟0进行中断 EA=1;//开放所有中断 } void Delay(void) { unsigned char i; for(i=0;i<=10;i++) { ; } } unsigned char VALBIT(unsigned int Val,unsigned char Bit) { unsigned int Buf; Buf=0x0001; if(Bit) Buf<<=Bit;

实例解析linux内核I2C体系结构(2)

实例解析linux内核I2C体系结构(2) 华清远见刘洪涛四、在内核里写i2c设备驱动的两种方式 前文介绍了利用/dev/i2c-0在应用层完成对i2c设备的操作,但很多时候我们还是习惯为i2c设备在内核层编写驱动程序。目前内核支持两种编写i2c驱动程序的方式。下面分别介绍这两种方式的实现。这里分别称这两种方式为“Adapter方式(LEGACY)”和“Probe方式(new style)”。 (1)Adapter方式(LEGACY) (下面的实例代码是在2.6.27内核的pca953x.c基础上修改的,原始代码采用的是本文将要讨论的第2种方式,即Probe方式) ●构建i2c_driver static struct i2c_driver pca953x_driver = { .driver = { .name= "pca953x", //名称 }, .id= ID_PCA9555,//id号 .attach_adapter= pca953x_attach_adapter, //调用适配器连接设备 .detach_client= pca953x_detach_client,//让设备脱离适配器 }; ●注册i2c_driver static int __init pca953x_init(void) { return i2c_add_driver(&pca953x_driver); } module_init(pca953x_init); ●attach_adapter动作 执行i2c_add_driver(&pca953x_driver)后会,如果内核中已经注册了i2c适配器,则顺序调用这些适配器来连接我们的i2c设备。此过程是通过调用i2c_driver中的attach_adapter方法完成的。具体实现形式如下: static int pca953x_attach_adapter(struct i2c_adapter *adapter) { return i2c_probe(adapter, &addr_data, pca953x_detect); /* adapter:适配器 addr_data:地址信息 pca953x_detect:探测到设备后调用的函数 */ } 地址信息addr_data是由下面代码指定的。 /* Addresses to scan */ static unsigned short normal_i2c[] = {0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,I2C_CLIENT_END}; I2C_CLIENT_INSMOD;

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()相反的功能。用于内存和中断等系统资源的释放和注销。 3)总线驱动i2c-davinci.c中,定义了i2c_davinci_xfer函数。该函数是I2C总线通信传输函数。并且I2C适配器对应的i2c_algorithm结构体实例为i2c_davinci_algo,其中的master_xfer函数指针指向i2c_davinci_xfer函数。 4)当设备被打开,并且用户开始读操作时,会调用设备驱动lm75.c中show_temp()函数,该函数会调用i2c-core.c中的i2c_smbus_xfer()函数,i2c_smbus_xfer()函数会检查适配器对应的i2c_algorithm结构体中是否注册了smbus_xfer函数(目前i2c_davinci_algo中未注册smbus_xfer函数),程序会调用i2c_smbus_xfer_emulated()函数,最终,还是会调用标准的I2C总线通信函数master_xfer(),由于master_xfer 已经指向i2c_davinci_xfer函数,所以会调用总线驱动i2c-davinci.c中的i2c_davinci_xfer函数来读取信息。 三、接口函数 1)应用层接口: Int lm75a_temp_read(float *temp) 读取lm75a 温度 2)内核中:lm75.c文件 static ssize_t show_temp(struct device *dev, struct device_attribute *da,char *buf)

i2c总线原理

I2C总线原理 ?什么是I2C总线? I2C即Inter IC,由Philips公司开发,是当今电子设计中应用非常广泛的串行总线之一,主要用于电压、温度监控,EEPROM数据的读写,光模块的管理等。 I2C总线只有两根线,SCL和SDA,SCL即Serial Clock,串行参考时钟,SDA即Serial Data,串行数据。 ?I2C总线的速率能达到多少? 标准模式下:100Kbps 快速模式下:400Kbps 高速模式下:3.4Mbps I2C总线结构如下图所示: 如上图所示,I2C是OC或OD输出结构,使用时必须在芯片外部进行上拉,上拉电阻R的取值根据I2C总线上所挂器件数量及I2C总线的速率有关,一般是标准模式下R选择10kohm,快速模式下R选取1kohm,I2C总线上挂的I2C器件越多,就要求I2C的驱动能力越强,R的取值就要越小,实际设计中,一般是先选取4.7kohm上拉

电阻,然后在调试的时候根据实测的I2C波形再调整R的值。 ?I2C总线上最多能挂多少个I2C器件? I2C总线上允许挂接I2C器件的数量由两个条件决定: 1).I2C从设备的地址位数。I2C标准中有7位地址和10位地址两种。如果是7位地址,允许挂接的I2C器件数量为:27=128,如果是10位地址,允许挂接的I2C 器件数量为:210=1024,一般I2C总线上挂接的I2C器件不会太多,所以现在几乎所有的I2C器件都使用7位地址。 2).挂在I2C总线上所有I2C器件的管脚寄生电容之和。I2C总线规范要求,I2C 总线容性负载最大不能超过470pF。 ?I2C总线是如何工作的? 1).I2C总线传输的特点。 I2C总线按字节传输,即每次传输8bits二进制数据,传输完毕后等待接收端的应答信号ACK,收到应答信号后再传输下一字节。等不到ACK信号后,传输终止。空闲情况下,SCL和SDA都处于高电平状态。 2).如何判断一次传输的开始? 如上图所示,I2C总线传输开始的标志是:SCL信号处于高电平期间,SDA信号出现一个由高电平向低电平的跳变。 3).如何判断一次传输的结束? 如上图所示,I2C总线传输结束的标志是:SCL信号处于高电平期间,SDA信号出现一个由低电平向高电平的跳变。跟开始标识正好相反。 4).什么样的I2C数据才是有效的。

I2C 24CXX驱动程序(真正实用 全)

#define _24cXX_H /* Includes ----------------------------------------------------------------*/ #include "stm32f10x.h" #include "value.h" //#include "stdbool.h" /* Define ------------------------------------------------------------------*/ /* EEPROM Addresses defines */ //注:32 64 的字地址是16位2个字节如果使用32或64请简单修改驱动即可 #define WC24cXX 0x00 // 器件地址写#define RC24cXX 0x01 // 器件地址读 #define USE_24C08 //使用24C08 #ifdef USE_24C02 #define MAXSIZE24cXX 256 // 总容量Bytes //级联时请修改本参数和硬件驱动 #define BLOCK_SIZE 256 // 块容量Bytes #define I2C_PAGESIZE 8 // 8个字节每页 #endif #ifdef USE_24C04 #define MAXSIZE24cXX 512 // 总容量Bytes //级联时请修改本参数和硬件驱动 #define BLOCK_SIZE 256 // 块容量Bytes #define I2C_PAGESIZE 16 // 16个字节每页 #endif #ifdef USE_24C08 #define MAXSIZE24cXX 1024 // 总容量Bytes //级联时请修改本参数和硬件驱动 #define BLOCK_SIZE 256 // 块容量Bytes #define I2C_PAGESIZE 16 // 16个字节每页 /* user define */ #define YBCV_ADDR_0 0x0000 //定义仪表控制数据结构体的EEPROM存储地址0 #define YBCV_ADDR_1 0x0200 //定义仪表控制数据结构体的EEPROM存储地址1 #define EEPROM_VERIFY YB_CTRL_V ALE_SIZE //EEPROM仪表通道修正参数存储地址 #endif #ifdef USE_24C16 #define MAXSIZE24cXX 2048 // 总容量Bytes #define I2C_PAGESIZE 16 // 16个字节每页 #endif

I2C设备与驱动的关联

I2C设备与驱动的关联 作者:leeoo 联系方式:neu_linuxer@https://www.360docs.net/doc/e82181380.html, 在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()函数,以便使其他模块中的函数可以调用此函数。它在完成简单的包装后,调用了driver_register()函数,完成了从平台实现到Linux内核实现的过渡。 在此,我们需要关注一下platform_match()和platform_drv_probe()函数。 platform_match() 函数确定驱动与设备的关联,而platform_drv_probe()函数会在随后介绍的函数中被调用。 //比较驱动信息中的name与设备信息中的name两者是否一致 static int platform_match(struct device * dev, struct device_driver * drv) { struct platform_device *pdev = container_of(dev, struct platform_device, dev); return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0); } struct bus_type platform_bus_type = { .name = "platform", .dev_attrs = platform_dev_attrs, .match = platform_match, .uevent = platform_uevent, .suspend = platform_suspend, .suspend_late = platform_suspend_late, .resume_early = platform_resume_early, .resume = platform_resume, }; EXPORT_SYMBOL_GPL(platform_bus_type); /** * platform_driver_register * @drv: platform driver structure */ int platform_driver_register(struct platform_driver *drv) { drv->driver.bus = &platform_bus_type;

Linux_I2C总线分析(主要是probe的方式)1

Linux I2C 总线浅析 ㈠ Overview 内核空间层次! i2c adapter 是一个struct, 用来抽象一个物理i2c bus ,而且还和linux 设备驱动架构柔和在一起.. 如果只说硬件的话,就是在CPU内部集成的一个I2C控制器(提供给用户的就是那几个register),硬件上并没的所谓的adapter,client这些东东,,adapter和client都是linux 驱动软件抽象出来的东西 资料帖子: i2c_algorithm { /* If an adapter algorithm can't do I2C-level access, set master_xfer to NULL. If an adapter algorithm can do SMBus access, set smbus_xfer. If set to NULL, the SMBus protocol is simulated

using common I2C messages */ /* master_xfer should return the number of messages successfully processed, or a negative value on error */ i nt (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); i nt (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data); /* To determine what the adapter supports */ u32 (*functionality) (struct i2c_adapter *); }; /* * i2c_adapter is the structure used to identify a physical i2c bus along * with the access algorithms necessary to access it. */ struct i2c_adapter { s truct module *owner; u nsigned int id; u nsigned int class; /* classes to allow probing for */ c onst struct i2c_algorithm *algo; /* the algorithm to access the bus */ v oid *algo_data; /* data fields that are valid for all devices */ u8 level; /* nesting level for lockdep */ s truct mutex bus_lock; i nt timeout; /* in jiffies */ i nt retries; s truct device dev; /* the adapter device */ i nt nr; c har name[48]; s truct completion dev_released; }; Linux的I2C体系结构分为3个组成部分: 1·I2C核心: I2C核心提供了I2C总线驱动和设备驱动的注册、注销方法,I2C通信方法(即“algorithm”)上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码等。这部分是与平台无关的。 2·I2C总线驱动: I2C总线驱动是对I2C硬件体系结构中适配器端的实现。I2C总线驱动主要包含了I2C适配

51单片机I2C总线驱动程序

51单片机I2C总线驱动程序 SI2I2C 总线是PHLIPS 公司推出的一种串行总线,是具备多主机系统所需 的包括总线裁决和高低速器件同步功能的高性能串行总线。I2C 总线只有两根 双向信号线。一根是数据线SDA,另一根是时钟线SCL。 一.I2C 系统结构每个接到I2C 总线上的器件都有唯一的地址。主机与其它器 件间的数据传送可以是由主机发送数据到其它器件,这时主机即为发送器。由 总线上接收数据的器件则为接收器。 二.数据位的有效性规定I2C 总线进行数据传送时,时钟信号为高电平期间, 数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线 上的高电平或低电平状态才允许变化。 三.字节传送与应答每一个字节必须保证是8 位长度。数据传送时,先传送最 高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有 9 位)。 四.驱动程序#define uchar unsigned char#define uint unsigned int#define somenop() _nop_(),_nop_(),_nop_(),_nop_(),_nop_(),_nop_()sbit SCL=P2;sb it SDA=P2;123451.起始信号和终止信号 SCL 线为高电平期间,SDA 线由高电平向低电平的变化表示起始信号;SCL 线为高电平期间,SDA 线由低电平向高电平的变化表示终止信号。 起始和终止信号都是由主机发出的,在起始信号产生后,总线就处于被占用 的状态;在终止信号产生后,总线就处于空闲状态 void I2C_Start() //起始{SCL=1;somenop();SDA=1;somenop(); SDA=0;somenop();SCL=0;somenop();}void I2C_Stop() //终止{ SDA=0;somenop();SCL=1;somenop();SDA=1;somenop();}12345678910111213141

实例解析linux内核I2C体系结构

实例解析linux内核I2C体系结构 作者:刘洪涛,华清远见嵌入式学院讲师。 一、概述 谈到在linux系统下编写I2C驱动,目前主要有两种方式,一种是把I2C 设备当作一个普通的字符设备来处理,另一种是利用linux I2C驱动体系结构来完成。下面比较下这两种驱动。 第一种方法的好处(对应第二种方法的劣势)有: ●思路比较直接,不需要花时间去了解linux内核中复杂的I2C子系统的操作方法。 第一种方法问题(对应第二种方法的好处)有: ●要求工程师不仅要对I2C设备的操作熟悉,而且要熟悉I2C的适配器操作; ●要求工程师对I2C的设备器及I2C的设备操作方法都比较熟悉,最重要的是写出的程序可移植性差; ●对内核的资源无法直接使用。因为内核提供的所有I2C设备器及设备驱动都是基于I2C子系统的格式。I2C适配器的操作简单还好,如果遇到复杂的I2C适配器(如:基于PCI的I2C适配器),工作量就会大很多。 本文针对的对象是熟悉I2C协议,并且想使用linux内核子系统的开发人员。 网络和一些书籍上有介绍I2C子系统的源码结构。但发现很多开发人员看了这些文章后,还是不清楚自己究竟该做些什么。究其原因还是没弄清楚I2C子系统为我们做了些什么,以及我们怎样利用I2C子系统。本文首先要解决是如何利用现有内核支持的I2C适配器,完成对I2C设备的操作,然后再过度到适配器代码的编写。本文主要从解决问题的角度去写,不会涉及特别详细的代码跟踪。 二、I2C设备驱动程序编写 首先要明确适配器驱动的作用是让我们能够通过它发出符合I2C标准协议的时序。 在Linux内核源代码中的drivers/i2c/busses目录下包含着一些适配器的驱动。如S3C2410的驱动i2c-s3c2410.c。当适配器加载到内核后,接下来的工作就要针对具体的设备编写设备驱动了。

linux i2c驱动

linux i2c驱动 1. i2c-dev interface I2C dev-interface 通常,i2c设备由某个内核驱动控制。但是在用户空间,也可以访问某个I2C设备:你需要 加载i2c-dev模块。 每个被注册的i2c适配器(控制器)会获得一个数字号,从0开始。你可以检查/sys/class/i2c-dev,来查看适配器对应哪个数字号。你也可以通过命令 "i2cdetect -l"获 取你的当前系统的所有I2c适配器的列表。i2cdetct是i2c-tool包中的一个工具。 i2c设备文件是字符设备,主设备号是89,次设备号的分配如上所述。设备文件名通常被 规定为"i2c-%d"(i2c-0, i2c-1, ...,i2c-10, ...)i2c设备文件是字符设备, 主设备号是 89,次设备号的分配如上所述。设备文件名通常被规定为"i2c-%d"(i2c-0, i2c-1, ...,i2c-10, ...).所有256个次设备号都保留给i2c使用。 C example ========= 假定你要在你的C应用程序中访问i2c适配器。第一件事情就是包含头文件 "#include "。注意,存在两个"i2c-dev.h"文件: 一个属于Linux kernel,用于 内核驱动中;一个由i2c-tools发布,用于用户程序。显然,这里需要使用第二个 i2c-dev.h文件。 现在,你需要确定访问哪个适配器。你需要通过查看/sys/class/i2c-dev/或者运行 "i2cdetect -l"确定。适配器号时常是动态分配的,你无法预先假定某个值。因为它们甚 至会在系统重启后变为不同的值。 下一步,打开设备文件,如下: int file; int adapter_nr = 2; /*probably dynamically determined */ char filename[20];

i2c驱动程序总结

I2C驱动程序总结 由于6410没有合适的i2c参考驱动,本总结主要基于TQ2440的AT24C02 一、TQ2440电路 二、I2c驱动程序分析 1写入口函数at24cxx_init() 在入口函数中主要有一个增加设备驱动的函数i2c_add_driver(),该函数会调用i2c_register_driver(THIS_MODULE, 驱动名字)完成注册。 2写出口函数at24cxx_exit() 在出口函数里主要有一个删除设备驱动的函数i2c_del_driver(),这个函数功能有从设备驱动链表中删除驱动,卸载注册的驱动等 3修饰入口函数和出口函数 module_init(at24cxx_init); 这样,使用insmod命令加载驱动模块时,入口函数 at24cxx_init()就会被调用 module_exit(at24cxx_exit); 这样,使用rmmod命令加载驱动模块时,入口函数 at24cxx_exit()就会被调用 4写I2C驱动主要是:分配一个i2c_driver结构体 设置填充i2c_driver结构体

注册(前面1、2、3步) staticstruct i2c_driver at24cxx_driver={ .driver = { .name = “at24cxx”, } .attach_adapter = at24cxx_attach, .detach_client = at24cxx_detach }; 函数at24cxx_attach()和at24cxx_detach需要自己构造 5构造at24cxx_attach()函数和at24cxx_detach()函数 Static int at24cxx_attach(struct i2c_adapter *adapter){ return i2c_probe(adapter,&addr_data,at24cxx_detect); } I2c_probe函数主要是通过适配器adapter发送结构体addr_data的地址,这个地址就是i2c设备的地址,需要自己根据硬件原理图定义的,如果收到回应,就是说有这个i2c设备,就调用at24cxx_detect处理,这个函数需要自己去构造的。 class_device_destroy(cls, MKDEV(major, 0)); class_destroy(cls); unregister_chrdev(major, "at24cxx"); i2c_detach_client(client); kfree(i2c_get_clientdata(client)); 卸载函数主要是把申请的主设备号注销掉,注销掉注册的设备,解除适配器上的设备驱动,最后释放申请的设备空间。 6、构造addr_data结构体 static unsigned short ignore[] = { I2C_CLIENT_END }; static unsigned short normal_addr[] = { 0x50, I2C_CLIENT_END }; 这里需要注意的是,I2C 设备的设备地址为7 位地址,不算第八位的R/W控制位,由电路图和i2c的数据手册可得出设备的地址。 所以i2c设备的地址为1010000,即0x50 staticstruct i2c_client_address_data addr_data = { .normal_i2c = normal_addr, /* 要发出S信号和设备地址并得到ACK信号,才能确定 存在这个设备*/ .probe = ignore, .ignore = ignore, //.forces = forces, /* 强制认为存在这个设备*/ };

相关文档
最新文档