瑞芯微Rockchip开发者社区
直播中

李涛

7年用户 1353经验值
私信 关注
[问答]

如何在android7.1.2源码目录下添加HAL层i2c模块?

如何在android7.1.2源码目录下添加HAL层i2c模块?

回帖(1)

刘润生

2022-3-2 17:05:26
确认物理设备是否已经正常连接,android6.0.1 i2c_detect 可以用,但是android7.1.2  i2c_detect 本人测试无法使用,但是可以看到i2c设备名称如下:



本人案例是按照设备名为:i2c-1 进行硬件连接的。

还需要注意在打开i2c-1设备时,可能会遇到Pemission Denied错误,如若遇到,请从源码根目录下进入system/ core/rootdir目录,打开ueventd.rc 添加一行:/dev/i2c-1 0666 root root   ,每个开发板可能书写格式有所不同,请参考改文件内别的设备书写格式!

以下是在android7.1.2 源码目录下添加HAL层i2c 模块的详细步骤:

1.编写HAL层i2c模块的头文件iic.h

在源码根目录下:hardware/libhardware/include/hardware 新建iic.h文件

#ifndef _HARDWARE_IIC_H
#define _HARDWARE_IIC_H


#include
#include
#include
#include

#include

__BEGIN_DECLS

#define IIC_HARDWARE_MODULE_ID "iic"
#define DEVICE_NAME "/dev/i2c-1"

#define I2C_RETRIES 0x0701
#define I2C_TIMEOUT 0x0702
#define I2C_RDWR        0x0707  
#define I2C_M_TEN         0x0010  
#define I2C_M_RD         0x0001


struct iic_module_t {

    struct hw_module_t common;

};

typedef struct iic_device {

    struct hw_device_t common;
        int fd;
        int (*iic_write)(struct iic_device *dev, unsigned int slaveAddr, unsigned int regAddr, unsigned char dataBuf);
    int (*iic_read)(struct iic_device *dev, unsigned int slaveAddr, unsigned int regAddr, unsigned char *dataBuf);

} iic_device_t;


static inline int iic_open(const struct hw_module_t* module,
        iic_device_t** dev) {
    return module->methods->open(module, IIC_HARDWARE_MODULE_ID,
        (struct hw_device_t**) dev);
}

static inline int iic_close(iic_device_t* dev) {
    return dev->common.close(&dev->common);
}

__END_DECLS

#endif



2.编写HAL层i2c模块的iic.c

在源码目录下:hardware/libhardware/modules 新建iic目录,在该目录下新建iic.c 和 Android.mk 文件

#include
#include

#include    
#include   
#include   
#include   
#include    
#include   
#include

#include
#include
#include
#include
#include
#include
#include
#include

struct i2c_rdwr_ioctl_data iic_data;
int ret;

static int t613_iic_write(iic_device_t *dev __unused, unsigned int slaveAddr, unsigned int regAddr, unsigned char dataBuf) {

        iic_data.nmsgs=1;
        (iic_data.msgs[0]).len = 3;
        (iic_data.msgs[0]).addr = slaveAddr>>1;
        (iic_data.msgs[0]).flags = 0; //write
        (iic_data.msgs[0]).buf = (unsigned char*)malloc(3);
        (iic_data.msgs[0]).buf[0] = (unsigned char)(regAddr>>8);
        (iic_data.msgs[0]).buf[1] = (unsigned char)(regAddr);
        (iic_data.msgs[0]).buf[2] = dataBuf;

        ALOGE("IIC write HAL: From register %06x write ",regAddr);
        ALOGE("%04x ",(iic_data.msgs[0]).buf[2]);

        ret=ioctl(dev->fd,I2C_RDWR,(unsigned long)&iic_data);
        if(ret<0) ALOGE("IIC HAL write ioctl error.");
      
        usleep(3000);
        return 0;
}


