准备工作如下:
确认物理设备是否已经正常连接,请根据https://blog.csdn.net/Chhjnavy/article/details/95215479 该篇文章查看设备名称,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 usbaudio audio_remote_submix camera usbcamera 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 jboolean 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 档(该工具在源码目录下 RKTools\windows)
11.打开Win32diskImager.exe 将bin 档烧写到SD卡中,然后上电启动RK3288
步骤7~11详细请参考:https://blog.csdn.net/Chhjnavy/article/details/95043440