linux传感器二之G-Sensor 8452驱动及相关_g-sensor 芯片-程序员宅基地

技术标签: linux底层驱动开发之input子系统篇  

8452是一款G-Sensor芯片,采用I2C跟主芯片通讯,采用中断方式跟操作系统协作。通过内部检测XYZ三个方向的加速度,实现各种应用。

(1)原理框图如下:

       

      现在来实现在WINCE中的I2C驱动,读写的时序波形图分别如下:

读:

写:

基础写函数实现如下:

static P_XLLP_OST_T ost_reg = 0;
static XLLP_I2C_T  *i2c_reg = NULL;
static XLLP_CLKMGR_T *clk_reg = NULL;  //在初始化中要映射

static int OS_I2CMasterWriteData(XLLP_UINT8_T slaveAddr, const XLLP_UINT8_T * bytesBuf, int bytesCount)
{
     volatile int status;
     XLLP_BOOL_T bSENDSTOP = XLLP_TRUE;  //写完之后发停止位
     status = XllpCustomI2CWrite((P_XLLP_I2C_T)(i2c_reg), (P_XLLP_OST_T)(ost_reg), slaveAddr, bytesBuf,   bytesCount, bSENDSTOP,25);

     return status;
}

static int MMA8452_WriteSensorReg( const XLLP_UINT8_T subAddress, XLLP_UINT8_T *bufP )
{
     XLLP_UINT8_T buffer[2];
     int status;
     int lock;
 
     buffer[0] = subAddress;
     buffer[1] = *bufP;

     gSensorSlaveAddr = 0x1c;  //I2C地址
     lock = __i2c_acquire_lock();
 
     status = OS_I2CMasterWriteData( gSensorSlaveAddr, buffer, 2);
     if (XLLP_STATUS_SUCCESS != status) {
        RETAILMSG(1, (TEXT("Failed to write MMA8452_WriteSensorReg./r/n")));
     }

     __i2c_release_lock(lock);
     return status;
}

基础读函数实现如下:

static int OS_I2CMasterWriteData_Read(XLLP_UINT8_T slaveAddr, const XLLP_UINT8_T * bytesBuf, int bytesCount)
{
      volatile int status;
      XLLP_BOOL_T bSENDSTOP = XLLP_FALSE;  //写完后不发停止位
      status = XllpCustomI2CWrite((P_XLLP_I2C_T)(i2c_reg), (P_XLLP_OST_T)(ost_reg), slaveAddr, bytesBuf, bytesCount, bSENDSTOP,25);

      return status;
}

static int OS_I2CMasterReadData(XLLP_UINT8_T slaveAddr, XLLP_UINT8_T * bytesBuf, int bufLen)
{
      volatile int status;
      XLLP_BOOL_T bSENDSTOP = XLLP_TRUE;  //读完后发停止位

      status = XllpCustomI2CRead((P_XLLP_I2C_T)(i2c_reg), (P_XLLP_OST_T)(ost_reg), slaveAddr, bytesBuf, bufLen, bSENDSTOP,25);

      return status;
}

static int MMA8452_ReadSensorReg( const XLLP_UINT8_T subAddress, XLLP_UINT8_T *bufP )
{
      XLLP_UINT8_T buffer[1];
      int status;
      int lock;
 
      buffer[0] = subAddress;
      *bufP = 0x00;
 
      gSensorSlaveAddr = 0x1c;

      lock = __i2c_acquire_lock();  
      status = OS_I2CMasterWriteData_For_Read( gSensorSlaveAddr, buffer, 1); //写要读的子地址,注意没有停止位
      if (XLLP_STATUS_SUCCESS == status)
      {
             status = OS_I2CMasterReadData( gSensorSlaveAddr, buffer, 1); //重写器件地址并读
             *bufP = buffer[0];               //回传数据
       }
       else
       {
              RETAILMSG(1, (TEXT("Failed to MMA8452_ReadSensorReg./r/n")));
       }
   
       if (XLLP_STATUS_SUCCESS != status) {
           RETAILMSG(1, (TEXT("Failed to MMA8452_ReadSensorReg./r/n")));
       }

       __i2c_release_lock(lock);
       return status;
}

(2)唤醒功能的解析

        在实际使用中,会用到g-sensor唤醒系统。一般有方向唤醒和点击唤醒两种。两者都是利用XYZ方向轴上的加速度变化,来中断操作系统。在配置睡眠唤醒的时候,一般有若干参数寄存器需要设置合适值。其中,双击唤醒的图示如下(从图中可以看出是默认低电平有效时是高电平):

                     

