当前位置: 首页 > news >正文

淄博市建设局网站中国移动和办公app下载

淄博市建设局网站,中国移动和办公app下载,网站建设置顶,网站建设中问题分析与解决目录 一、本章目标 二、IIC设备驱动 2.1 I2C协议简介 2.2 LinuxI2C驱动 2.3 I2C 设备驱动实例 一、本章目标 一条总线可以将多个设备连接在一起#xff0c;提高了系统的可扩展性能。这个互联的系统通常由三部分组成:总线控制器、物理总线(一组信号线) 和设备。总线控制器…目录 一、本章目标 二、IIC设备驱动 2.1  I2C协议简介 2.2 LinuxI2C驱动 2.3 I2C 设备驱动实例 一、本章目标 一条总线可以将多个设备连接在一起提高了系统的可扩展性能。这个互联的系统通常由三部分组成:总线控制器、物理总线(一组信号线) 和设备。总线控制器和设备通过总线连接在一起总线控制器可以发起对总线上设备的访问操作。通常总线控制器有一个驱动程序用于控制总线控制器来操作总线从而来访问设备这一类驱动通常在内核中都已实现了。连接在总线上的设备也可能有一段程序要运行这段程序可能是不基于操作系统的裸机程序 (俗称固件)也可能是基于操作系统的一个驱动。最后还有一类驱动程序它们通常调用总线控制器的驱动程序来完成对总线上具体设备的访问这类驱动程序的叫法不一这里统称为设备驱动(一定要和前面说到的运行在设备本身的固件或驱动区分开)这也是本章重点讨论的内容。本章依次讨论了最常见的I2C总线、SPI总线、USB总线和PCI总线的设备驱动。今天先来学习IIC。 二、IIC设备驱动 2.1  I2C协议简介 I2C(Intel-Integrated Circuit)是由飞利浦(现在叫恩智浦)公司开发的一种慢速两线制总线协议。最初总线的速率定为 100KHz经过发展速率出现了 400KHz、3.4MHZ、1MHz和5MHz的不同等级目前大多数器件都支持400KHz。不过速率是可变的比如一个支持400KHz的器件完全可以工作在299KHz这个速率上只要不超过400KHz即可。I2C 总线为那些不需要经常访问、低带宽的设备提供了一种廉价的互联方式被广泛地应用在嵌入式系统设备当中。不过 I2C 总线协议有商标上的一些限制有些厂家为了避免这种限制使用了另外一种总线协议 SMBus(System Management Bus)。SMBus 总线协议其实是I2C总线协议的一个子集,绝大多数I2C 设备都能够在SMBus 总线上工作现在的计算机主板通常使用 SMBus 总线最常见的就是内存条上的 EEPROM 配置芯片. I2C 总线由 SCL (串行时钟线)和 SDA(串行数据线)两条线组成其上连接有主机控制器(Master在 Linux 驱动中称为 Adapter) 和从设备 (Slave在 Linux 驱动中称为 Client)。所有的访问操作都是由主机控制器发起的在同一条总线上可以有多个主机控制器当多个主机控制器同时对设备发起访问时由协议的冲突检测和仲裁机制来保证只有一个主机控制器对从设备进行访问。多个从设备是通过从设备的地址来区分的,地址分为7位地址和10 位地址两种常见的是7位地址。下图是具有两个主机控制器的I2C总线连接图总线控制器由微控制器来充当从设备有门阵列、LCD 驱动器ADC和 EEPROM。 下面以图示方式来说明12C 的总线时序 开始位:当SCL为高电平时SDA 由高电平变为低电平的期间如图中最左边的STARTcondition 所标记的区域这表示主机控制器要开始对从机发起访问了。地址位:接下来的7个时钟周期主机控制器将会发送从机的 7位地址(如果是 10位地址需要分两次发送)如图中ADDRESS 所标记的区域。读/写位:在第8个时钟周期如果 SDA 为高电平则表示接下来要读取从机的数据如果是低电平则表示主机要写数据到从机如图 10.2中 R/W所标记的区域。应答位:在第9个时钟周期由从机进行应答低电平为 ACK高电平为 NACK如果从机响应应该发ACK。 数据位:在接下来的若干个周期内主机可以持续读取数据(如果读/写位为读)或号数据(如果读/写位为写)每次数据传输完成(如图 10.2中的 DATA 所标记的区域)也要进行应答是读则由主机控制器来应答是写则由从机来应答只是在主机读完最后一个字节的数据后应该以 NACK 来应答。停止位::当SCL 为高电平时SDA 由低电平变为高电平的期间如图10.2中最右边的STOP condition 所标记的区域这表示主机控制器结束了对从机的访问 I2C 从设备内部通常有若干个寄存器每个寄存器都有一个地址对这些从设备的访问通常是顺序访问的。比如上次从寄存器 2开始连续访问了 4 个寄存器那么下次访问将从寄存器6开始。不过按照下图的时序可以实现随机的读和写访问。 随机写访问是在主机发送完从机地址和写标志位从机应答后主机继续写寄存器地址如图 10.3 中的 RA 所示。当从机对写入的寄存器地址进行应答后主机才写入真正的数据。对随机读访问则要复杂一些在寄存器地址写入从机应答后主机需要再次发送开始位然后发送从机地址和读标志位之后才是读操作。 2.2 LinuxI2C驱动 I2C驱动层次结构如图10.5所示。I2C主机驱动:I2C 主机控制器的驱动一般由 SoC 芯片厂商负责设计实现用于控制I2C主机控制器发出时序信号。I2CCore:为上层提供统一的API接口和对其他模块进行注册和注销等管理等. I2C 设备驱动:调用12C Core 提供的统一 API根据I2C 设备的访问规范控制I2主机控制器发出不同的时序信号对12C 设备进行访问。该驱动称为内核层I2C 设备驱动 i2c-dev:将I2C主机控制器实现为一个字符设备应用程序可以直接访问/dev/i2c-N来访问12C 主机控制器从而对12C 设备发起访问该应用程序称为应用层I2C 设备驱动 I2C Core 为屏蔽不同的 I2C 主机控制器驱动提供了可能可以使 I2C 设备驱动仅关心如何操作 I2C 设备而不需要了解 12C 主机控制器的细节从而使I2C 设备驱动可以独立的存在适用于各种不同的硬件平台。         I2C 驱动和我们之前接触到的平台总线设备驱动非常类似都有总线、设备和驱动这三者。12C 的设备由 struct i2c_client 来进行描述类似于 struct platform_device但是我们较少自己来创建这个结构对象。通常在一个嵌入式系统中我们是知道一个 I2C设备的地址、驱动的名字和连接的主机控制器等信息的。对 I2C 设备的描述和向内核的注册操作可以通过类似于下面的代码来实现具体可以参考linux-3.14/arch/arm/mach-s3c24xx/mach-mini2440.c 486 /* 487 * I2C devices 488 */ 489 static struct at24_platform_data at24c08 { 490 .byte_len SZ_8K / 8, 491 .page_size 16, 492 }; 493 494 static struct i2c_board_info mini2440_i2c_devs[] __initdata { 495 { 496 I2C_BOARD_INFO(24c08, 0x50), 497 .platform_data at24c08, 498 }, 499 }; ...... 676 i2c_register_board_info(0, mini2440_i2c_devs, 677 ARRAY_SIZE(mini2440_i2c_devs));i2c_board_info 用于描述某些信息已知的 12C 设备通常用I2C_BOARD_INFO宏来描述基本信息包括驱动的名字和设备的地址。上面的代码定义了一个 i2c_board_info的数组 mini2440_i2c_devs里面有一个设备其对应的12C 设备驱动的名字是 24c08设备地址为0x50。另外platform_data 指定了其他的一些设备数据如这片 EEPROM 的存储容量和页大小信息。最后使用 i2c_register_board_info 将 mini2440_i2c_devs 数组中的所有设备都注册到了 0号 I2C 总线上。 但随着设备树的出现上述方法基本被淘汰了取而代之的是用设备树节点来进行I2C 设备的描述。Exynos4412 的 I2C 设备节点描述请参见内核文档 Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt。在该文档中给出了一个具体的实例代码如下。 38 i2c13870000 { 39 compatible samsung,s3c2440-i2c;40 reg 0x13870000 0x100;41 interrupts 345;42 samsung,i2c-sda-delay 100;43 samsung,i2c-max-bus-freq 100000;44 /* Samsung GPIO variant begins here */45 gpios gpd1 2 0 /* SDA */46 gpd1 3 0 /* SCL */;47 /* Samsung GPIO variant ends here */48 /* Pinctrl variant begins here */49 pinctrl-0 i2c3_bus;50 pinctrl-names default;51 /* Pinctrl variant ends here */52 #address-cells 1;53 #size-cells 0;54 55 wm89941a {56 compatible wlf,wm8994;57 reg 0x1a;58 };59 };i2c13870000 是一个12C 主机控制器节点里面的 compatible、reg、interrupts 等属性指定了其匹配的主机控制器驱动、I/O 内存的范围和使用的中断等信息。作为一个 12C设备驱动开发者来说这些信息我们通常不关心。我们需要关心的是接在这个主机控制器上的 12C 设备的子节点如何来描述。上面例子中的子节点 wm8994la 中的 compatible属性给出了匹配的驱动而 reg 指定了 12C 设备的地址。也就是说如果我们要编写一个I2C 设备的节点信息则只需要在对应的 I2C 主机控制器节点中编写一个子节点给出compatible 和reg 属性即可。对比一下这其实和 I2c_board_info 所描述的信息基本一样只是形式不同而已。         在内核的启动过程中会自动将这些信息转换为一个 struct i2c_client 结构对象当有匹配的驱动注册时同样会像平台驱动一样调用其 probe 函数。接下来我们就来看看I2C 驱动核心的数据结构是 struct i2c_driver其定义如下。   struct i2c_driver{ ......int (*probe)(struct i2c_client *, const struct i2c_device_id *);\int (*remove)(struct i2c_client *);void (*shutdown)(struct i2c_client *);int (*suspend)(struct i2c_client *, pm_message_t mesg);int (*resume)(struct i2c_client *); ......struct device_driver driver;const struct i2c_device_id *id_table; ...... }; 上面省略了 I2C 设备驱动开发者较少关心的成员不难发现这和前面的 struct platform_driver 基本一样所以在此就不再赘述。struct i2c_driver 相关的主要 API 罗列如下。 i2c_add_driver(driver)void i2c_del_driver(struct i2c_driver *driver);void i2c_set_clientdata(struct i2c_client *dev, void *data);void *i2c_get_clientdata(const struct i2c_client *dev);int i2c_check_functionality(struct i2c_adapter *adap, u32 func); i2c add driver; 添加I2C 设备驱动。 i2c del driver: 删除 I2C 设备驱动。 i2c set clientdata: 将 data 保存在 struct i2c client 结构中 i2c get_clientdata: 从 struct i2c_client 中获取保存的数据 i2c_check_functionality: 查 12C 从设备所绑定的主机控制器是否支持 func 中指定的所有功能常见的功能如下。 I2C_FUNC_10BIT_ADDR: 十位地址 I2C_PUNC_SMBUS_READ_BYTE_DATA:单字节随机读 I2C_EUNC_SMBUS_WRITE_BYTE_DATA: 单字节随机写 I2C_FUNC_SMBUS_READ_BLOCK_DATA: 多字节随机读 I2C_FUNC_SMBUS_WRITE_BLOCK_DATA:多字节随机写 简单的 I2C 数据收发相关的函数原型如下。 int i2c_master_send(const struct i2c_client *client, const char *buf, int count); int i2c_master_recv(const struct 12c_client *client, char *buf, int count); int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);i2c_master_send:向12C 从设备写数据I2C 设备的地址包含在 client 中要写的数 缓冲区地址为 buf写的字节数为 count返回成功写入的字节数负数表示失败。 i2c_master_recv: 从12C 从设备读数据参数和返回值同写操作。 i2c_transfer: 可以将几个读写操作合并在一起执行的函数adap 是执行读写操作的2C主机控制器msgs 是消息数组num 是消息的条数。消息的结构类型定义如下。 struct i2c_msg {_u16 addr;_u16 flags;_ul6 len;_u8 *buf; }; addr:I2C 从设备的地址。 flags: 操作的一些标志常见的有 I2C_M_RD表示本次是读操作。I2C_M_TEN,表示使用的是 10 位 I2C 设备地址。 len:本次要读或写的数据字节数。 buf:数据缓冲区指针。 如果要向设备先写后读可以通过类似于下面的代码来实现。   msgs[0].len1; msgs[0].addr0x48; msgs[0].flags0; msgs[0].buftxbuf; msgs[0].buf[0]0x0; msgs[1].len2; msgs[1].addr0x48; msgs[1],flagsI2C_M_RD; msgs[1].bufrxbuf; msgs[1].buf[0]0; msgs[1].buf[1]0; i2c_transfer(client-adapter, msgs,2); 上面的代码构造了两条消息两条消息都是要操作设备地址为 0x48 的 12C 备第一条消息是向设备写 1个字节的数据第二条消息是读两个字节的数据。 i2c_transfer 不要求每条消息的地址都是一样的该函数返回被成功执行的消息条数 为负表示失败。还有一些适合于 SMBus 的更简单的 API如下所示。 s32 i2c_smbus_read_byte_data (struct i2c_client *client, u8 command); s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value); s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command, u8 *values); s32 i2c_smbus_write_block_data(struct i2c_elient *client, u8 command, u8 length,const u8 *values); 上面的函数为单字节或多字节的随机读写函数command 是 SMBus 中的命令通常是 i2C 设备内部的寄存器地址。返回的是实际读写的字节数为负表示失败。其他参数都很好理解这里不再详细说明。         我们前面谈到如果把 12C 主机控制器实现为一个字符设备应用程序可以通过对应的设备来直接访问 12C 主机控制器从而产生相应的时序来访问 12C 从设备这样应用程序叫应用层 i2C 设备驱动。不过这需要配置内核以确保这一功能被选中配置如下。 内核配置并重新编译后目标板使用新的内核镜像系统启动后可以看到如下的 设备。 使能的主机控制器节点越多设备文件就会越多。 应用层也有相关的 API最主要的如下。 ioctl(fileI2C_SLAVE,long addr) ioctl(fileI2C FUNCS, unsigned long *funcs) ioctl(fileI2C_RDWR, struct i2c_rdwr_ioctl_data *msgset) __s32 i2c_smbus_read_byte_data(int file,__u8 command) __s32 i2c_smbus_write_byte_data(int file,__u8 command,__u8 value); __s32 i2c_smbus_read_block_data(int file,__u8 command,__u8 *values); __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length,__u8 *values); I2C_SLAVE: 设置要访问的从机设备地址。 I2C_FUNCS: 获取主机控制器的功能。 I2C_RDWR:读写 12C 设备读写操作由 msgset 来指定其类型定义如下。 struct i2c_rdwr_ioctl_data {struct i2c_msg *msgs;int nmsgs; } 其中的 struct i2c_msg 我们在前面已经见过了。针对前面的内核层 i2C 设备驱动的例子而言应用层 I2C 设备驱动代码如下。   i2c_data.nmsgs2; i2c_data.msgs[0].len1; i2c_data.msgs[0].addr0x48; 12c_data.msgs[0].flags0; i2c_data.msgs[0].buftxbuf; i2c_data.msgs[0].buf[0]0x0; i2c_data.msgs[1].len2; i2c_data.msgs[1].addr0x48; i2c_data.msgs[1].flagsI2C_M_RD; i2c_data.msgs[1].bufrxbuf; i2c_data.msgs[1].buf[0]0; i2c_data.msgs[1].buf[1]0; ioctl(fd,I2C_RDWR,(unsigned long)i2c_data); i2c_smbus_read_byte_data 之类的函数和前面内核层中的含义一样此处不再细述. 2.3 I2C 设备驱动实例 在 FS4412 目标板上有一个集陀螺仪、三轴加速度传感器和温度传感器于一体的器件MPU6050相关的原理图如图所示。 MPU6050 连接在 Exynos4412 编号为 5 的 i2C 主机控制器上MPU6050 设备的地址为 0x68根据前面的知识并查阅 Exynos4412 的用户手册可以得出相应的设备节点代码。 i2c138B0000{samsung,i2c-sda-delay 100;samsung,i2c-max-bus-freq 20000;pinctr1-0 i2c5_bus;pinctrl-names default;status okay;mpu605068 {compatiblefs4412,mpu6050;reg 0x68;}; }; 重新编译设备树给目标板使用系统启动后将会多出一个 i2c-5 的字符设备 正常应该只有一个i2c-0设备的上面那个是已经配好的所以有个i2c-5 MPU6050 的寄存器非常多但是只是简单获取一些传感数据关注如图几个寄存器就可以了。 /****************MPU6050内部常用寄存器地址****************/#define SMPLRT_DIV 0x19 //陀螺仪采样率,典型值:0x07(125Hz) #define CONFIG 0x1A //低通滤波频率,典型值:0x06(5Hz) #define GYRO_CONFIG 0x1B //陀螺仪自检及测量范围,典型值:0x18(不自检,2000°/s) #define ACCEL_CONFIG 0x1C //加速计自检及测量范围及高通滤波频率,典型值:0x0(不自检,2G,5Hz) #define ACCEL_XOUT_H 0x3B #define ACCEL_XOUT_L 0x3C #define ACCEL_YOUT_H 0x3D #define ACCEL_YOUT_L 0x3E #define ACCEL_ZOUT_H 0x3F #define ACCEL_ZOUT_L 0x40 #define TEMP_OUT_H 0x41 #define TEMP_OUT_L 0x42 #define GYRO_XOUT_H 0x43 #define GYRO_XOUT_L 0x44 #define GYRO_YOUT_H 0x45 #define GYRO_YOUT_L 0x46 #define GYRO_ZOUT_H 0x47 #define GYRO_ZOUT_L 0x48 #define PWR_MGMT_1 0x6B //电源管理,典型值:0x00(正常启用) #define SlaveAddress 0x68 //MPU6050-I2C地址 SMPLRT_DIV: 采样时钟分频值相应的公式为:采样率 陀螺仪输出频率 /(1 SMPLRT_DIV)。CONFIG: EXT_SYNC_SET 是外部同步的配置不需要设为0 即可。DLPF_CFG是数字低通滤波器的配置它将决定陀螺仪和三轴加速度传感器的带宽和延时值最大可配置的值为 6。GYRO_CONFIG: 陀螺配置寄存器FS_SEL 用于选择陀螺仪的输出范围设置值和范围如图 所示 ACCEL_CONFIG: 三轴加速度传感器配置寄存器AFS_SEL 用于三轴加速度传感器的输出范围设置值和范围如图所示。 ACCEL_xxx、TEMP_xxx、GYRO xxx:传感器输出值三者的换算关系如下。 三轴加速度 采样值 /n, n 根据 FS_SEL 的值 0、1、2、3 分别对应为 16384、8192、4096、2048。         温度 采样值 /340 36.53。 陀螺仪角速度 采样值 /n,n 根据 AFS_SEL 的值 0、1、2、3 分别对应为 131、65.5、32.8、16.4。         PWR_MGMT_1:电源管理寄存器 1。DEVICE_RESET 用于复位整个芯片。SLEEP是休眠控制为1表示休眠。CYCLE 是循环模式控制如果 SLEEP 为0CYCLE为1,那么传感器将会定期醒来进行采样。TEMP_ DIS 为1禁止温度传感器CLKSEL 为0选择内部的 8MHz 时钟。         根据以上对寄存器的介绍可以写出如下的应用层 I2C 设备驱动代码 /*i2c-dev.h - i2c-bus driver, char device interfaceCopyright (C) 1995-97 Simon G. VoglCopyright (C) 1998-99 Frodo Looijaard frodoldds.nlThis program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2 of the License, or(at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston,MA 02110-1301 USA. *//* $Id: i2c-dev.h 5361 2008-10-19 09:47:02Z khali $ */#ifndef LIB_I2CDEV_H #define LIB_I2CDEV_H#include linux/types.h #include sys/ioctl.h/* -- i2c.h -- *//** I2C Message - used for pure i2c transaction, also from /dev interface*/ struct i2c_msg {__u16 addr; /* slave address */unsigned short flags; #define I2C_M_TEN 0x10 /* we have a ten bit chip address */ #define I2C_M_RD 0x01 #define I2C_M_NOSTART 0x4000 #define I2C_M_REV_DIR_ADDR 0x2000 #define I2C_M_IGNORE_NAK 0x1000 #define I2C_M_NO_RD_ACK 0x0800short len; /* msg length */char *buf; /* pointer to msg data */ };/* To determine what functionality is present */#define I2C_FUNC_I2C 0x00000001 #define I2C_FUNC_10BIT_ADDR 0x00000002 #define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */ #define I2C_FUNC_SMBUS_PEC 0x00000008 #define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ #define I2C_FUNC_SMBUS_QUICK 0x00010000 #define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 #define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000 #define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000 #define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000 #define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000 #define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000 #define I2C_FUNC_SMBUS_PROC_CALL 0x00800000 #define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 #define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \I2C_FUNC_SMBUS_WRITE_BYTE) #define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \I2C_FUNC_SMBUS_WRITE_BYTE_DATA) #define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \I2C_FUNC_SMBUS_WRITE_WORD_DATA) #define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) #define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)/* Old name, for compatibility */ #define I2C_FUNC_SMBUS_HWPEC_CALC I2C_FUNC_SMBUS_PEC/* * Data for SMBus Messages */ #define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ #define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */ union i2c_smbus_data {__u8 byte;__u16 word;__u8 block[I2C_SMBUS_BLOCK_MAX 2]; /* block[0] is used for length *//* and one more for PEC */ };/* smbus_access read or write markers */ #define I2C_SMBUS_READ 1 #define I2C_SMBUS_WRITE 0/* SMBus transaction types (size parameter in the above functions) Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */ #define I2C_SMBUS_QUICK 0 #define I2C_SMBUS_BYTE 1 #define I2C_SMBUS_BYTE_DATA 2 #define I2C_SMBUS_WORD_DATA 3 #define I2C_SMBUS_PROC_CALL 4 #define I2C_SMBUS_BLOCK_DATA 5 #define I2C_SMBUS_I2C_BLOCK_BROKEN 6 #define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ #define I2C_SMBUS_I2C_BLOCK_DATA 8/* ----- commands for the ioctl like i2c_command call:* note that additional calls are defined in the algorithm and hw * dependent layers - these can be listed here, or see the * corresponding header files.*//* - bit-adapter specific ioctls */ #define I2C_RETRIES 0x0701 /* number of times a device address *//* should be polled when not *//* acknowledging */ #define I2C_TIMEOUT 0x0702 /* set timeout - call with int *//* this is for i2c-dev.c */ #define I2C_SLAVE 0x0703 /* Change slave address *//* Attn.: Slave address is 7 or 10 bits */ #define I2C_SLAVE_FORCE 0x0706 /* Change slave address *//* Attn.: Slave address is 7 or 10 bits *//* This changes the address, even if it *//* is already taken! */ #define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, ! 0 for 10 bit */#define I2C_FUNCS 0x0705 /* Get the adapter functionality */ #define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/ #define I2C_PEC 0x0708 /* ! 0 for SMBus PEC */#define I2C_SMBUS 0x0720 /* SMBus-level access *//* -- i2c.h -- *//* Note: 10-bit addresses are NOT supported! *//* This is the structure as used in the I2C_SMBUS ioctl call */ struct i2c_smbus_ioctl_data {char read_write;__u8 command;int size;union i2c_smbus_data *data; };/* This is the structure as used in the I2C_RDWR ioctl call */ struct i2c_rdwr_ioctl_data {struct i2c_msg *msgs; /* pointers to i2c_msgs */int nmsgs; /* number of i2c_msgs */ };static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, int size, union i2c_smbus_data *data) {struct i2c_smbus_ioctl_data args;args.read_write read_write;args.command command;args.size size;args.data data;return ioctl(file,I2C_SMBUS,args); }static inline __s32 i2c_smbus_write_quick(int file, __u8 value) {return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL); }static inline __s32 i2c_smbus_read_byte(int file) {union i2c_smbus_data data;if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,data))return -1;elsereturn 0x0FF data.byte; }static inline __s32 i2c_smbus_write_byte(int file, __u8 value) {return i2c_smbus_access(file,I2C_SMBUS_WRITE,value,I2C_SMBUS_BYTE,NULL); }static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command) {union i2c_smbus_data data;if (i2c_smbus_access(file,I2C_SMBUS_READ,command,I2C_SMBUS_BYTE_DATA,data))return -1;elsereturn 0x0FF data.byte; }static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value) {union i2c_smbus_data data;data.byte value;return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,I2C_SMBUS_BYTE_DATA, data); }static inline __s32 i2c_smbus_read_word_data(int file, __u8 command) {union i2c_smbus_data data;if (i2c_smbus_access(file,I2C_SMBUS_READ,command,I2C_SMBUS_WORD_DATA,data))return -1;elsereturn 0x0FFFF data.word; }static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value) {union i2c_smbus_data data;data.word value;return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,I2C_SMBUS_WORD_DATA, data); }static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value) {union i2c_smbus_data data;data.word value;if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,I2C_SMBUS_PROC_CALL,data))return -1;elsereturn 0x0FFFF data.word; }/* Returns the number of read bytes */ static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values) {union i2c_smbus_data data;int i;if (i2c_smbus_access(file,I2C_SMBUS_READ,command,I2C_SMBUS_BLOCK_DATA,data))return -1;else {for (i 1; i data.block[0]; i)values[i-1] data.block[i];return data.block[0];} }static inline __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, __u8 *values) {union i2c_smbus_data data;int i;if (length 32)length 32;for (i 1; i length; i)data.block[i] values[i-1];data.block[0] length;return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,I2C_SMBUS_BLOCK_DATA, data); }/* Returns the number of read bytes */ /* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If youask for less than 32 bytes, your code will only work with kernels2.6.23 and later. */ static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command,__u8 length, __u8 *values) {union i2c_smbus_data data;int i;if (length 32)length 32;data.block[0] length;if (i2c_smbus_access(file,I2C_SMBUS_READ,command,length 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :I2C_SMBUS_I2C_BLOCK_DATA,data))return -1;else {for (i 1; i data.block[0]; i)values[i-1] data.block[i];return data.block[0];} }static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,__u8 length, __u8 *values) {union i2c_smbus_data data;int i;if (length 32)length 32;for (i 1; i length; i)data.block[i] values[i-1];data.block[0] length;return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,I2C_SMBUS_I2C_BLOCK_BROKEN, data); }/* Returns the number of read bytes */ static inline __s32 i2c_smbus_block_process_call(int file, __u8 command,__u8 length, __u8 *values) {union i2c_smbus_data data;int i;if (length 32)length 32;for (i 1; i length; i)data.block[i] values[i-1];data.block[0] length;if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command,I2C_SMBUS_BLOCK_PROC_CALL,data))return -1;else {for (i 1; i data.block[0]; i)values[i-1] data.block[i];return data.block[0];} }#endif /* LIB_I2CDEV_H */#include stdio.h #include stdlib.h #include sys/types.h #include sys/stat.h #include sys/ioctl.h #include fcntl.h #include errno.h#include i2c-dev.h#define SMPLRT_DIV 0x19 #define CONFIG 0x1A #define GYRO_CONFIG 0x1B #define ACCEL_CONFIG 0x1C #define ACCEL_XOUT_H 0x3B #define ACCEL_XOUT_L 0x3C #define ACCEL_YOUT_H 0x3D #define ACCEL_YOUT_L 0x3E #define ACCEL_ZOUT_H 0x3F #define ACCEL_ZOUT_L 0x40 #define TEMP_OUT_H 0x41 #define TEMP_OUT_L 0x42 #define GYRO_XOUT_H 0x43 #define GYRO_XOUT_L 0x44 #define GYRO_YOUT_H 0x45 #define GYRO_YOUT_L 0x46 #define GYRO_ZOUT_H 0x47 #define GYRO_ZOUT_L 0x48 #define PWR_MGMT_1 0x6Bvoid swap_int16(short *val) {*val (*val 8) | (*val 8); }int main(int argc, char *argv[]) {int fd;int ret;short accelx, accely, accelz;short temp;short gyrox, gyroy, gyroz;unsigned char *p;fd open(/dev/i2c-5, O_RDWR);if (fd -1)goto fail;if (ioctl(fd, I2C_SLAVE, 0x68) 0)goto fail;i2c_smbus_write_byte_data(fd, PWR_MGMT_1, 0x80);usleep(200000);i2c_smbus_write_byte_data(fd, PWR_MGMT_1, 0x40);i2c_smbus_write_byte_data(fd, PWR_MGMT_1, 0x00);i2c_smbus_write_byte_data(fd, SMPLRT_DIV, 0x7);i2c_smbus_write_byte_data(fd, CONFIG, 0x6);i2c_smbus_write_byte_data(fd, GYRO_CONFIG, 0x3 3);i2c_smbus_write_byte_data(fd, ACCEL_CONFIG, 0x3 3);while (1) {accelx i2c_smbus_read_word_data(fd, ACCEL_XOUT_H);swap_int16(accelx);accely i2c_smbus_read_byte_data(fd, ACCEL_YOUT_H);swap_int16(accely);accelz i2c_smbus_read_byte_data(fd, ACCEL_ZOUT_H);swap_int16(accelz);printf(accelx: %.2f\n, accelx / 2048.0);printf(accely: %.2f\n, accely / 2048.0);printf(accelz: %.2f\n, accelz / 2048.0);temp i2c_smbus_read_word_data(fd, TEMP_OUT_H);swap_int16(temp);printf(temp: %.2f\n, temp / 340.0 36.53);gyrox i2c_smbus_read_word_data(fd, GYRO_XOUT_H);swap_int16(gyrox);gyroy i2c_smbus_read_byte_data(fd, GYRO_YOUT_H);swap_int16(gyroy);gyroz i2c_smbus_read_byte_data(fd, GYRO_ZOUT_H);swap_int16(gyroz);printf(gyrox: %.2f\n, gyrox / 16.4);printf(gyroy: %.2f\n, gyroy / 16.4);printf(gyroz: %.2f\n, gyroz / 16.4);sleep(1);}fail:perror(i2c test);exit(EXIT_FAILURE); }代码第 9 行包含了一个 i2c-dev.h 头文件,该文件中包含了 i2c_smbus_read_word_data等函数的定义。代码第 11 行至第 29 行是相关存器地址的宏定文。第45行开了/dev/i2c-5因为根据前面的分析MPU6050 是连接在 5号主机控制器上的。代码第 9行将 i2C 设备的地址设置为 0x68也就是 MPU6050 的设备地址。代码第 52行复位整个芯片然后休眠了 200ms等待芯片复位完成再将 SLEEP 位先置1后置0确保其不处于 SLEEP 模式。代码第 57 行设置采样时钟分频值为7第 8 行设置 DLPF_CFG 的值为6那么采样率为 1KHz /(1 7) 125Hz。代码第 59 行和第 60行分别设置陀螺仪的的输出范围为土2000 和三轴加速度的输出范围为16。代码第 60行至第 90行则读出采祥值.然后根据前面的换算关系进行换算并打印输出。 编译和测试的命令如下。 内核层 I2C 设备驱动代码如下 #include linux/init.h #include linux/kernel.h #include linux/module.h#include linux/fs.h #include linux/cdev.h#include linux/slab.h #include linux/ioctl.h #include linux/uaccess.h#include linux/io.h #include linux/ioport.h #include linux/i2c.h #include linux/delay.h#include mpu6050.h#define FSRTC_MAJOR 256 #define FSRTC_MINOR 9 #define FSRTC_DEV_NAME mpu6050#define SMPLRT_DIV 0x19 #define CONFIG 0x1A #define GYRO_CONFIG 0x1B #define ACCEL_CONFIG 0x1C #define ACCEL_XOUT_H 0x3B #define ACCEL_XOUT_L 0x3C #define ACCEL_YOUT_H 0x3D #define ACCEL_YOUT_L 0x3E #define ACCEL_ZOUT_H 0x3F #define ACCEL_ZOUT_L 0x40 #define TEMP_OUT_H 0x41 #define TEMP_OUT_L 0x42 #define GYRO_XOUT_H 0x43 #define GYRO_XOUT_L 0x44 #define GYRO_YOUT_H 0x45 #define GYRO_YOUT_L 0x46 #define GYRO_ZOUT_H 0x47 #define GYRO_ZOUT_L 0x48 #define PWR_MGMT_1 0x6Bstruct mpu6050_dev {struct i2c_client *client;atomic_t available;struct cdev cdev; };static int mpu6050_open(struct inode *inode, struct file *filp) {struct mpu6050_dev *mpu6050 container_of(inode-i_cdev, struct mpu6050_dev, cdev);filp-private_data mpu6050;if (atomic_dec_and_test(mpu6050-available))return 0;else {atomic_inc(mpu6050-available);return -EBUSY;} }static int mpu6050_release(struct inode *inode, struct file *filp) {struct mpu6050_dev *mpu6050 filp-private_data;atomic_inc(mpu6050-available);return 0; }static long mpu6050_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {struct mpu6050_dev *mpu6050 filp-private_data;struct atg_val val;if (_IOC_TYPE(cmd) ! MPU6050_MAGIC)return -ENOTTY;switch (cmd) {case MPU6050_GET_VAL:val.accelx i2c_smbus_read_word_data(mpu6050-client, ACCEL_XOUT_H);val.accely i2c_smbus_read_word_data(mpu6050-client, ACCEL_YOUT_H);val.accelz i2c_smbus_read_word_data(mpu6050-client, ACCEL_ZOUT_H);val.temp i2c_smbus_read_word_data(mpu6050-client, TEMP_OUT_H);val.gyrox i2c_smbus_read_word_data(mpu6050-client, GYRO_XOUT_H);val.gyroy i2c_smbus_read_word_data(mpu6050-client, GYRO_YOUT_H);val.gyroz i2c_smbus_read_word_data(mpu6050-client, GYRO_ZOUT_H);val.accelx be16_to_cpu(val.accelx);val.accely be16_to_cpu(val.accely);val.accelz be16_to_cpu(val.accelz);val.temp be16_to_cpu(val.temp);val.gyrox be16_to_cpu(val.gyrox);val.gyroy be16_to_cpu(val.gyroy);val.gyroz be16_to_cpu(val.gyroz);if (copy_to_user((struct atg_val __user *)arg, val, sizeof(struct atg_val)))return -EFAULT;break;default:return -ENOTTY;}return 0; }static struct file_operations mpu6050_ops {.owner THIS_MODULE,.open mpu6050_open,.release mpu6050_release,.unlocked_ioctl mpu6050_ioctl, };static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id) {int ret;dev_t dev;struct mpu6050_dev *mpu6050;dev MKDEV(FSRTC_MAJOR, FSRTC_MINOR);ret register_chrdev_region(dev, 1, FSRTC_DEV_NAME);if (ret)goto reg_err;mpu6050 kzalloc(sizeof(struct mpu6050_dev), GFP_KERNEL);if (!mpu6050) {ret -ENOMEM;goto mem_err;}i2c_set_clientdata(client, mpu6050);mpu6050-client client;cdev_init(mpu6050-cdev, mpu6050_ops);mpu6050-cdev.owner THIS_MODULE;ret cdev_add(mpu6050-cdev, dev, 1);if (ret)goto add_err;if (!i2c_check_functionality(client-adapter, I2C_FUNC_SMBUS_WORD_DATA)) {ret -ENOSYS;goto fun_err;}i2c_smbus_write_byte_data(client, PWR_MGMT_1, 0x80);msleep(200);i2c_smbus_write_byte_data(client, PWR_MGMT_1, 0x40);i2c_smbus_write_byte_data(client, PWR_MGMT_1, 0x00);i2c_smbus_write_byte_data(client, SMPLRT_DIV, 0x7);i2c_smbus_write_byte_data(client, CONFIG, 0x6);i2c_smbus_write_byte_data(client, GYRO_CONFIG, 0x3 3); i2c_smbus_write_byte_data(client, ACCEL_CONFIG, 0x3 3);atomic_set(mpu6050-available, 1);return 0;fun_err:cdev_del(mpu6050-cdev); add_err:kfree(mpu6050); mem_err:unregister_chrdev_region(dev, 1); reg_err:return ret; }static int mpu6050_remove(struct i2c_client *client) {dev_t dev;struct mpu6050_dev *mpu6050 i2c_get_clientdata(client);dev MKDEV(FSRTC_MAJOR, FSRTC_MINOR);cdev_del(mpu6050-cdev);kfree(mpu6050);unregister_chrdev_region(dev, 1);return 0; }static const struct i2c_device_id mpu6050_id[] {{mpu6050, 0},{} };MODULE_DEVICE_TABLE(i2c, mpu6050_id);static struct i2c_driver mpu6050_driver {.probe mpu6050_probe,.remove mpu6050_remove,.id_table mpu6050_id,.driver {.owner THIS_MODULE,.name mpu6050,}, };module_i2c_driver(mpu6050_driver);MODULE_LICENSE(GPL); MODULE_AUTHOR(name e-mail); MODULE_DESCRIPTION(MPU6050 driver);#ifndef _MPU6050_H #define _MPU6050_Hstruct atg_val {short accelx;short accely;short accelz;short temp;short gyrox;short gyroy;short gyroz; };#define MPU6050_MAGIC m#define MPU6050_GET_VAL _IOR(MPU6050_MAGIC, 0, struct atg_val)#endif代码第 43 行至第 47 行定义了 struct mpu6050_dev 结构类型成员 client 用于保存匹配的 client 对象。代码第 178 行至第 195 行是对 i2C 驱动的定义和注册相关的操作。代127 行将分配得到的 struct mpu050_dev 结构对象地址存入 client 中,方便之后从cliem中获取。代码第 136 行使用 i2c_check_functionality 验证 i2C 机控制器是否具有一个的随机读写能力。代码第 141 行至第 149 是对 MPU6050 的初始化,和前面应用层的 i2C没备驱动一样。mpu6050_ioctl 函数中读取寄存器的值将大端转换成小端后复制给用户测试用的应用层代码比较简单以下是编译和测试的命令。   #include sys/types.h #include sys/stat.h #include fcntl.h #include sys/ioctl.h #include stdio.h#include mpu6050.hint main(int argc, char *argv[]) {int fd;struct atg_val val;fd open(/dev/mpu6050, O_RDWR);while (2) {ioctl(fd, MPU6050_GET_VAL, val);printf(accelx: %.2f\n, val.accelx / 2048.0);printf(accely: %.2f\n, val.accely / 2048.0);printf(accelz: %.2f\n, val.accelz / 2048.0);printf(temp: %.2f\n, val.temp / 340.0 36.53); printf(gyrox: %.2f\n, val.gyrox / 16.4);printf(gyroy: %.2f\n, val.gyroy / 16.4);printf(gyroz: %.2f\n, val.gyroz / 16.4);sleep(1);} }_____________________________________________________________________________ 十分抱歉这篇文章晚了一个月前段时间受感情影响导致工作和生活以及学习都不顺利直接摆烂了两个星期想想十分对不起老师和喜欢我文章的读者们后面不会了那个小太阳又回来了。
http://www.w-s-a.com/news/324932/

