一周搞定MPU6050Linux驱动(3)

第4-5日

 

参考:

anroid gsensor lis3dh驱动

《Linux设备驱动程序》

《一周搞定MPU6050linux驱动(1,2)》

 

开干:

1、闲言碎语

这个驱动,越写觉的越简单,入门难,入门之后感觉还好。Linux开发还是比较友好的。

 

2、编写MPU6050带字符驱动的i2c从设备驱动

要实现的功能就是,将MPU6050作为字符驱动,在应用层,对其进行读数据。实现简单的功能。在前面的分析和实践中,可以看到实现字符驱动主要是实现file_operation中的方法,注册初始化cdev,让cdev和file_opration产生联系,字符驱动的初始化通过module_init来声明。实现i2c从设备驱动,主要是i2c_client和i2c_driver通过名字匹配,然后调用probe函数对设备进行初始化。那么,实现字符驱动的i2c从设备驱动,其实就是在i2c从设备驱动中添加字符驱动操作方法,从而在/dev中产生设备节点,让用户可以通过Linux application的API对其进行操作。

本文实现了带字符驱动的i2c从设备驱动,然后编写了用户层测试程序,测试结果正确。下面对部分代码进行分析。

 

定义i2c_driver,file_operations,

static struct i2c_driver mpu6xxx_driver = {

.driver = {

.name = "mpu6xxx",

.owner = THIS_MODULE,

},

.class = I2C_CLASS_HWMON,

.id_table = mpu6xxx_ids,

.probe = mpu6xxx_probe,

.remove = mpu6xxx_remove,

};

主要实现其中的probe函数。

struct file_operations mpu6xxx_fops = {

owner : THIS_MODULE,

unlocked_ioctl : mpu6xxx_ioctl,

open : mpu6xxx_open,

release : mpu6xxx_release,

 

};

主要实现其中的ioctl函数。

 

probe函数实现:

static int mpu6xxx_probe(struct i2c_client *client, const struct i2c_device_id *id){

 

u16 version;

int result,retval = -1;

struct mpu6xxx_data *mpu6xxx;

dev_t dev;

 

printk(KERN_DEBUG "mpu6xxx driver probe... \n");

 

if(!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)){

retval = -EINVAL;

goto failed;

} //核查i2c驱动

 

mpu6xxx = kzalloc(sizeof(struct mpu6xxx_data),GFP_KERNEL);

//分配用户数据

if(!mpu6xxx)

{

retval = -ENOMEM;

goto failed;

}

 

memset(&mpu6xxx->gyro,0,sizeof(struct sub_sensor));

memset(&mpu6xxx->accel,0,sizeof(struct sub_sensor));

mutex_init(&mpu6xxx->lock);

 

mpu6xxx->client = client;

i2c_set_clientdata(client,mpu6xxx); //用来在驱动中获取数据

this_client = client;

 

version = i2c_smbus_read_byte_data(client,MPU6050_REG_WHO_AM_I);

if(version != 0x70)

{

printk("error retval %d , version %.2x \n",retval , version);

retval = -2;

goto failed;

}

//检查version

 

result = alloc_chrdev_region(&dev,this_major,1,"mpu6xxx");

if(result < 0)

{

retval = result;

goto failed;

}

 

this_major = MAJOR(dev);

cdev_init(&mpu6xxx->cdev,&mpu6xxx_fops);

mpu6xxx->cdev.owner = THIS_MODULE;

 

result = cdev_add(&mpu6xxx->cdev,dev,1);

if(result)

{

retval = result;

goto failed;

}

 

mpu_cls = class_create(THIS_MODULE,"mpu6xxx");

if(IS_ERR(mpu_cls))

{

retval = -3;

goto failed;

}

 

mpu_device = device_create(mpu_cls,NULL,dev,NULL,"mpu6xxx");

if(IS_ERR(mpu_device))

{

class_destroy(mpu_cls);

}

//注册cdev,以及在/dev中产生节点

 

mpu6xxx_reset(mpu6xxx);

mpu6xxx_disable(mpu6xxx);

 

retval = 0;

 

printk(KERN_DEBUG "mpuxxx probe succeed...\n");

 

return retval;

 

failed:

 

return retval;

};

 

 

ioctl实现:

 

static int mpu6xxx_ioctl(struct file *file, unsigned int cmd,unsigned long arg)

{

int re = -1;

void __user *argp = (void __user *)arg;

struct mpu6xxx_data *mpu6xxx = i2c_get_clientdata(this_client);

 

printk("ioctl ... cmd %d mpucmd %d BUFFERSIZE %d\n",cmd,MPU_IOCTL_GETGYRO,BUFFERSIZE);

 

switch(cmd)

{

case MPU_IOCTL_GETGYRO:

// ioctl这个cmd码,可以参考博客http://blog.csdn.net/shanshanpt/article/details/19897897

mutex_lock(&(mpu6xxx->lock) ); //通过互斥操作来避免频繁读写

 

re = mpu6xxx_read_data(mpu6xxx,0);

if(re != 0) return re;

printk("x : %d \n", mpu6xxx->gyro.x.value);

if(copy_to_user(argp,&mpu6xxx->gyro,sizeof(struct sub_sensor))) //将数据拷贝到用户空间

{

printk("failed copy data .. \n");

mutex_unlock(&mpu6xxx->lock);

return -EFAULT;

}

printk("ioctl succed...\n");

mutex_unlock(&mpu6xxx->lock);

break ;

case MPU_IOCTL_GETACCEL:

mutex_lock(&(mpu6xxx->lock) );

 

re = mpu6xxx_read_data(mpu6xxx,1);

if(re != 0) return re;

if(copy_to_user(argp,&mpu6xxx->accel,sizeof(struct sub_sensor)))

{

mutex_unlock(&(mpu6xxx->lock) );

printk("failed copy data .. \n");

return -EFAULT;

}

 

mutex_unlock(&(mpu6xxx->lock) );

 

break;

default: break;

}

 

return 0;

}

 

驱动加载结果:

 

 

应用层代码结果:

 

 

在动6050时,数据会变动。并且数据大小正常。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值