Android系统sensor大致框架流程:

App中传感器注册,获取系统服务,数据上报给app(onSensorChange)都是通过SystemSensorManager.java完成的,

SensorManager.java仅仅是类似于接口类,功能是由SystemSensorManager.java实现

SystemSensorManager.java 中函数会调用 jni 的android_hardware_SensorManager.cpp实现

android_hardware_SensorManager.cpp调用SensorManager.cpp实现

SensorManager.cpp 与sensorService.cpp 间进行通信,其中命令传输通过binder实现,数据传输通过管道实现;其中binder做主
要贡献的是ISensorEventConnection.cpp,完成binder的服务端和客户端

sensorService.cpp通过中通过 threadloop 不断的从hardware 层获取sensor数据,其中对sensor 的操作主要有sensordevice 类完成

hardware (sensor hal)层则通过read / write ,ioctl操作 sensor驱动设备节点去操作sensor 设备,读取sensor上报的数据(一般是input子系统)

kenel中sensor驱动从IC中通过i2c或者其他接口读取到数据,然后将数据放入到input子系统中上报给上层。

Rk平台sensor调试说明

Rk平台sensor驱动代码路径:kernel/drivers/input/sensors,其中 sensor-dev.c 是核心代码,整合了不同类型的sensor,包括 accel, gyro, lsensor, psensor, compass等。

下面是实际工作中的调试流程:
这里只记录调试gsensor部分,其他gryo+compass同理,他们在rk平台分开三个不同.c文件实现驱动加载和id匹配和数据上报等:
1、硬件板子确认
拿到硬件板子之后,首先确认上电ok[供电电压对,如3.3v],万用表量到供电(3.3v)供电正常,i2c空闲上拉状态正常等。

2、确认资料和硬件连接IO
对照供应商那边提供的资料,规格书(datasheet)、驱动或者demo代码资料等。首先从资料中确定模块的I2C从设备地址,确定模块的id寄存器和寄存器值;
驱动代码方面,不一定拿到的就是直接可以用的驱动,除非在相同平台上调试过,不然的话,别想着驱动一拿过来就直接可以编译进去跑起来,要么是编译问题,总之各种问题,反正这也是你们驱动工程师搞的活,比如我这次拿到的资料是这样的:

这样的:

但是在rk平台调试的话,如果客户没有提供直接可以使用的驱动代码,我们可以根据它的sensor驱动框架,穿插进去你的实现代码就可以了,其实主要代码部分就是读取id,设置使能寄存器,还有读取数据寄存器,以及上报数据等操作而已,可以近似的拷贝一个现有的gsesnor的.c文件来修改即可。这里调试的lsm9ds1九轴sensor的gsensor功能, 首先第一步,配置你的dts资源描述,例如我这里,配置dts信息如下:

&i2c1 {status = "okay";lsm9ds1_accel@6b { /* SDO_AG: if 0 ==> 0x6a; if 1 ==> 0x6b */status = "okay";compatible = "lsm9ds1_acc";pinctrl-names = "default";pinctrl-0 = <&lsm9ds1a_irq_gpio>, <&lsm9ds1a_power_gpio>;reg = <0x6b>; //i2c地址irq-gpio = <&gpio1 13 IRQ_TYPE_EDGE_RISING>; //GPIO1_B5,中断脚power-gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>; //GPIO1_C6,供电脚type = <SENSOR_TYPE_ACCEL>;irq_enable = <0>; //poll modepoll_delay_ms = <30>;//power-off-in-suspend = <1>; //resume init sensorlayout = <4>;reprobe_en = <1>;};
};

硬件原理方面需要确认你的i2c连接总线是哪一组,还有就是从规格书或者资料确定lsm9ds1模组的i2c从设备地址,确认供电脚的gpio[如果长供电不用理会],如果使用中断模式需要确认你中断脚连接的GPIO口是哪个[我这里是GPIO1_B5]等。

3、添加sensor的id

在sensor-dev.c中添加sensor_id,其中“lsm9ds1_acc”字段与dts中的compatible字段对应。

ACCEL_ID_LSM9DS1定义在 include/linux/sensor-dev.h 中

4、增加gsensor驱动内容
driver/input/sensors/accel/目录下增加相应驱动:
1)实现 gsensor_lsm9ds1_ops实例:

