linux下mpu6050驱动 i2c

linux下mpu6050驱动

    • 环境介绍
    • 大致流程
    • 接线
    • 修改设备树
    • 增加驱动文件
      • dev struct
      • open
      • release
      • read
      • ops
      • match
      • probe
      • remove
      • i2c driver
      • misc
    • 完整代码示例

环境介绍

  1. imx6ull
  2. mpu6050模块(i2c接口)
  3. ubuntu 18.04

大致流程

  1. 接线,对照原理图,找到i2c的资源,这里我们用的i2c2的接口
  2. 修改设备树,在对应i2c2控制器下增加节点
  3. 增加驱动文件,对读写的实现

接线

修改设备树

  • 在i2c控制器下追加节点
&i2c2 {
	clock_frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c2>;
	status = "okay";
	mpu6050:mpu6050@68 {
	    compatible = "dar,mpu6050";
	    reg = <0x68>;
	    status = "okay";
	};
};

增加驱动文件

  • 使用i2c总线框架,按照标准流程

dev struct

struct mpu6050_dev {
	dev_t devid;				/* 设备号 	 */
	struct cdev cdev;			/* cdev 	*/
	struct class *class;		/* 类 		*/
	struct device *device;		/* 设备 	 */
	struct device_node	*nd; 	/* 设备节点 */
	int major;					/* 主设备号 */
	void *private_data;			/* 私有数据 		*/
	signed int gyro_x_adc;		/* 陀螺仪X轴原始值 	 */
	signed int gyro_y_adc;		/* 陀螺仪Y轴原始值		*/
	signed int gyro_z_adc;		/* 陀螺仪Z轴原始值 		*/
	signed int accel_x_adc;		/* 加速度计X轴原始值 	*/
	signed int accel_y_adc;		/* 加速度计Y轴原始值	*/
	signed int accel_z_adc;		/* 加速度计Z轴原始值 	*/
	signed int temp_adc;		/* 温度原始值 			*/
};

open

static int mpu6050_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &mpu6050dev; /* 设置私有数据 */
	return 0;
}

release

static int mpu6050_release(struct inode *inode, struct file *filp)
{
	return 0;
}

read

static ssize_t mpu6050_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{
	signed int data[7];
	long err = 0;
	struct mpu6050_dev *dev = (struct mpu6050_dev *)filp->private_data;
	mpu6050_readdata(dev);
	data[0] = dev->gyro_x_adc;
	data[1] = dev->gyro_y_adc;
	data[2] = dev->gyro_z_adc;
	data[3] = dev->accel_x_adc;
	data[4] = dev->accel_y_adc;
	data[5] = dev->accel_z_adc;
	data[6] = dev->temp_adc;
	err = copy_to_user(buf, data, sizeof(data));
	return 0;
}

ops

static const struct file_operations mpu6050_ops = {
	.owner = THIS_MODULE,
	.open = mpu6050_open,
	.read = mpu6050_read,
	.release = mpu6050_release,
};

match

static const struct of_device_id mpu6050_of_match[] = {
	{ .compatible = "xxx,mpu6050" },
	{ /* Sentinel */ }
};

probe

static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	int ret = 0;
	if (mpu6050dev.major) {
		mpu6050dev.devid = MKDEV(mpu6050dev.major, 0);
		register_chrdev_region(mpu6050dev.devid, MPU6050_CNT, MPU6050_NAME);
	} else {
		alloc_chrdev_region(&mpu6050dev.devid, 0, MPU6050_CNT, MPU6050_NAME);
		mpu6050dev.major = MAJOR(mpu6050dev.devid);
	}
	cdev_init(&mpu6050dev.cdev, &mpu6050_ops);
	cdev_add(&mpu6050dev.cdev, mpu6050dev.devid, MPU6050_CNT);
	mpu6050dev.class = class_create(THIS_MODULE, MPU6050_NAME);
	if (IS_ERR(mpu6050dev.class)) {
		return PTR_ERR(mpu6050dev.class);
	}
	mpu6050dev.device = device_create(mpu6050dev.class, NULL, mpu6050dev.devid, NULL, MPU6050_NAME);
	if (IS_ERR(mpu6050dev.device)) {
		return PTR_ERR(mpu6050dev.device);
	}
	mpu6050dev.private_data = client;
	mpu6050_reginit();		
	return 0;
}

remove

static int mpu6050_remove(struct i2c_client *client)
{
	cdev_del(&mpu6050dev.cdev);
	unregister_chrdev_region(mpu6050dev.devid, MPU6050_CNT);
	device_destroy(mpu6050dev.class, mpu6050dev.devid);
	class_destroy(mpu6050dev.class);
	return 0;
}

i2c driver

static struct i2c_driver mpu6050_driver = {
	.probe = mpu6050_probe,
	.remove = mpu6050_remove,
	.driver = {
			.owner = THIS_MODULE,
		   	.name = "mpu6050",
		   	.of_match_table = mpu6050_of_match, 
		   },
	.id_table = mpu6050_id,
};

misc

  1. init入口
  2. exit出口
  3. read具体函数
  4. name,cnt之类
  5. 以上不再赘述,比较简单

完整代码示例

仓库地址

你可能感兴趣的:(linux,传感器,c,linux)