zoukankan      html  css  js  c++  java
  • G-Sensor 8452驱动及相关

    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 ", __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上报的数据是一定范围跳动的。

     

     

    (转载)

  • 相关阅读:
    suse12安装详解
    Centos7上部署openstack mitaka配置详解(将疑难点都进行划分)
    菜鸟帮你跳过openstack配置过程中的坑[文末新添加福利]
    openstack中dashboard页面RuntimeError: Unable to create a new session key. It is likely that the cache is unavailable.
    Multiple network matches found for name 'selfservice', use an ID to be more specific.报错
    查看 SELinux状态及关闭SELinux
    SELinux深入理解
    IP地址、子网掩码、网络号、主机号、网络地址、主机地址
    Oracle job procedure 存储过程定时任务
    POI文件导出至EXCEL,并弹出下载框
  • 原文地址:https://www.cnblogs.com/Ph-one/p/4182856.html
Copyright © 2011-2022 走看看