对于8452,MMA8452_PULSE_THSX、MMA8452_PULSE_THSY、MMA8452_PULSE_THSZ这三个寄存器是用来设置加速度门限,值越大,需要敲击的力度也越大,对唤醒反应越迟钝。MMA8452_PULSE_TMLT是对第一次敲击的响应时间;MMA8452_PULSE_LTCY是第一次敲击后滤波去噪的延迟时间,该参数太小,会造成有可能把第一次敲击的杂波当作第二次敲击,该参数太大,会造成相隔很短的第二次敲击不会被识别;MMA8452_PULSE_WIND则是第二次敲击的识别时间区间,不在这个时间区间内的敲击不会被识别,以免造成误操作。

 (3)关于layout的说明

                                  

使用图示如下:

参照上图的layout位置图,可以设置具体使用时的方向参数,最终只有一个值是正确的。注意:始终以正常使用手机的方位来看图,0-7的参数由于不同平台的软件不同,也可能意味着是从1-8。

        举一个实例,一个四方向旋转的平板整机,当前方向值是1,平放时Z轴为-9.XX,说明Z轴反了,那么决定正确值的范围只能在(4、5、6、7)之间;以屏幕旋转的正确视图为准(X Y轴的指向,跟手机一样类似竖屏。但不以这个为准),发现右旋X是9.XX左旋X是-9.XX,是正确的;但是Y轴的视图上下反了,且从Y的读值看出来也是反的。综合以上,X轴不变Y轴反一下的图示只有5符合要求。从上上图的座标变换表格也可以看出:1对应的是(-y,x,z),把Y轴Z轴都倒的就是(y,x,-z),对应的方向值就是5。

(4)gsensor返回值的说明及gsensor校准

        值域范围有正负数之分,正负是方向,以跟重力加速度对比来确定下来;值则以是否动态来说明。静止误差范围在300mg内算正常,也就是说<9.8-0.3,9.8+0.3>,超出该范围内说明GSENSOR的内部出厂校准参数出了偏差,可能原因是温度、运输、贴片所导致,该错误是不可逆的。

        出现以上值超限的话,则需要对GSENSOR的工作过程进行校准,这个过程仅仅是对后期上报的数据进行修正,不可能再去纠正GSENSOR的内部属性。一般的过程是,平台放在一个平面上,分别得到GSENSOR的三个方向的校准offset,将其存入NVRAM中,以后再上报数据时读GSENSOR的读出值跟offset进行运算后再上报。由于GSENSOR的内部偏差是固定的,所以该补偿可用于任何工作状态的GSENSOR应用,此过程可采用若干次采样的平均值上报以减少误差。

        需要注意的是,该校准仅仅是对出现偏差的现象进行校准,要么偏大要么偏小;如果某个时候GSENSOR读出的值的上限和下限均超出范围,应该考虑是否是其他原因(电压纹波,高采样率)导致的,此时使用offset偏差是解决不了问题的。

(5)Z轴补丁

         8452的某些批次芯片本身存在质量问题。Z轴受敲击一旦出现超出范围问题之后达到20或者-20(超出-2g/2g),除非受其他敲击可能恢复的话,绝大部分时候是不会自动恢复的,这是芯片自身的问题,内部物理结构发生变化了。所以,可以采用在SENSOR HAL补丁方式解决这个问题,方法是Z轴出问题之后用XY模拟出Z轴的值,以让上层软件可以使用。以下的PATCH目前是可以保证平放时是9.8。同时芯片厂工程师说明该补丁的缺陷有两个:一是无法判断出手机是正放还是反放,提供的值只能是9.8没有-9.8;二是在手机动态时,模拟出的Z值是有偏差的。

        补丁CODE如下:

#define ZCORRECTACTIVE 1      /*  switch on /off the z  stuck correction code */ 
#define ONEGCOUNTS 1024      /* 1024  1g counts for MMA8452 */
#define ZLOCKTHRESHOLD 2*ONEGCOUNTS*0.9     /* 10% below 2g stuck counts */
#define ZNORMALDIRECTION 1      /* define the sign of Z axis for normal screen face up operation, supposing the Z sign is positive here  */
#define ZTIMEOUTCOUNTS 5         /* Z lock timeout counts, suppose sampling interval is 25Hz,40ms, 5 x 40ms=200ms for timeout delay*/
int zneg_out_counts = 0;
int zpos_out_counts = 0; 

在SENSOR HAL的POLL函数内添加

if(sensors_data.data[i].sensor==0)                        //只针对gsensor处理