相关文章:

  • 手机微网站与微官网现在去成都需要隔离吗
  • 学校的二级网站怎么建设深圳企业网站制作设计
  • 自己做qq头像静态的网站网站建设是属于软件开发费吗
  • 举报网站建设做网站之前的工作
  • 用QQ群做网站排名个人网站制作协议
  • 做茶叶网站的素材天津网站营销
  • 网站设计建设流程图微信端的网站开发python
  • 湖州网站seo优化网站改域名备案
  • dedecms怎么制作网站合肥电商网站开发
  • 网站开发通用流程图做flash的网站
  • 营销型网站有哪些平台网站建设藤设计
  • 网站需求分析网站建设美食网站建设多少钱
  • 有专门做网站的吗建德网站
  • 做网站要买服务器吗单页设计思路
  • 一 电子商务网站建设规划网站开发前端框架和后端框架
  • 自助网站建设系统软件自己免费建设网站
  • 百度微建站access如何与网站连接数据库
  • ppt素材免费网站网站正能量晚上免费软件
  • 个人淘宝客网站如何备案搭建一个平台要多少钱
  • nginx 网站建设淘客网站怎么做首页
  • 网站制作的基本步骤是手机网站建设 新闻
  • 水墨 网站源码工装
  • 任丘网站建设服务网站 建设原则
  • 长沙做一个网站要多少钱网站底部备案代码
  • wordpress构建自定义设置页面seo培训学什么
  • 延安有哪些做网站的公司如何建设网站?
  • 网站建设者属于广告经营者吗网站管理程序
  • 网站内容优化方法深圳市宝安区怎么样
  • 视频网站开发视频公司网站制作多少钱
  • 单页简洁手机网站模板购物软件