Devin's Blog

Diversity is essential to happiness

0%

i2c_mpu6050

mpu6050芯片 linux 驱动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#ifndef MPU6050_HHHH
#define MPU6050_HHHH

#define MPU6050_MAGIC 'K'

#define SMPLRT_DIV 0x19
#define CONFIG 0x1A
#define GYRO_CONFIG 0x1B
#define ACCEL_CONFIG 0x1C
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48
#define PWR_MGMT_1 0x6B

union mpu6050_data
{
struct {
unsigned short x;
unsigned short y;
unsigned short z;
}accel;
struct {
unsigned short x;
unsigned short y;
unsigned short z;
}gyro;
unsigned short temp;
};

#define GET_ACCEL _IOR(MPU6050_MAGIC, 0, union mpu6050_data)
#define GET_GYRO _IOR(MPU6050_MAGIC, 1, union mpu6050_data)
#define GET_TEMP _IOR(MPU6050_MAGIC, 2, union mpu6050_data)

#endif

i2c_driver.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#include <linux/module.h>  //linux 3.14/include/linux
#include <linux/kernel.h> //define of printk
#include <linux/init.h> //module_init module_exit
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include "mpu6050.h"
#include <linux/i2c.h>

dev_t devno;
unsigned int major;
struct class *pcls;
struct device *pdevice;

static struct mpu6050_device{
struct i2c_client *client;
};
struct mpu6050_device *mpu6050;


//这个函数为什么这样设计 函数的参数
static int mpu6050_read_byte(struct i2c_client *client,unsigned char reg)
{
char txbuf[1] = {reg};
char rxbuf[1];
struct i2c_msg msg[2] = {
{client->addr,0,1,txbuf},
{client->addr,1,1,rxbuf},
//读出来的数据放在rxbuf
};
i2c_transfer(client->adapter,msg,ARRAY_SIZE(msg));
return rxbuf[0];
}
static int mpu6050_write_byte(struct i2c_client *client,unsigned char reg,unsigned char val )
{
char txbuf[2] = {reg,val};

struct i2c_msg msg[1] = {
{client->addr,0,2,txbuf},
//mpu6050地址 写标志位 字节数 写的内容
};
i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
//adapter
return 0;
}

static int mpu6050_init(struct i2c_client *client)
{

mpu6050_write_byte(client,PWR_MGMT_1,0x0);
mpu6050_write_byte(client,SMPLRT_DIV,0x07);
mpu6050_write_byte(client,CONFIG,0x06);
mpu6050_write_byte(client,GYRO_CONFIG,0xf8);
mpu6050_write_byte(client,ACCEL_CONFIG,0x19);
printk("mpu6050 init success \n");
return 0;
}

int mpu6050_open(struct inode *inode, struct file *file)
{
return 0;
}

void mpu6050_release(struct inode *inode, struct file *file)
{

}

long mpu6050_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
union mpu6050_data data;
struct i2c_client *client = mpu6050->client;

switch(cmd)
{
case GET_ACCEL:
data.accel.x =
mpu6050_read_byte(client,ACCEL_XOUT_L);
data.accel.x |=
mpu6050_read_byte(client,ACCEL_XOUT_H) << 8;

data.accel.y =
mpu6050_read_byte(client,ACCEL_YOUT_L);
data.accel.y |=
mpu6050_read_byte(client,ACCEL_YOUT_H) << 8;

data.accel.z =
mpu6050_read_byte(client,ACCEL_ZOUT_L);
data.accel.z |=
mpu6050_read_byte(client,ACCEL_ZOUT_H)<< 8;
break;
case GET_GYRO:
data.gyro.x =
mpu6050_read_byte(client,GYRO_XOUT_L);
data.gyro.x |=
mpu6050_read_byte(client,GYRO_XOUT_H)<<8;

data.gyro.y =
mpu6050_read_byte(client,GYRO_ZOUT_L);
data.gyro.y |=
mpu6050_read_byte(client,GYRO_ZOUT_H) << 8;
break;
default:
printk("invaild argument\n");
}
copy_to_user((void*)arg,&data,sizeof(data));
return sizeof(data);
}

static struct file_operations fops = {
.owner = THIS_MODULE,
.open = mpu6050_open,
.release = mpu6050_release,
.unlocked_ioctl = mpu6050_ioctl,
};

static int mpu6050_probe(struct i2c_client * client, const struct device * id)
{
printk("mpu6050_probe\n");

mpu6050 = kzalloc(sizeof(*mpu6050),GFP_KERNEL);
mpu6050->client = client;
major = register_chrdev(major,"mpu6050",&fops);
devno = MKDEV(major,0);
printk("create the devno success\n");

pcls = class_create(THIS_MODULE,"mpu6050-auto");
pdevice = device_create(pcls,NULL,devno,NULL,"mpu6050");
printk("create the device node\n");

//hardware init
mpu6050_init(client);
printk("mpu6050_probe\n");
return 0;
}

static int mpu6050_remove(struct i2c_client * client)
{

printk("mpu6050 remove \n");

unregister_chrdev(major,"mpu6050");
device_destroy(pcls,devno);

class_destroy(pcls);
return 0;
}

int mpu6050_suspend(struct i2c_client *client,pm_message_t state)
{
printk("fs4412_i2c_suspened\n");
return 0;
}

int mpu6050_resume(struct i2c_client *client)
{
printk("fs4412_i2c_resume\n");

return 0;
}

//一个是id_table 一个是.driver.of_match_table 都有什么用
static const struct i2c_device_id mpu6050_id[] =
{

{"mpu6050",0},
};

static struct of_device_id mpu6050_dt_match[] =
{
{.compatible = "invense,mpu6050"},

}; //这里为什么需要结构体数组 只有一个设备啊
//结构体数组可以填多组

struct i2c_driver mpu6050_driver = {
.probe = mpu6050_probe,
.remove = mpu6050_remove,
.suspend = mpu6050_suspend,
.resume = mpu6050_resume,
.id_table = mpu6050_id,
.driver = {
.name = "mpu6050",
.owner = THIS_MODULE,
.of_match_table = mpu6050_dt_match,
},
};


static int __init fs4412_i2c_driver_init(void)
{
printk("fs4412_i2c_driver_init\n");

//register
i2c_add_driver(&mpu6050_driver);

return 0;
}

static void __exit fs4412_i2c_driver_exit(void)
{
printk("fs4412_i2c_driver_exit\n");

//unregister
i2c_del_driver(&mpu6050_driver);

}

MODULE_LICENSE("GPL");//许可声明 开源许可
module_init(fs4412_i2c_driver_init);//声明入口
module_exit(fs4412_i2c_driver_exit);//声明出口

test_mpu6050

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include "stdio.h"
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#include "mpu6050.h"
int main()
{
int fd;
union mpu6050_data data;

fd = open("/dev/mpu6050",O_RDWR);
if(fd<0)
{
perror("open");
exit(1);
}
while(1)
{
ioctl(fd,GET_ACCEL,&data);
printf("acceleration data : x = %04x,y =%04x,z =%04x\n",data.accel.x,data.accel.y,data.accel.z);

ioctl(fd,GET_GYRO,&data);
printf("gyroscope data: x = %04x,y =%04x,z =%04x\n",data.gyro.x,data.gyro.y,data.gyro.z);
sleep(2);
}
close(fd);
return 0;
}