static int t613_iic_read(iic_device_t *dev __unused,  unsigned int slaveAddr, unsigned int regAddr, unsigned char *dataBuf) {   

        iic_data.nmsgs = 2;
        (iic_data.msgs[0]).addr  = slaveAddr >>1;
        (iic_data.msgs[0]).flags = 0 ;
        (iic_data.msgs[0]).len = 2;
        (iic_data.msgs[0]).buf = (unsigned char*)malloc(2);
        (iic_data.msgs[0]).buf[0] = (unsigned char)(regAddr>>8);
        (iic_data.msgs[0]).buf[1] = (unsigned char)(regAddr);

        (iic_data.msgs[1]).addr  = slaveAddr >>1;
        (iic_data.msgs[1]).flags = I2C_M_RD;
        (iic_data.msgs[1]).len = 1;
        (iic_data.msgs[1]).buf=(unsigned char*)malloc(1);
        (iic_data.msgs[1]).buf = dataBuf;

        ALOGE("IIC read HAL: From register %06x read ",regAddr);
        ALOGE("%04x ",(iic_data.msgs[1]).buf[0]);

        ret=ioctl(dev->fd,I2C_RDWR,(unsigned long)&iic_data);
        if(ret<0) ALOGE("IIC HAL read ioctl error.");

        usleep(3000);
        return 0;
}


static int iic_device_close(hw_device_t *dev) {
    free(dev);
    return 0;
}

static int iic_device_open(const hw_module_t* module, const char* name,
        hw_device_t** device) {
    if (strcmp(name, IIC_HARDWARE_MODULE_ID) == 0) {
        iic_device_t *dev = calloc(1, sizeof(iic_device_t));

        dev->common.tag = HARDWARE_DEVICE_TAG;
        dev->common.version = 0x00010000; // [31:16] major, [15:0] minor
        dev->common.module = (struct hw_module_t*) module;
        dev->common.close = iic_device_close;

                dev->iic_write = t613_iic_write;
                dev->iic_read = t613_iic_read;
               
        *device = &dev->common;

                if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {
                        ALOGE("iic Stub hal: failed to open /dev/i2c-1 --");  
                        free(dev);         
                        return -EFAULT;   
                }else{               
                        ALOGI("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){
                        ALOGE("malloc error.");
                                close(dev->fd);  
                        exit(1);  
                    }
                        ioctl(dev->fd, I2C_TIMEOUT, 2);  
                    ioctl(dev->fd, I2C_RETRIES, 1);
                }
        return 0;
    } else {
        return -EINVAL;
    }
}


/*===========================================================================*/
/* Default iic HW module interface definition                           */
/*===========================================================================*/

static struct hw_module_methods_t iic_module_methods = {
  .open = iic_device_open,
};

struct iic_module_t HAL_MODULE_INFO_SYM = {
  .common = {
          .tag = HARDWARE_MODULE_TAG,
          .module_api_version = 0x0100, // [15:8] major, [7:0] minor (1.0)
          .hal_api_version = 0x00, // 0 is only valid value
          .id = IIC_HARDWARE_MODULE_ID,
          .name = "Default IIC HW HAL",
          .author = "https://chhjnavy.github.io/",
          .methods = &iic_module_methods,
  },
};


LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := iic.default
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SRC_FILES := iic.c
LOCAL_SHARED_LIBRARIES := liblog libcutils
LOCAL_MODULE_TAGS := optional

include $(BUILD_SHARED_LIBRARY)

在源码根目录下:hardware/libhardware/modules 修改Android.mk 添加iic 文件夹名

hardware_modules := gralloc hwcomposer audio nfc nfc-nci local_time
        power u***audio audio_remote_submix camera u***camera consumerir sensors vibrator
        tv_input fingerprint input vehicle thermal vr iic
include $(call all-named-subdir-makefiles,$(hardware_modules))

在源码根目录下执行:mmm hardware/libhardware/modules/iic/   会对iic 模块进行编译

在源码根目录下产生 out/target/product/rk3288/obj/lib/iic.default.so.toc



3.编写在JNI (Java Native Interface)提供java层与C/C++交互的接口