{
         LOGD("%s:get sensor value,type: %d, value0 %d, value1 %d,value2 %d,updata %d!zhangcheng\r\n", __func__,
         sensors_data.data[i].sensor, sensors_data.data[i].values[0], sensors_data.data[i].values[1],
          sensors_data.data[i].values[2],sensors_data.data[i].update);    //打印出当前读出的gsensor的原始值
         xacc = sensors_data.data[i].values[0]*ONEGCOUNTS/9806;    
         yacc = sensors_data.data[i].values[1]*ONEGCOUNTS/9806;
         zacc = sensors_data.data[i].values[2]*ONEGCOUNTS/9806;     //转换,将原始重力加速度转换成g系数

         if ((ZCORRECTACTIVE == 1))
         {
                 if(zacc >= ZLOCKTHRESHOLD)       //正向超限
                 {
                         if(zneg_out_counts == 0)
                         {
                                  zpos_out_counts++;
                                  if (zpos_out_counts >= ZTIMEOUTCOUNTS)
                                  {
                                          zpos_out_counts = ZTIMEOUTCOUNTS;
                                          zacc = ZNORMALDIRECTION  *sqrt(abs(ONEGCOUNTS*ONEGCOUNTS-xacc*xacc-yacc*yacc));     //用XY轴模拟Z轴
                                          sensors_data.data[i].values[2] = zacc*9806/ONEGCOUNTS;                      //反转换后传给上层应用
                                  }
                          }
                          else if(zneg_out_counts > 0)
                          {
                                  zneg_out_counts = 0;
                          }
                   }
                   else if(zacc<= (-1)*ZLOCKTHRESHOLD)      //反向超限
                   {
                           if ((zpos_out_counts == 0))
                           {
                                    zneg_out_counts++;
                                    if (zneg_out_counts >= ZTIMEOUTCOUNTS)
                                    {
                                             zneg_out_counts = ZTIMEOUTCOUNTS;
                                             zacc = ZNORMALDIRECTION  * sqrt(abs(ONEGCOUNTS*ONEGCOUNTS-xacc*xacc-yacc*yacc));        //用XY轴模拟Z轴
                                             sensors_data.data[i].values[2] = zacc*9806/ONEGCOUNTS;                     //反转换后传给上层应用
                                    }
                           }
                           else if(zpos_out_counts > 0) 
                           {
                                    zpos_out_counts = 0;
                           }
                   }
                   else
                   {
                            zpos_out_counts = 0;
                            zneg_out_counts = 0;
                   }        
          }
}

(6)GSENSOR跟陀螺仪的差别

         陀螺仪能够测量沿一个轴或几个轴运动的角速度,是补充加速计功能的理想技术。如果组合使用加速计和陀螺仪这两种传感器,系统设计人员可以跟踪并捕捉三维空间的完整运动,为最终用户提供现场感更强的用户使用体验、精确的导航系统以及其它功能。

(7)GSENSOR游戏反应迟钝的分析

        很多重力游戏比如摩托车/飞行器/枪击等游戏,依赖于GSENSOR的即时响应来操作,如果GSENSOR的响应不够及时,那么这游戏基本上是很难玩,极大影响用户体验。出现该问题的原因有两种:(1)如果GSENSOR是轮询工作的,轮询的频率很重要;(2)GSENSOR的采样频率,影响到即时响应。

         曾经碰到过这样一个现象:手机断电后开机重力游戏正常,但是假关机再开机后重力游戏就响应非常慢。从上面两个可能点入手,通过TRACE可以确定上层对底层轮询的IOCTL的频率是正常的,这个可以通过内核TRACE的时间看出来,那么问题就出现在GSENSOR本身。后来分析出确实是采样频率被从60HZ设定成1HZ了,难怪上层响应这么慢,这个最直接的体现就是GSENSOR上报的是一大串相同的数据,而正常的时候GSENSOR上报的数据是一定范围跳动的。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Jkf40622/article/details/41680715

智能推荐

hdu 1229 还是A+B(水)-程序员宅基地

文章浏览阅读122次。还是A+BTime Limit: 2000/1000 MS (Java/Others)Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 24568Accepted Submission(s): 11729Problem Description读入两个小于10000的正整数A和B,计算A+B。...

http客户端Feign——日志配置_feign 日志设置-程序员宅基地

文章浏览阅读419次。HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息。FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。BASIC:仅记录请求的方法,URL以及响应状态码和执行时间。NONE:不记录任何日志信息,这是默认值。配置Feign日志有两种方式;方式二:java代码实现。注解中声明则代表某服务。方式一:配置文件方式。_feign 日志设置

[转载]将容器管理的持久性 Bean 用于面向服务的体系结构-程序员宅基地

文章浏览阅读155次。将容器管理的持久性 Bean 用于面向服务的体系结构本文将介绍如何使用 IBM WebSphere Process Server 对容器管理的持久性 (CMP) Bean的连接和持久性逻辑加以控制,使其可以存储在非关系数据库..._javax.ejb.objectnotfoundexception: no such entity!

