zoukankan      html  css  js  c++  java
  • MPU6050带字符驱动的i2c从设备驱动1

    开干:
    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... ");

    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 ",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... ");

    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 ",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 ", mpu6xxx->gyro.x.value);
    if(copy_to_user(argp,&mpu6xxx->gyro,sizeof(struct sub_sensor))) //将数据拷贝到用户空间
    {
    printk("failed copy data .. ");
    mutex_unlock(&mpu6xxx->lock);
    return -EFAULT;
    }
    printk("ioctl succed... ");
    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 .. ");
    return -EFAULT;
    }

    mutex_unlock(&(mpu6xxx->lock) );

    break;
    default: break;
    }

    return 0;
    }

    驱动加载结果:



    应用层代码结果:



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

  • 相关阅读:
    泛型简介
    单元测试(junit使用)
    枚举简介
    面试题:二叉树的镜像
    面试题:和为S的连续正数列
    面试题:丑数
    面试题:合并两个排序的链表
    面试题:数值的整数次方
    面试题:矩形覆盖
    面试题:数组中的逆序对
  • 原文地址:https://www.cnblogs.com/zym0805/p/7483867.html
Copyright © 2011-2022 走看看