三轴陀螺仪MPU3050驱动程序分析

控制/MCU

1878人已加入

描述

  MPU3050是invensense公司的三轴陀螺仪芯片,三轴陀螺仪最大的作用就是“测量角速度,以判别物体的运动状态,所以也称为运动传感器。

  下图是MPU3050的系统框图,芯片有1个中断引脚,可以通过i2c来控制,获取xGyro,yGyro,zGyro

  MPU3050

  设备驱动中用mpu3050_sensor结构体来描述MPU3050设备对象(对象中包含i2c客户端及输入设备来处理获取的x,y,z轴数据的传递)

  structmpu3050_sensor{//mpu3050传感器

  structi2c_client*client;//i2c客户端

  structdevice*dev;//设备文件

  structinput_dev*idev;//输入设备

  };

  用axis_data来描述获取的xGyro,yGyro,zGyro的数值

  structaxis_data{//轴数据

  s16x;//x轴

  s16y;//y轴

  s16z;//z轴

  };

  首先注册i2c设备

  module_i2c_driver(mpu3050_i2c_driver);

  staticstructi2c_drivermpu3050_i2c_driver={

  .driver={

  .name=“mpu3050”,

  .owner=THIS_MODULE,

  .pm=&mpu3050_pm,

  .of_match_table=mpu3050_of_match,

  },

  .probe=mpu3050_probe,//i2cprobe方法

  .remove=__devexit_p(mpu3050_remove),

  .id_table=mpu3050_ids,

  };

  i2c设备与驱动匹配需要在板级驱动中注册i2c驱动

  htconemax板的做法如下

  staticstructi2c_board_info__initdatampu3050_GSBI12_boardinfo[]={

  {

  I2C_BOARD_INFO(“mpu3050”,0xD0》》1),

  .irq=PM8921_GPIO_IRQ(PM8921_IRQ_BASE,PM_GYRO_INT),

  .platform_data=&mpu3050_data,

  },

  };

  然后调用

  i2c_register_board_info(MSM8064_GSBI2_QUP_I2C_BUS_ID,

  mpu3050_GSBI12_boardinfo,

  ARRAY_SIZE(mpu3050_GSBI12_boardinfo));

  注册i2c板级信息

  MPU3050
 

  设备匹配后调用mpu3050_probe方法

  staticint__devinitmpu3050_probe(structi2c_client*client,conststructi2c_device_id*id)

  {

  structmpu3050_sensor*sensor;//mpu3050传感器

  structinput_dev*idev;//输入设备

  intret;

  interror;

  sensor=kzalloc(sizeof(structmpu3050_sensor),GFP_KERNEL);//分配mpu3050数据

  idev=input_allocate_device();//分配输入设备

  if(!sensor||!idev){

  dev_err(&client-》dev,“failedtoallocatedriverdata\n”);

  error=-ENOMEM;

  gotoerr_free_mem;

  }

  sensor-》client=client;//捆绑i2c客户端

  sensor-》dev=&client-》dev;//捆绑设备文件

  sensor-》idev=idev;//捆绑输入设备

  mpu3050_set_power_mode(client,1);//设置设备正常电压模式

  msleep(10);//睡眠

  ret=i2c_smbus_read_byte_data(client,MPU3050_CHIP_ID_REG);//获取0x00寄存器值

  if(ret《0){

  dev_err(&client-》dev,“failedtodetectdevice\n”);

  error=-ENXIO;

  gotoerr_free_mem;

  }

  if(ret!=MPU3050_CHIP_ID){//判断芯片ID值(0x69)是否MPU3050

  dev_err(&client-》dev,“unsupportedchipid\n”);

  error=-ENXIO;

  gotoerr_free_mem;

  }

  idev-》name=“MPU3050”;//设置输入设备名

  idev-》id.bustype=BUS_I2C;//输入设备使用i2c总线

  idev-》dev.parent=&client-》dev;//设置i2c设备为输入设备父设备

  idev-》open=mpu3050_input_open;//输入设备打开方法

  idev-》close=mpu3050_input_close;//输入设备关闭方法

  __set_bit(EV_ABS,idev-》evbit);//设置绝对位移事件标志位,设置各轴数据范围

  input_set_abs_params(idev,ABS_X,MPU3050_MIN_VALUE,MPU3050_MAX_VALUE,0,0);

  input_set_abs_params(idev,ABS_Y,MPU3050_MIN_VALUE,MPU3050_MAX_VALUE,0,0);

  input_set_abs_params(idev,ABS_Z,MPU3050_MIN_VALUE,MPU3050_MAX_VALUE,0,0);

  input_set_drvdata(idev,sensor);//&idev-》dev-》p-》driver_data=sensor

  pm_runtime_set_active(&client-》dev);

  error=mpu3050_hw_init(sensor);//初始化MPU3050固件

  if(error)

  gotoerr_pm_set_suspended;

  //申请中断,上升沿触发

  error=request_threaded_irq(client-》irq,NULL,mpu3050_interrupt_thread,IRQF_TRIGGER_RISING,“mpu3050”,sensor);

  if(error){

  dev_err(&client-》dev,“can‘tgetIRQ%d,error%d\n”,client-》irq,error);

  gotoerr_pm_set_suspended;

  }

  error=input_register_device(idev);//注册输入设备

  if(error){

  dev_err(&client-》dev,“failedtoregisterinputdevice\n”);

  gotoerr_free_irq;

  }

  pm_runtime_enable(&client-》dev);

  pm_runtime_set_autosuspend_delay(&client-》dev,MPU3050_AUTO_DELAY);

  return0;

  err_free_irq:

  free_irq(client-》irq,sensor);

  err_pm_set_suspended:

  pm_runtime_set_suspended(&client-》dev);

  err_free_mem:

  input_free_device(idev);

  kfree(sensor);

  returnerror;

  }

  申请,配置,注册相应的input设备,设置电源模式,初始化mpu3050芯片,申请中断,并指明中断返回函数

  设置电源模式:mpu3050有两种电压模式val=1为正常模式,val=0为低功耗模式

  staticvoidmpu3050_set_power_mode(structi2c_client*client,u8val)

  {

  u8value;

  value=i2c_smbus_read_byte_data(client,MPU3050_PWR_MGM);//获取0x3E寄存器数据

  //根据val值设置0x3E寄存器第6位SLEEP

  value=(value&~MPU3050_PWR_MGM_MASK)|

  (((val《《MPU3050_PWR_MGM_POS)&MPU3050_PWR_MGM_MASK)^MPU3050_PWR_MGM_MASK);

  i2c_smbus_write_byte_data(client,MPU3050_PWR_MGM,value);//设置0x3E寄存器数据

  }

  初始化mpu3050:软复位,配置时钟及分频。。。

  staticint__devinitmpu3050_hw_init(structmpu3050_sensor*sensor)

  {

  structi2c_client*client=sensor-》client;//获取i2c客户端

  intret;

  u8reg;

  /*Reset设置0x3E寄存器第7位H_RESET*/

  ret=i2c_smbus_write_byte_data(client,MPU3050_PWR_MGM,MPU3050_PWR_MGM_RESET);

  if(ret《0)

  returnret;

  //获取0x3E寄存器值

  ret=i2c_smbus_read_byte_data(client,MPU3050_PWR_MGM);

  if(ret《0)

  returnret;

  ret&=~MPU3050_PWR_MGM_CLKSEL;//清除0x3E寄存器0~2位CLK_SET值

  ret|=MPU3050_PWR_MGM_PLL_Z;//设置0x3E寄存器CLK_SET值为0x03

  ret=i2c_smbus_write_byte_data(client,MPU3050_PWR_MGM,ret);//设置0x3E寄存器

  if(ret《0)

  returnret;

  /*Outputfrequencydivider.Thepollinterval设置0x15寄存器值为119输出分频值*/

  ret=i2c_smbus_write_byte_data(client,MPU3050_SMPLRT_DIV,MPU3050_DEFAULT_POLL_INTERVAL-1);

  if(ret《0)

  returnret;

  /*Setlowpassfilterandfullscale设置低通滤波器和全扫描范围*/

  reg=MPU3050_DEFAULT_FS_RANGE;

  reg|=MPU3050_DLPF_CFG_42HZ《《3;

  reg|=MPU3050_EXT_SYNC_NONE《《5;

  ret=i2c_smbus_write_byte_data(client,MPU3050_DLPF_FS_SYNC,reg);//设置0x16寄存器

  if(ret《0)

  returnret;

  return0;

  }

  中断返回函数:读取xyz轴数值,并上报给input子系统

  staticirqreturn_tmpu3050_interrupt_thread(intirq,void*data)

  {

  structmpu3050_sensor*sensor=data;//获取mpu3050传感器

  structaxis_dataaxis;

  mpu3050_read_xyz(sensor-》client,&axis);//获取xyz轴数值

  input_report_abs(sensor-》idev,ABS_X,axis.x);//上报x轴事件

  input_report_abs(sensor-》idev,ABS_Y,axis.y);//上报y轴事件

  input_report_abs(sensor-》idev,ABS_Z,axis.z);//上报z轴事件

  input_sync(sensor-》idev);//同步事件

  returnIRQ_HANDLED;

  }

  获取xyz轴数值,通过i2c命令去获取便可

  staticintmpu3050_xyz_read_reg(structi2c_client*client,u8*buffer,intlength)

  {

  /*

  *Annoyingwecan’tmakethisconstbecausethei2clayerdoesn‘t

  *declareinputbuffersconst.

  */

  charcmd=MPU3050_XOUT_H;//i2c读取0x1D~0x22寄存器值

  structi2c_msgmsg[]={

  {

  .addr=client-》addr,

  .flags=0,

  .len=1,

  .buf=&cmd,

  },

  {

  .addr=client-》addr,

  .flags=I2C_M_RD,

  .len=length,

  .buf=buffer,

  },

  };

  returni2c_transfer(client-》adapter,msg,2);

  }

  应用层在MPU3050设备节点的时候会开启中断,MPU3050有数据更新则会触发中断,接着调用中断返回函数上报事件,应用程序便可读取设备节点获取xyz轴的数据

  staticintmpu3050_input_open(structinput_dev*input)

  {

  structmpu3050_sensor*sensor=input_get_drvdata(input);//获取mpu3050传感器

  interror;

  pm_runtime_get(sensor-》dev);

  /*Enableinterrupts

  使能中断,设置0x17寄存器MPU_RDY_EN,DMP_DONE_EN,RAW_RDY_EN位*/

  error=i2c_smbus_write_byte_data(sensor-》client,MPU3050_INT_CFG,

  MPU3050_LATCH_INT_EN|MPU3050_RAW_RDY_EN|MPU3050_MPU_RDY_EN);

  if(error《0){

  pm_runtime_put(sensor-》dev);

  returnerror;

  }

  return0;

  }

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分