MPU3050是invensense公司的三軸陀螺儀芯片,三軸陀螺儀最大的作用就是“測量角速度,以判別物體的運(yùn)動(dòng)狀態(tài),所以也稱為運(yùn)動(dòng)傳感器。
下圖是MPU3050的系統(tǒng)框圖,芯片有1個(gè)中斷引腳,可以通過i2c來控制,獲取xGyro,yGyro,zGyro
設(shè)備驅(qū)動(dòng)中用mpu3050_sensor結(jié)構(gòu)體來描述MPU3050設(shè)備對象(對象中包含i2c客戶端及輸入設(shè)備來處理獲取的x,y,z軸數(shù)據(jù)的傳遞)
structmpu3050_sensor{//mpu3050傳感器
structi2c_client*client;//i2c客戶端
structdevice*dev;//設(shè)備文件
structinput_dev*idev;//輸入設(shè)備
};
用axis_data來描述獲取的xGyro,yGyro,zGyro的數(shù)值
structaxis_data{//軸數(shù)據(jù)
s16x;//x軸
s16y;//y軸
s16z;//z軸
};
首先注冊i2c設(shè)備
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設(shè)備與驅(qū)動(dòng)匹配需要在板級驅(qū)動(dòng)中注冊i2c驅(qū)動(dòng)
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,
},
};
然后調(diào)用
i2c_register_board_info(MSM8064_GSBI2_QUP_I2C_BUS_ID,
mpu3050_GSBI12_boardinfo,
ARRAY_SIZE(mpu3050_GSBI12_boardinfo));
注冊i2c板級信息
?
設(shè)備匹配后調(diào)用mpu3050_probe方法
staticint__devinitmpu3050_probe(structi2c_client*client,conststructi2c_device_id*id)
{
structmpu3050_sensor*sensor;//mpu3050傳感器
structinput_dev*idev;//輸入設(shè)備
intret;
interror;
sensor=kzalloc(sizeof(structmpu3050_sensor),GFP_KERNEL);//分配mpu3050數(shù)據(jù)
idev=input_allocate_device();//分配輸入設(shè)備
if(!sensor||!idev){
dev_err(&client-》dev,“failedtoallocatedriverdata\n”);
error=-ENOMEM;
gotoerr_free_mem;
}
sensor-》client=client;//捆綁i2c客戶端
sensor-》dev=&client-》dev;//捆綁設(shè)備文件
sensor-》idev=idev;//捆綁輸入設(shè)備
mpu3050_set_power_mode(client,1);//設(shè)置設(shè)備正常電壓模式
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”;//設(shè)置輸入設(shè)備名
idev-》id.bustype=BUS_I2C;//輸入設(shè)備使用i2c總線
idev-》dev.parent=&client-》dev;//設(shè)置i2c設(shè)備為輸入設(shè)備父設(shè)備
idev-》open=mpu3050_input_open;//輸入設(shè)備打開方法
idev-》close=mpu3050_input_close;//輸入設(shè)備關(guān)閉方法
__set_bit(EV_ABS,idev-》evbit);//設(shè)置絕對位移事件標(biāo)志位,設(shè)置各軸數(shù)據(jù)范圍
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;
//申請中斷,上升沿觸發(fā)
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);//注冊輸入設(shè)備
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;
}
申請,配置,注冊相應(yīng)的input設(shè)備,設(shè)置電源模式,初始化mpu3050芯片,申請中斷,并指明中斷返回函數(shù)
設(shè)置電源模式: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寄存器數(shù)據(jù)
//根據(jù)val值設(shè)置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);//設(shè)置0x3E寄存器數(shù)據(jù)
}
初始化mpu3050:軟復(fù)位,配置時(shí)鐘及分頻。。。
staticint__devinitmpu3050_hw_init(structmpu3050_sensor*sensor)
{
structi2c_client*client=sensor-》client;//獲取i2c客戶端
intret;
u8reg;
/*Reset設(shè)置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;//設(shè)置0x3E寄存器CLK_SET值為0x03
ret=i2c_smbus_write_byte_data(client,MPU3050_PWR_MGM,ret);//設(shè)置0x3E寄存器
if(ret《0)
returnret;
/*Outputfrequencydivider.Thepollinterval設(shè)置0x15寄存器值為119輸出分頻值*/
ret=i2c_smbus_write_byte_data(client,MPU3050_SMPLRT_DIV,MPU3050_DEFAULT_POLL_INTERVAL-1);
if(ret《0)
returnret;
/*Setlowpassfilterandfullscale設(shè)置低通濾波器和全掃描范圍*/
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);//設(shè)置0x16寄存器
if(ret《0)
returnret;
return0;
}
中斷返回函數(shù):讀取xyz軸數(shù)值,并上報(bào)給input子系統(tǒng)
staticirqreturn_tmpu3050_interrupt_thread(intirq,void*data)
{
structmpu3050_sensor*sensor=data;//獲取mpu3050傳感器
structaxis_dataaxis;
mpu3050_read_xyz(sensor-》client,&axis);//獲取xyz軸數(shù)值
input_report_abs(sensor-》idev,ABS_X,axis.x);//上報(bào)x軸事件
input_report_abs(sensor-》idev,ABS_Y,axis.y);//上報(bào)y軸事件
input_report_abs(sensor-》idev,ABS_Z,axis.z);//上報(bào)z軸事件
input_sync(sensor-》idev);//同步事件
returnIRQ_HANDLED;
}
獲取xyz軸數(shù)值,通過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);
}
應(yīng)用層在MPU3050設(shè)備節(jié)點(diǎn)的時(shí)候會開啟中斷,MPU3050有數(shù)據(jù)更新則會觸發(fā)中斷,接著調(diào)用中斷返回函數(shù)上報(bào)事件,應(yīng)用程序便可讀取設(shè)備節(jié)點(diǎn)獲取xyz軸的數(shù)據(jù)
staticintmpu3050_input_open(structinput_dev*input)
{
structmpu3050_sensor*sensor=input_get_drvdata(input);//獲取mpu3050傳感器
interror;
pm_runtime_get(sensor-》dev);
/*Enableinterrupts
使能中斷,設(shè)置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;
}
評論