在源码根目录下:frameworks/base/services/core/jni

    1) 新建com_android_server_IICService.cpp,然后需要让Android启动时加载此jni模块
    2) 在同目录下修改onload.cpp: 在namespace android中添加一行: int register_android_server_IICService(JNIEnv *env);
    3) 在JNI_onLoad方法中添加一行:  register_android_server_IICService(env);
    4) 在同目录下修改Android.mk: LOCAL_SRC_FILES增加一行: $(LOCAL_REL_DIR)/com_android_server_IICService.cpp

#include "jni.h"   
#include "JNIHelp.h"   
#include "android_runtime/AndroidRuntime.h"   
#include    
#include    
#include    
#include    
#include   
  
namespace android   
{   

        struct iic_device *iic_dev = NULL;

    static void iic_setVal(JNIEnv* env, jobject clazz, jint slaveAddr, jint regAddr, jint databuf) {

                if(!iic_dev) {
                        ALOGE("iic JNI: device is not open.");   
                }
                iic_dev->iic_write(iic_dev,slaveAddr,regAddr,databuf);
    }

    static jint iic_getVal(JNIEnv* env, jobject clazz,jint slaveAddr, jint regAddr) {

                unsigned char data[1] = {0};
            iic_dev->iic_read(iic_dev,slaveAddr,regAddr,data);

                if(!iic_dev) {
            ALOGE("iic JNI: device is not open.");
                }
                return data[0];
    }

      
    /*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/   
    static ***oolean iic_init(JNIEnv* env, jclass clazz) {
   
                iic_module_t *module;
                int err;
                err = hw_get_module(IIC_HARDWARE_MODULE_ID,(const struct hw_module_t**)&module);
                if (err != 0) {
                        ALOGE("Error acquiring iic hardware module: %d", err);
                        return 0;
                }

                err = iic_open(&(module->common), &iic_dev);
                if (err != 0) {
                        ALOGE("Error opening iic hardware module: %d", err);
                        return 0;
                }  
        ALOGE("iic device is opening...");   
        return 1;         
    }
        /*JNI方法表*/   
    static const JNINativeMethod method_table[] = {   
        {"init_native", "()Z", (void*)iic_init},
        {"setVal_native", "(III)V", (void*)iic_setVal},
        {"getVal_native", "(II)I", (void*)iic_getVal},
    };
    /*注册JNI方法*/   
    int register_android_server_IICService(JNIEnv *env) {   
            return jniRegisterNativeMethods(env, "com/android/server/IICService", method_table, NELEM(method_table));   
    }
};


在源码根目录下执行:mmm frameworks/base/services/core/jni   对该模块进行编译



4.编写跨进程访问服务AIDL(Android Interface Definition Language)

在源码根目录下:frameworks/base/core/java/android/os

    1)新建IIICService.aidl 文件

    2)修改frameworks/base下的Android.mk编译文件,在LOCAL_SRC_FILES中增加 core/java/android/os/IIICService.aidl

package android.os;  
interface IIICService {
    void setVal(int slaveAddr, int regAddr, int databuf);
    int getVal(int slaveAddr, int regAddr);
}

在源码根目录下执行:mmm frameworks/base   对该模块进行编译



5.编写AIDL(Android Interface Definition Language)具体实现的方法类

在源码根目录下:frameworks/base/services/core/java/com/android/server

    1)新建IICService.java文件

package com.android.server;   
import android.content.Context;   
import android.os.IIICService;   
import android.util.Slog;   
public class IICService extends IIICService.Stub {   
    private static final String TAG = "IICService";
    IICService() {   
        init_native();   
    }
    public void setVal(int slaveAddr, int regAddr, int databuf) {   
        setVal_native(slaveAddr, regAddr, databuf);   
    }      
    public int getVal(int slaveAddr, int regAddr) {   
        return getVal_native(slaveAddr, regAddr);
    }

    private static native boolean init_native();
    private static native void setVal_native(int slaveAddr, int regAddr, int databuf);
    private static native int getVal_native(int slaveAddr, int regAddr);
};

    2)修改frameworks/base/services/java/com/android/server下的SystemServer.java 在private void startOtherServices() 添加

try{

    Slog.i(TAG, "IIC SERVICE");
    ServiceManager.addService("iic", new IICService());
}catch(Throwable e){
    Slog.e(TAG, "Failure starting IIC Service", e);
}


