分享

Android平台读写i2c设备开发笔记一

 写意人生 2014-06-20

     在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,代码如下:

  1. #ifndef ANDROID_IIC_INTERFACE_H    
  2.     #define ANDROID_IIC_INTERFACE_H    
  3.     #include <hardware/hardware.h>    
  4.         
  5.     __BEGIN_DECLS    
  6.         
  7.     /*定义模块ID*/    
  8.     #define IIC_HARDWARE_MODULE_ID "iic"    
  9.         
  10.     /*硬件模块结构体*/    
  11.     struct iic_module_t {    
  12.         struct hw_module_t common;    
  13.     };    
  14.         
  15.     /*硬件接口结构体*/    
  16.     struct iic_device_t {    
  17.         struct hw_device_t common;    
  18.         int fd;    
  19.         int (*iic_write)(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, unsigned short subAddr, int len);    
  20.         int (*iic_read)(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, int len);    
  21.     };    
  22.         
  23.     __END_DECLS    
  24.         
  25.     #endif  

 

这里定义了iic_write和iic_read两个接口,头文件按照hal规范编写。

2. 编写hal层接口模块文件

     进入源码根目录下hardware/libhardware/modules目录新建iic目录,并在iic目录中添加iic.c,代码如下:

  1. #include <hardware/hardware.h>    
  2. #include <hardware/iic.h>    
  3. #include <fcntl.h>    
  4. #include <errno.h>    
  5. #include <cutils/log.h>    
  6. #include <cutils/atomic.h>   
  7. #include <stdio.h>  
  8. #include<linux/i2c.h>  
  9. #include<linux/i2c-dev.h>  
  10. #include <stdlib.h>  
  11. #include <linux/types.h>  
  12. #include <unistd.h>  
  13. #include <sys/types.h>  
  14. #include <sys/ioctl.h>  
  15. #include <string.h>  
  1. <span style="font-size:14px;">#define DEVICE_NAME "/dev/i2c-1"    
  2. #define MODULE_NAME "iic"    
  3. #define MODULE_AUTHOR "mfayz@sohu.com"    
  4.   
  5.   
  6. #define I2C_RETRIES 0x0701/* number of times a device address should be polled when not acknowledging */  
  7. #define I2C_TIMEOUT 0x0702/* set timeout in units of 10 ms */  
  8. #define I2C_RDWR         0x0707  
  9.   
  10.   
  11. /*********定义struct i2c_rdwr_ioctl_data和struct i2c_msg,要和内核一致*******/  
  12. struct i2c_msg  
  13.        {  
  14.          unsigned short addr;  
  15.          unsigned short flags;  
  16.          #define I2C_M_TEN 0x0010  
  17.          #define I2C_M_RD 0x0001  
  18.          unsigned short len;  
  19.          unsigned char *buf;  
  20.        };  
  21.   
  22.   
  23. struct i2c_rdwr_ioctl_data {  
  24. struct i2c_msg *msgs;/* pointers to i2c_msgs */  
  25. int nmsgs; /* number of i2c_msgs */  
  26. };   
  27.   
  28.   
  29.     /*设备打开和关闭接口*/    
  30. static int iic_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);    
  31. static int iic_device_close(struct hw_device_t* device);    
  32.         
  33.     /*设备访问接口*/    
  34. static int iic_write(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, unsigned short subAddr, int len);    
  35. static int iic_read(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, int len);   
  36.       
  37.     /*模块方法表*/    
  38. static struct hw_module_methods_t iic_module_methods = {    
  39.         open: iic_device_open    
  40. };    
  41.   
  42.   
  43. struct i2c_rdwr_ioctl_data iic_data;  
  44. int ret;  
  45.   
  46.   
  47.     /*模块实例变量*/    
  48. struct iic_module_t HAL_MODULE_INFO_SYM = {    
  49.         common: {    
  50.             tag: HARDWARE_MODULE_TAG,    
  51.             version_major: 1,    
  52.             version_minor: 0,    
  53.             id: IIC_HARDWARE_MODULE_ID,    
  54.             name: MODULE_NAME,    
  55.             author: MODULE_AUTHOR,    
  56.             methods: &iic_module_methods, //实现了一个open的方法供jni层调用,从而实例化eeprom_device_t   
  57.         }    
  58. };    
  59.   
  60.   
  61. static int iic_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device){    
  62.     struct iic_device_t* dev;  
  63.     dev = (struct iic_device_t*)malloc(sizeof(struct iic_device_t));    
  64.     if(!dev) {    
  65.         LOGE("iic Stub: failed to alloc space");    
  66.         return -EFAULT;    
  67.     }else{  
  68. LOGE("hal: alloc space succ!");  
  69.     }    
  70.     
  71.     memset(dev, 0, sizeof(struct iic_device_t));    
  72.     dev->common.tag = HARDWARE_DEVICE_TAG;    
  73.     dev->common.version = 0;    
  74.     dev->common.module = (hw_module_t*)module;    
  75.     dev->common.close = iic_device_close;    
  76.     dev->iic_write = iic_write;  
  77.     dev->iic_read = iic_read;  
  78.     *device = &dev->common;     //将实例化后的iic_device_t地址返回给jni层,这样jni层就可以直接调用方法了。  
  79.   
  80.   
  81.     if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {    
  82.         LOGE("iic Stub hal: failed to open /dev/i2c-1 -- %s.", strerror(errno));  
  83. free(dev);    
  84.         return -EFAULT;    
  85.     }else{      
  86.         LOGI("iic Stub hal: open /dev/i2c-1 successfully.");   
  87. iic_data.nmsgs=2;   
  88. iic_data.msgs=(struct i2c_msg*)malloc(iic_data.nmsgs*sizeof(struct i2c_msg));   
  89.   
  90.   
  91. if(!iic_data.msgs){  
  92.                 LOGE("malloc error");  
  93. close(dev->fd);  
  94.                 exit(1);  
  95.         }  
  96. ioctl(dev->fd, I2C_TIMEOUT, 2);//设置超时时间  
  97.         ioctl(dev->fd, I2C_RETRIES, 1);//设置重发次数  
  98.     }  
  99.     return 0;    
  100. }   
  101.   
  102.   
  103. static int iic_device_close(struct hw_device_t* device) {    
  104.         struct iic_device_t* iic_device = (struct iic_device_t*)device;    
  105.         
  106.         if(iic_device) {    
  107.             close(iic_device->fd);    
  108.             free(iic_device);    
  109.         }    
  110.             
  111.         return 0;    
  112. }    
  113.         
  114. static int iic_write(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, unsigned short subAddr, int len) {  
  115. int count = 0;  
  116. unsigned char data[2];  
  117. unsigned char bytes;  
  118.   
  119.   
  120.         LOGI("iic Stub hal: set value %s to device.", dataBuf);   
  121. iic_data.nmsgs=1;   
  122.         (iic_data.msgs[0]).len=2; //写入地址位和数据长度  
  123.         (iic_data.msgs[0]).addr=slaveAddr;// 设备地址0x50  
  124.         (iic_data.msgs[0]).flags=0; //write  
  125.         (iic_data.msgs[0]).buf=(unsigned char*)malloc(2);  
  126. while(count<len){  
  127.  bytes = 0;  
  128.  data[bytes++] =  subAddr;//先写子地址   
  129.  data[bytes]   = dataBuf[count];//再写value  
  130.           LOGI("IIC write HAL: %x,%x", data[0],data[1]);  
  131.           (iic_data.msgs[0]).buf=data;//the data to write   
  132.           ret=ioctl(dev->fd,I2C_RDWR,(unsigned long)&iic_data);  
  133.           if(ret<0){  
  134.              LOGI("IIC HAL ioctl error");  
  135.           }  
  136.           count++;  
  137.  subAddr++;  
  138.  usleep(3000);//延迟3毫秒  
  139.         }   
  140.       LOGI("you have write %s into iic at %x address len: %d",dataBuf, subAddr, len);  
  141.   
  142.         return 0;    
  143. }    
  144.         
  145. static int iic_read(struct iic_device_t* dev, unsigned char* dataBuf, unsigned short slaveAddr, int len){    
  146.       int count = 0;  
  147.         
  148.       iic_data.nmsgs=1;  
  149.         
  150.       (iic_data.msgs[0]).len=1;   
  151.       (iic_data.msgs[0]).addr=slaveAddr; //  设备地址  
  152.       (iic_data.msgs[0]).flags=I2C_M_RD;//read  
  153.       (iic_data.msgs[0]).buf=(unsigned char*)malloc(1);  
  154.       while(count<len){  
  155.          (iic_data.msgs[0]).buf= dataBuf++;  
  156. if(ioctl(dev->fd,I2C_RDWR,(unsigned long)&iic_data)<0){  
  157.                         LOGE("ioctl read error");  
  158.          }  
  159. LOGI("IIC read HAL: %x", dataBuf[count]);  
  160. count++;  
  161.       }   
  162.         
  163.         return 0;   
  164. }</span>  


注意:需打开设备/dev/i2c-1权限,否则会碰到Pemission Denied错误。从源码根目录下进入system/core/rootdir目录,打开ueventd.rc 添加一行:/dev/i2c-1 0666 root root (这里设备各开发板可能不同)

3. 在iic目录下编写android.mk进行编译

  1. LOCAL_PATH := $(call my-dir)  
  2.       include $(CLEAR_VARS)  
  3.       LOCAL_MODULE_TAGS := optional  
  4.       LOCAL_PRELINK_MODULE := false  
  5.       LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw  
  6.       LOCAL_SRC_FILES := iic.c  
  7.       LOCAL_MODULE := iic.default  
  8.       include $(BUILD_SHARED_LIBRARY)  


编译命令:mmm -B hardware/libhardware/module/iic 编译成功会得到iic.default.so,打包进img默认会被加载。


(待续)

原文:http://blog.csdn.net/rickbeyond/article/details/7838313

如有侵权,请告知,谢谢。


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多