Android平台读写i2c设备开发笔记一
来源:互联网 发布:淘宝网购如何防骗技巧 编辑:程序博客网 时间:2024/06/09 20:12
在android开发和移植过程中,有时需要对某设备进行读写,但系统可能并未提供相应的服务。我们就需要自己开发硬件访问服务来控制设备。下面的例子是读写最简单的i2c设备eeprom的流程, i2c的驱动编写有两种方式,一种是利用系统提供的i2c-dev.c来实现一个i2c适配器的设备文件,然后通过在应用层操作I2C适配器来控制I2C设备;另一种是为I2C从设备独立编写一个设备驱动,不需要i2c-dev.c文件。由于前者比较简单通用性强,我们采用前者来展开。
根据android层次划分,我们照例对开发分为如下几步:
1. 添加HAL层接口模块访问设备
2. 使用JNI在应用程序框架层添加服务访问接口
3. 使用服务接口api开发应用程序
一. 添加HAL层接口模块访问设备
首先确认物理设备正常。根据开发板说明书获知设备挂载在/dev/i2c-1上,检测到该设备的存在,则通用设备驱动正常。
eeprom设备为at24c**系列,根据说明书获知设备从地址为0x50,准备工作完毕。
1. 编写hal层接口模块头文件iic.h
进入源码根目录下hardware/libhardware/include/hardware目录新建iic.h,代码如下:
#ifndef ANDROID_IIC_INTERFACE_H #define ANDROID_IIC_INTERFACE_H #include <hardware/hardware.h> __BEGIN_DECLS /*定义模块ID*/ #define IIC_HARDWARE_MODULE_ID "iic" /*硬件模块结构体*/ struct iic_module_t { struct hw_module_t common; }; /*硬件接口结构体*/ struct iic_device_t { struct hw_device_t common; int fd; int (*iic_write)(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, unsigned short subAddr, int len); int (*iic_read)(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, int len); }; __END_DECLS #endif
这里定义了iic_write和iic_read两个接口,头文件按照hal规范编写。
2. 编写hal层接口模块文件
进入源码根目录下hardware/libhardware/modules目录新建iic目录,并在iic目录中添加iic.c,代码如下:
#include <hardware/hardware.h> #include <hardware/iic.h> #include <fcntl.h> #include <errno.h> #include <cutils/log.h> #include <cutils/atomic.h> #include <stdio.h>#include<linux/i2c.h>#include<linux/i2c-dev.h>#include <stdlib.h>#include <linux/types.h>#include <unistd.h>#include <sys/types.h>#include <sys/ioctl.h>#include <string.h>
#define DEVICE_NAME "/dev/i2c-1" #define MODULE_NAME "iic" #define MODULE_AUTHOR "mfayz@sohu.com" #define I2C_RETRIES 0x0701/* number of times a device address should be polled when not acknowledging */#define I2C_TIMEOUT 0x0702/* set timeout in units of 10 ms */#define I2C_RDWR 0x0707/*********定义struct i2c_rdwr_ioctl_data和struct i2c_msg,要和内核一致*******/struct i2c_msg { unsigned short addr; unsigned short flags; #define I2C_M_TEN 0x0010 #define I2C_M_RD 0x0001 unsigned short len; unsigned char *buf; };struct i2c_rdwr_ioctl_data {struct i2c_msg *msgs;/* pointers to i2c_msgs */int nmsgs; /* number of i2c_msgs */}; /*设备打开和关闭接口*/ static int iic_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device); static int iic_device_close(struct hw_device_t* device); /*设备访问接口*/ static int iic_write(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, unsigned short subAddr, int len); static int iic_read(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, int len); /*模块方法表*/ static struct hw_module_methods_t iic_module_methods = { open: iic_device_open }; struct i2c_rdwr_ioctl_data iic_data;int ret; /*模块实例变量*/ struct iic_module_t HAL_MODULE_INFO_SYM = { common: { tag: HARDWARE_MODULE_TAG, version_major: 1, version_minor: 0, id: IIC_HARDWARE_MODULE_ID, name: MODULE_NAME, author: MODULE_AUTHOR, methods: &iic_module_methods, //实现了一个open的方法供jni层调用,从而实例化eeprom_device_t } }; static int iic_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device){ struct iic_device_t* dev; dev = (struct iic_device_t*)malloc(sizeof(struct iic_device_t)); if(!dev) { LOGE("iic Stub: failed to alloc space"); return -EFAULT; }else{LOGE("hal: alloc space succ!"); } memset(dev, 0, sizeof(struct iic_device_t)); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = (hw_module_t*)module; dev->common.close = iic_device_close; dev->iic_write = iic_write; dev->iic_read = iic_read; *device = &dev->common; //将实例化后的iic_device_t地址返回给jni层,这样jni层就可以直接调用方法了。 if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) { LOGE("iic Stub hal: failed to open /dev/i2c-1 -- %s.", strerror(errno));free(dev); return -EFAULT; }else{ LOGI("iic Stub hal: open /dev/i2c-1 successfully."); iic_data.nmsgs=2; iic_data.msgs=(struct i2c_msg*)malloc(iic_data.nmsgs*sizeof(struct i2c_msg)); if(!iic_data.msgs){ LOGE("malloc error");close(dev->fd); exit(1); }ioctl(dev->fd, I2C_TIMEOUT, 2);//设置超时时间 ioctl(dev->fd, I2C_RETRIES, 1);//设置重发次数 } return 0; } static int iic_device_close(struct hw_device_t* device) { struct iic_device_t* iic_device = (struct iic_device_t*)device; if(iic_device) { close(iic_device->fd); free(iic_device); } return 0; } static int iic_write(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, unsigned short subAddr, int len) {int count = 0;unsigned char data[2];unsigned char bytes; LOGI("iic Stub hal: set value %s to device.", dataBuf); iic_data.nmsgs=1; (iic_data.msgs[0]).len=2; //写入地址位和数据长度 (iic_data.msgs[0]).addr=slaveAddr;// 设备地址0x50 (iic_data.msgs[0]).flags=0; //write (iic_data.msgs[0]).buf=(unsigned char*)malloc(2);while(count<len){ bytes = 0; data[bytes++] = subAddr;//先写子地址 data[bytes] = dataBuf[count];//再写value LOGI("IIC write HAL: %x,%x", data[0],data[1]); (iic_data.msgs[0]).buf=data;//the data to write ret=ioctl(dev->fd,I2C_RDWR,(unsigned long)&iic_data); if(ret<0){ LOGI("IIC HAL ioctl error"); } count++; subAddr++; usleep(3000);//延迟3毫秒 } LOGI("you have write %s into iic at %x address len: %d",dataBuf, subAddr, len); return 0; } static int iic_read(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, int len){ int count = 0; iic_data.nmsgs=1; (iic_data.msgs[0]).len=1; (iic_data.msgs[0]).addr=slaveAddr; // 设备地址 (iic_data.msgs[0]).flags=I2C_M_RD;//read (iic_data.msgs[0]).buf=(unsigned char*)malloc(1); while(count<len){ (iic_data.msgs[0]).buf= dataBuf++;if(ioctl(dev->fd,I2C_RDWR,(unsigned long)&iic_data)<0){ LOGE("ioctl read error"); }LOGI("IIC read HAL: %x", dataBuf[count]);count++; } return 0; }
注意:需打开设备/dev/i2c-1权限,否则会碰到Pemission Denied错误。从源码根目录下进入system/core/rootdir目录,打开ueventd.rc 添加一行:/dev/i2c-1 0666 root root (这里设备各开发板可能不同)
3. 在iic目录下编写android.mk进行编译
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_PRELINK_MODULE := false LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_SRC_FILES := iic.c LOCAL_MODULE := iic.default include $(BUILD_SHARED_LIBRARY)
编译命令:mmm -B hardware/libhardware/module/iic 编译成功会得到iic.default.so,打包进img默认会被加载。
(待续)
- Android平台读写i2c设备开发笔记一
- Android平台读写i2c设备开发笔记
- Android平台读写i2c设备开发笔记
- Android平台读写i2c设备开发笔记二
- Android平台读写i2c设备开发笔记三
- android NDK平台搭建 && Android平台读写i2c设备
- MTK android平台添加读写i2c设备工具
- MTK android平台添加读写i2c设备工具
- amlogic平台android uboot中添加i2c设备实现i2c的读写
- amlogic平台android 系统linux内核中添加i2c设备实现i2c的读写
- Android平台应用开发笔记(一)
- Linux I2C设备读写应用程序
- Linux I2C设备读写应用程序
- Linux I2C设备读写应用程序
- I2C设备,读写地址换算
- i2c 设备读写 与驱动
- I2C设备应用层读写
- Linux I2C设备读写应用程序
- 锁的概述 (ctrl+2 sql)
- WordPress表结构说明
- WideCharToMultiByte和MultiByteToWideChar函数的用法
- C#中使用多线程访问Winform中控件的若干问题
- CSS float时,子元素与父元素大小问题
- Android平台读写i2c设备开发笔记一
- zoj1763-----------A Simple Question of Chemistry
- perl实现多线程
- 连锁零售行业IT运维管理四大困境
- java同步discuz账号
- -swf-version编译器参数设置与playerglobal.swc的关系
- Introduction to Windows Metro Style
- c 语言宏的用法
- KVM 虚拟机在物理主机之间迁移的实现