在源码根目录下执行:mmm frameworks/base/services   对该模块进行编译



6.编写app 用来测试iic 是否通讯正常

在源码根目录下:packages/apps/T613

主程序如下:

完整code 请到:https://download.csdn.net/download/chhjnavy/11389018 下载

package com.example.t613;

import android.support.v7.app.ActionBarActivity;
import android.os.ServiceManager;
import android.os.IIICService;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;


public class MainActivity extends ActionBarActivity implements OnClickListener{
      
        private final static String LOG_TAG = "com.example.t613";
        private EditText valueText = null;
        private Button button_read = null;
        private Button button_write = null;
        private Button button_clear = null;
      
        private IIICService iicService = null;
      
        int len = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        iicService = IIICService.Stub.asInterface(ServiceManager.getService("iic"));
        
        valueText = (EditText)findViewById(R.id.edit_value);
        
        button_read = (Button)findViewById(R.id.button_read);
        button_read.setOnClickListener(this);
        button_write = (Button)findViewById(R.id.button_write);
        button_write.setOnClickListener(this);
        button_clear = (Button)findViewById(R.id.button_clear);
        button_clear.setOnClickListener(this);
        
        
        Log.i(LOG_TAG, "Activity Created");
               
                String text = "94";
                valueText.setText(text);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

        @Override
        public void onClick(View v) {
                if(v.equals(button_read)) {
                        try {
                                int val2 = iicService.getVal(0x60,0x2480);
                                valueText.setText(String.valueOf(val2));
                        } catch (RemoteException e) {
                                Log.e(LOG_TAG, "Remote Exception while reading value from device.");
                        }
                }else if(v.equals(button_write)) {
                        try {
                                String val = valueText.getText().toString();

                                iicService.setVal(0x60,0x2471,0x41);
                                iicService.setVal(0x60,0x2480,Integer.valueOf(val));
                        } catch (RemoteException e) {
                                Log.e(LOG_TAG, "Remote Exception while writing value to device.");
                        }
                }else if(v.equals(button_clear)) {
                        String text = "";
                        valueText.setText(text);
                }
               
        }
}

为app编写Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

appcompat_dir := ../../../$(SUPPORT_LIBRARY_ROOT)/v7/appcompat/res
gridlayout_dir := ../../../$(SUPPORT_LIBRARY_ROOT)/v7/gridlayout/res
bitmap_dir := ../../../frameworks/opt/bitmap/res
res_dir := res $(appcompat_dir) $(gridlayout_dir) $(bitmap_dir)

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dir))
#LOCAL_RESOURCE_DIR := $(LOCAL_PATH)
LOCAL_PACKAGE_NAME := T613
LOCAL_CERTIFICATE := platform
#LOCAL_PRIVATE_PLATFORM_APIS = true
#LOCAL_SDK_VERSION := current

LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-appcompat
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-gridlayout
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v13

#LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/appcompat/res
#LOCAL_RESOURCE_DIR += prebuilts/sdk/current/support/v7/gridlayout/res

LOCAL_AAPT_FLAGS := --auto-add-overlay
LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.appcompat:android.support.v7.gridlayout

include $(BUILD_PACKAGE)
include $(call all-makefiles-under,$(LOCAL_PATH))
在源码根目录下执行:mmm packages/apps/T613   对该模块进行编译

7.在源码根目录下执行:make snod  将添加的模块都加载到img中

8.在源码根目录下执行:./mkimage.sh  更新目录rockdev/Image-rk3288 的文件

9.在源码根目录下执行:cd RKTools/linux/Linux_Pack_Firmware/rockdev  进入该目录执行:

./collectImages.sh && ./mkupdate.sh   产生新的update.img

10.在windows 下打开 SpiImageTools.exe 加在update.img,会在当前文件夹下产生bin 档(该工具在源码目录下 RKToolswindows)

11.打开Win32diskImager.exe 将bin 档烧写到SD卡中,然后上电启动RK3288

举报

更多回帖

发帖
×
20
完善资料,
赚取积分