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

     

     

    (转载)

  • 相关阅读:
    钟国晨160809323(作业5)
    12
    11
    第九次
    8作业
    第七次作业
    6
    林昊5
    计算机网络原理与应用笔记 3/29
    计算机网络原理与应用笔记 3/22
  • 原文地址:https://www.cnblogs.com/Ph-one/p/4182856.html
Copyright © 2020-2023  润新知