struct sensor_operate gsensor_lsm9ds1_ops = {.name          = "lsm9ds1_acc",   //与 sensor-dev.c 中定义的名称一致.type            = SENSOR_TYPE_ACCEL,   //对应sensor类型是gsensor.id_i2c         = ACCEL_ID_LSM9DS1,   //定义在include/linux/sensor-dev.h 中.read_reg           = OUT_X_L_A,   //0x28,读取 gsensor 数据的起始寄存器地址.read_len            = 6,  //需要读取的 gsensor 数据的字节数.id_reg            = WHO_AM_I_A, //芯片唯一ID寄存器,从datasheet获知是0x0f.id_data         = LSM9DS1_DEVICE_ID_A,  //芯片的ID值   ,从datasheet获知是0x68
.precision          = 16,  //采样gsensor数据的adc位数.ctrl_reg            = CTRL_REG5_A,  //0x1F,用于使能 gsensor 的寄存器地址.int_status_reg   = STATUS_REG_A,  //中断状态寄存器地址.range         = {-32768, 32768},  //量程,这里表示上报的量程为+-2G.trig               = IRQF_TRIGGER_HIGH | IRQF_ONESHOT,  //中断类型.active         = sensor_active,  //用于开关 gsensor.init              = sensor_init,  //用于初始化 gsensor.report         = sensor_report_value,  //用于上报gsensor数据
};

确认i2c通信上之后第一步就是读取模块的id是否跟datasheet上的一致,这个是i2c通讯识别到你的模块的方法,例如这里的id寄存器是0x0f,id值是0x68。也就是当i2c通讯上,读取到的id寄存器的id值是0x68,那说明识别到设备了,可以去设置它的控制器,然后读取它的数据了

2)注册sensor驱动到sensor-dev.c

static struct sensor_operate *gsensor_get_ops(void)
{return &gsensor_lsm9ds1_ops;
}static int __init gsensor_lsm9ds1_init(void)
{struct sensor_operate *ops = gsensor_get_ops();int result = 0;int type = ops->type;printk("\n# -czd-: __%s__, _line[%d]_ #\n", __func__, __LINE__);result = sensor_register_slave(type, NULL, NULL, gsensor_get_ops);return result;
}static void __exit gsensor_lsm9ds1_exit(void)
{struct sensor_operate *ops = gsensor_get_ops();int type = ops->type;sensor_unregister_slave(type, NULL, NULL, gsensor_get_ops);
}

初始化sensor,主要是对sensor的控制寄存器部分做初始化设置,说白了就是写寄存器设置寄存器值:

static int sensor_init(struct i2c_client *client) //初始化sensor控制寄存器
{struct sensor_private_data *sensor =(struct sensor_private_data *)i2c_get_clientdata(client);int result = 0;result = sensor->ops->active(client, 0, 0);if (result) {dev_err(&client->dev, "%s:line=%d,error\n",__func__, __LINE__);return result;}sensor->status_cur = SENSOR_OFF;result = sensor_write_reg(client, CTRL_REG4_A, 0x38);if (result) {dev_err(&client->dev, "%s:fail to set CTRL_REG4_A.\n",__func__);return result;}/* Normal / Low power mode (1600 Hz) */result = sensor_write_reg(client, CTRL_REG5_A, 0x78);if (result) {dev_err(&client->dev, "%s:fail to set CTRL_REG5_A.\n",__func__);return result;}result = sensor_write_reg(client, CTRL_REG6_A, 0x40);if (result) {dev_err(&client->dev, "%s:fail to set CTRL_REG6_A.\n",__func__);return result;}result = sensor_write_reg(client, CTRL_REG7_A, 0x00);if (result) {dev_err(&client->dev, "%s:fail to set CTRL_REG7_A.\n",__func__);return result;}return result;
}

当我们上层apk打开gsensor读取数据时,会通过ioctl调用drivers/input/sensors/sensor-dev.c文件中的gsensor_dev_ioctl这个接口函数实现对gsensor的打开操作,然后通过判断宏case GSENSOR_IOCTL_START 调用sensor_enable(sensor, SENSOR_ON);打开gsensor功能,然后再调用result = sensor->ops->active进入到具体sensor的驱动里面去设置gsensor active;