基础java练习题(递归)_java 递归例题-程序员宅基地

文章浏览阅读1.5k次。基础java练习题一、递归实现跳台阶从第一级跳到第n级,有多少种跳法一次可跳一级,也可跳两级。还能跳三级import java.math.BigDecimal;import java.util.Scanner;public class Main{ public static void main(String[]args){ Scanner reader=new Scanner(System.in); while(reader.hasNext()){ _java 递归例题

面向对象程序设计(荣誉)实验一 String_对存储在string数组内的所有以字符‘a’开始并以字符‘e’结尾的单词做加密处理。-程序员宅基地

文章浏览阅读1.5k次,点赞6次,收藏6次。目录1.串应用- 计算一个串的最长的真前后缀题目描述输入输出样例输入样例输出题解2.字符串替换(string)题目描述输入输出样例输入样例输出题解3.可重叠子串 (Ver. I)题目描述输入输出样例输入样例输出题解4.字符串操作(string)题目描述输入输出样例输入样例输出题解1.串应用- 计算一个串的最长的真前后缀题目描述给定一个串,如ABCDAB,则ABCDAB的真前缀有:{ A, AB,ABC, ABCD, ABCDA }ABCDAB的真后缀有:{ B, AB,DAB, CDAB, BCDAB_对存储在string数组内的所有以字符‘a’开始并以字符‘e’结尾的单词做加密处理。

算法设计与问题求解/西安交通大学本科课程MOOC/C_算法设计与问题求解西安交通大学-程序员宅基地

文章浏览阅读68次。西安交通大学/算法设计与问题求解/树与二叉树/MOOC_算法设计与问题求解西安交通大学

随便推点

[Vue warn]: Computed property “totalPrice“ was assigned to but it has no setter._computed property "totalprice" was assigned to but-程序员宅基地

文章浏览阅读1.6k次。问题:在Vue项目中出现如下错误提示:[Vue warn]: Computed property "totalPrice" was assigned to but it has no setter. (found in <Anonymous>)代码:<input v-model="totalPrice"/>原因:v-model命令,因Vue 的双向数据绑定原理 , 会自动操作 totalPrice, 对其进行set 操作而 totalPrice 作为计..._computed property "totalprice" was assigned to but it has no setter.

basic1003-我要通过!13行搞定:也许是全网最奇葩解法_basic 1003 case 1-程序员宅基地

文章浏览阅读60次。十分暴力而简洁的解决方式:读取P和T的位置并自动生成唯一正确答案,将题给测点与之对比,不一样就给我爬!_basic 1003 case 1

服务器浏览war文件,详解将Web项目War包部署到Tomcat服务器基本步骤-程序员宅基地

文章浏览阅读422次。原标题:详解将Web项目War包部署到Tomcat服务器基本步骤详解将Web项目War包部署到Tomcat服务器基本步骤1 War包War包一般是在进行Web开发时,通常是一个网站Project下的所有源码的集合,里面包含前台HTML/CSS/JS的代码,也包含Java的代码。当开发人员在自己的开发机器上调试所有代码并通过后,为了交给测试人员测试和未来进行产品发布,都需要将开发人员的源码打包成Wa..._/opt/bosssoft/war/medical-web.war/web-inf/web.xml of module medical-web.war.

python组成三位无重复数字_python组合无重复三位数的实例-程序员宅基地

文章浏览阅读3k次,点赞3次,收藏13次。# -*- coding: utf-8 -*-# 简述:这里有四个数字,分别是:1、2、3、4#提问:能组成多少个互不相同且无重复数字的三位数?各是多少?def f(n):list=[]count=0for i in range(1,n+1):for j in range(1, n+1):for k in range(1, n+1):if i!=j and j!=k and i!=k:list.a..._python求从0到9任意组合成三位数数字不能重复并输出

ElementUl中的el-table怎样吧0和1改变为男和女_elementui table 性别-程序员宅基地

文章浏览阅读1k次,点赞3次,收藏2次。<el-table-column prop="studentSex" label="性别" :formatter="sex"></el-table-column>然后就在vue的methods中写方法就OK了methods: { sex(row,index){ if(row.studentSex == 1){ return '男'; }else{ return '女'; }..._elementui table 性别

java文件操作之移动文件到指定的目录_java中怎么将pro.txt移动到design_mode_code根目录下-程序员宅基地

文章浏览阅读1.1k次。java文件操作之移动文件到指定的目录_java中怎么将pro.txt移动到design_mode_code根目录下

推荐文章

热门文章

相关标签