linux下mpu6050驱动
环境介绍
- imx6ull
- mpu6050模块(i2c接口)
- ubuntu 18.04
大致流程
- 接线,对照原理图,找到i2c的资源,这里我们用的i2c2的接口
- 修改设备树,在对应i2c2控制器下增加节点
- 增加驱动文件,对读写的实现
接线
略
修改设备树
- 在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
- init入口
- exit出口
- read具体函数
- name,cnt之类
- 以上不再赘述,比较简单