106 static int sensor_active(struct i2c_client *client, int enable, int rate)
107 {108         struct sensor_private_data *sensor =
109             (struct sensor_private_data *)i2c_get_clientdata(client);
110         int result = 0;
111
112
114         sensor->ops->ctrl_data = sensor_read_reg(client, sensor->ops->ctrl_reg);
115         if (enable)
116                 result = sensor_write_reg(client,
117                         sensor->ops->ctrl_reg,
118                         sensor->ops->ctrl_data | 0x78); //0x07
119         else
120                 result = sensor_write_reg(client, sensor->ops->ctrl_reg, 0x00);
121
122         if (result)
123                 dev_err(&client->dev, "%s:fail to active sensor\n", __func__);
124
125         DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",
126                 __func__,
127                 sensor->ops->ctrl_reg,
128                 sensor->ops->ctrl_data, enable);
129         return result;
130 }

打开gsensor功能之后,然后去读取gsensor的三轴原始数据,这里连续读取6个字节的寄存器值,分别对应三轴数据:

 reg_buf = sensor->ops->read_reg; //这里从read_reg读取连续6个寄存器的值(0x28,0x29,0x2A...),他们是gsensor的三轴数据寄存器for (i = 0; i < sensor->ops->read_len; i++) {buffer[i] = sensor_read_reg(client, reg_buf);reg_buf++;printk("\n# lsm9ds1: __%s__, _line[%d]_ (buf[%d]= %x)\n", __func__, __LINE__, i, buffer[i]);}

input子系统上报数据,上报之后就可以通过getevent获取到数值:

static int gsensor_report_value(struct i2c_client *client,struct sensor_axis *axis)
{struct sensor_private_data *sensor =(struct sensor_private_data *)i2c_get_clientdata(client);if (sensor->status_cur == SENSOR_ON) {input_report_abs(sensor->input_dev, ABS_X, axis->x);input_report_abs(sensor->input_dev, ABS_Y, axis->y);input_report_abs(sensor->input_dev, ABS_Z, axis->z);input_sync(sensor->input_dev);}return 0;
}

内核驱动加载和卸载函数:【kernel跑起来会自动执行module_init函数】

module_init(gsensor_lsm9ds1_init);
module_exit(gsensor_lsm9ds1_exit);

5、Android层中的sensor相关宏配置
BoardConfig.mk 中:

# Sensors
BOARD_SENSOR_ST := true //采用 RK 的 sensors Hal,也就是本文介绍的
BOARD_SENSOR_MPU_PAD := false //仅适用MPU6500、mpu6050 等芯片
支持哪些类型的sensor,如果没有,要配置成false,否则vts和cts测试会失败:
BOARD_GRAVITY_SENSOR_SUPPORT := true
BOARD_COMPASS_SENSOR_SUPPORT := false
BOARD_GYROSCOPE_SENSOR_SUPPORT := false
BOARD_PROXIMITY_SENSOR_SUPPORT := false
BOARD_LIGHT_SENSOR_SUPPORT := true
BOARD_PRESSURE_SENSOR_SUPPORT := false
BOARD_TEMPERATURE_SENSOR_SUPPORT := false

6、Gsensor和gyro的校准
Gsensor和gyro的校准可通过命令行方式,pcba测试的时候也可以做校准,具体查
看pcba的配置。

命令行校准方法:保持机器水平静止放置,输入以下命令校准:
Gsensor: echo 1 > /sys/class/sensor_class/accel_calibration
GYRO : echo 1 > /sys/class/sensor_class/gyro_calibration
查看校准值:
cat /sys/class/sensor_class/accel_calibration
cat /sys/class/sensor_class/gyro_calibration
如果无法查看校准值,则说明校准失败,可以打印 kernel log 确定失败原因。校准成功后,校准的值会保存到nand或emmc的vendor storage里面,不会被擦除,开机自动生效。

7、调试可能遇到问题点
7.1 getevent查看gsensor无数据上报
排查思路:
1) 确认驱动是否注册上,可以通过getevent 查看是否有名为gsensor的input设备;没有的话就要看为何没注册上,有可能是 dts 配置问题,驱动问题,i2c通讯失败,chip id 不匹配等等可能的原因,查看kernel log是否,具体问题具体分析;如果有注册上,往下看。
2) 确认android 层相关宏是否打开;
3) 确认hal层代码是否正常运行;开机打印logcat,搜索sensor字段查看相关log。
4 ) 确认上报的事件类型是否对应(kernel上报的和HAL读取的是否一致(ABS_X还是ABS_RX,或者ABS_MISC等))

7.2 Getevent有数据上报,屏幕不旋转或者旋转无规律;
除可通过sensor的apk查看数值是否正确外,还可以通过命令的方式查看android
上报的gsensor数据是否正确:
setprop sensor.debug.level 2
手动灭屏休眠,再唤醒后命令生效,通过 logcat –s SensorsHal 可以查看到 hal 上报
的gsensor数值;
静止水平放置时,理论正确的数值应该是有个轴的值为+9.8 或者-9.8,另外两个轴的
值为 0;
如果数值不对,请确认上面章节介绍的数据上报转换是否正确。

7.2 gsensor的方向不对
Sensor-dev.c定义了layout 值,对应不同的矩阵,具体可以查看 sensor-dev.c 代码查询,所以,适配方向可以通过修改dts里面的layout值来选择对应的转换矩阵,达到方向的变化。

layout = <4>;

8、rk3399 android7.1 sensor代码框架简单梳理:
HAL代码目录:

hardware/rockchip/sensor/stMmaSensor.cpp //gsensorGyroSensor.cpp //gyroAkmSensor.cpp //compass

kernel代码目录:

kernel/drivers/input/sensors/
accel //gsensor
compass //compass
gyro //gyro
首先开机起来,设备和driver的compatible属性匹配,然后跑sensor_probe探测函数,在里面进行一些初始化还有sensor 输入设备的注册;
初始化部分主要调用sensor_chip_init进行具体sensor的初始化调用,跑到对应sensor驱动里面去执行,通过sensor->ops = ops;这个结构体指针调用;
调用sensor_get_id获取sensor id值是否跟你具体sensor驱动的id值(sensor->ops->id_data)一致;
调用sensor_initial -->调用 sensor->ops->init(client)初始化sensor,主要进行一些寄存器值的设置;
调用devm_input_allocate_device分配输入设备,然后调用input_register_device注册输入子设备;
调用sensor_irq_init初始化中断:包括申请中断号,注册中断子程序sensor_interrupt等的动作;当打开sensor 测试apk时,hal层到底层驱动的调用流程如下[HAL]表示在hal层执行,[kernel表示在kernel层的driver实现]:
这里以gsensor的HAL到driver的调用为例说明:
[HAL]==>init_nusensors[HAL]==>poll__activate [HAL]==>调用int MmaSensor::enable,[HAL]==>然后调用ioctl(dev_fd, GSENSOR_IOCTL_START)打开gsensor,[kernel]==>调用到驱动的unlocked_ioctl = gsensor_dev_ioctl[kernel]==>sensor_enable(sensor, SENSOR_ON); //通过cmd(GSENSOR_IOCTL_START)调用到sensor_enable[kernel]==>然后调用到具体sensor驱动的sensor->ops->active(client, 1, sensor->pdata->poll_delay_ms); //使能sensor[kernel]==>然后打开中断或者打开循环工作队列使能中断:enable_irq(client->irq);加载工作队列:schedule_delayed_work[kernel]==>调用input_report_abs/input_sync上报读取到的sensor数据,如果调用成功可以在adb中执行getevent有数据上报[HAL]==>然后调用 MmaSensor::readEvents来读取gsensor数据,也就是读取输入子系统上报到上层的数据

rk3399_android7.1平台调试sensor流程记录相关推荐

  1. 记一次rk平台热点打开流程追踪记录

    记一次rk平台热点打开流程追踪记录 问题描述 rk平台偶现热点打开失败,错误日志如下: I/android.hardware.wifi@1.0-service: Starting legacy HAL ...

  2. .net erp(办公oa)开发平台架构之流程服务概要介绍

    背景 搭建一个适合公司erp业务的开发平台. 架构概要图:     流程引擎开发平台:   包含流程引擎设计器,流程管理平台,流程引擎服务.目前只使用单个数据库进行管理.   流程引擎设计器 采用si ...

  3. Hisilicon 平台调试经验总结

    记录最近一年调试hisilicon 平台的相关经验,现已经转到互联网云存储方面的.话说嵌入领域,智能硬件领域,无非就是CPU,外设:但鉴于现在芯片原厂SDK 中基本都封装好啊! 改动的比较少,差不多就 ...

  4. 小程序微信支付开发流程记录

    我所在公司需要开发一款商城小程序,里面需要用到微信支付,我负责里面的下单功能,从小程序端到后台的支付流程都是我自己开发的,由于我们组没有人有开发微信支付的经验,只有我有开发过JSAPI的微信支付的经验 ...

  5. 在INTEL KABYALAKE平台上运行COREBOOT 记录

    在INTEL KABYALAKE平台上运行COREBOOT 记录 1.选择INTEL-KABYLAKE DDR4 RVP11 2.添加ME/CPU微CODE/FLASH description 3.设 ...

  6. 高通SM4350平台指纹移植流程

    本文总结了高通sm4350平台指纹移植流程,厂家一般会提供移植文档,本文档可作为补充: 准备工作: 1.把指纹模组扣到主板上的SPI连接器上 2.高通sm4350平台,Android R版本全代码,全 ...

  7. 领导驾驶舱大数据平台的实施流程

    如今的大数据时代,管理者都喜欢引入一款领导驾驶舱大数据平台到日常管理中,让工作更有效率.领导驾驶舱的理念已经非常流行也深受喜爱.但是,工具用不好,发挥不了作用,依旧是徒劳无功的事情.那领导驾驶舱大数据 ...

  8. Android STB 海思平台调试

    文章目录 一.产品参数 1.1 Hi3798MV100 1.2 Hi3798MV300 二.网络类&播放类 三.系统类 3.1 输出相关 3.2 CEC 3.3 杜比 3.4 IGMP 3.5 ...

  9. unreal ue4 PixelStreaming 局域网及公有云部署全流程记录

    PixelStreaming 局域网及公有云部署全流程记录 发表于 2020-04-10 |  更新于: 2020-04-20 |  分类于 Unreal Engine |  717 写在前面 本篇是 ...

  10. 打包分包工具流程记录

    流程记录: 开始打包AB 1. 收集需要打包的资源路径 收集资源逻辑抽离出来做成Mgr,收集的资源用字典存取,键值为资源路径.(用IO流的DirectoryInfo.GetFileSystemInfo ...

最新文章

  1. 2020秋季学期教学委员会第一次全体会议
  2. html仿命令行界面,实战:vue仿dos命令界面
  3. java poi导入50万数据_java从oracle读取50万条数据写入Excel中抛GC overhead limit exc
  4. mybatis resultmap嵌套_Java面试专题之九:Mybatis面试5个大概率被问到的问题
  5. python算法实现源码_python 实现A_算法的示例代码
  6. 分享一些Java开发人员在编程中最容易踩雷的地方!
  7. Unity DF-GUI 中文输入以及自动换行
  8. my footprint :走过的路
  9. centos7和centos6 开机 运行级别详解和设置
  10. navicat将远程数据库复制到本地数据库方法
  11. asp.net常见问题收集
  12. Mask Network与Conflux发起联合Bounty
  13. !!!后续博客写到简书 + 博客园留博客目录
  14. github的学习和使用
  15. Atititi 软件界面gui开发之道 attilax著
  16. laravel queue(消息队列)的使用实例
  17. 编译原理第四章课后题答案
  18. 初次办理机电设备安装资质流程
  19. Java Web基础入门第八十二讲 Listener(监听器)——监听器在开发中的应用(一)
  20. CMTime,CMTimeMake CMTimeMakeWithSeconds

热门文章

  1. 【EMV L2】CDA复合动态数据认证/应用密文生成
  2. 通过机器学习神经网络自动写前端代码
  3. Dynamics CRM 2015中的SSRS Report集成配置
  4. Android Studio在创建项目是一直处于building “project name”gradle project info的解决办法...
  5. CSS position属性---absolute与relative
  6. TortoiseSVN--Subversion客户端使用详解及问题解决
  7. sql 基本操作语句笔记
  8. 关系分类 relation classification
  9. 【论文投稿】SOTA论文也未必能被接收,谷歌科学家Eric Jang谈顶会审稿标准
  10. 【经验之谈】掌握这13个PyTorch Trick,让你做实验行云流水~