一步一步教你构建一个MPU6050(I2C类)驱动(三)

首先我们要控制MPU6050,实质上就是读写它里面寄存器的值。i2c的数据通信帧的组成在前面已经讲过了这里就不在展开,我们先来看看内核中已经帮我们封装好的,构建一个数据帧的API:

/**
 * i2c_master_send - issue a single I2C message in master transmit mode
 * @client: Handle to slave device
 * @buf: Data that will be written to the slave
 * @count: How many bytes to write, must be less than 64k since msg.len is u16
 *
 * Returns negative errno, or else the number of bytes written.
 */
int i2c_master_send(const struct i2c_client *client, const char *buf, int count)
{
	int ret;
	struct i2c_adapter *adap = client->adapter;
	struct i2c_msg msg;

	msg.addr = client->addr;
	msg.flags = client->flags & I2C_M_TEN;
	msg.len = count;
	msg.buf = (char *)buf;

	ret = i2c_transfer(adap, &msg, 1);

	/*
	 * If everything went ok (i.e. 1 msg transmitted), return #bytes
	 * transmitted, else error code.
	 */
	return (ret == 1) ? count : ret;
}


/**
 * i2c_master_recv - issue a single I2C message in master receive mode
 * @client: Handle to slave device
 * @buf: Where to store data read from slave
 * @count: How many bytes to read, must be less than 64k since msg.len is u16
 *
 * Returns negative errno, or else the number of bytes read.
 */
int i2c_master_recv(const struct i2c_client *client, char *buf, int count)
{
	struct i2c_adapter *adap = client->adapter;
	struct i2c_msg msg;
	int ret;

	msg.addr = client->addr;
	msg.flags = client->flags & I2C_M_TEN;
	msg.flags |= I2C_M_RD;
	msg.len = count;
	msg.buf = buf;

	ret = i2c_transfer(adap, &msg, 1);

	/*
	 * If everything went ok (i.e. 1 msg received), return #bytes received,
	 * else error code.
	 */
	return (ret == 1) ? count : ret;
}

一个是发送数据的 i2c_master_send ,一个是接受数据的 i2c_master_recv 。

以 i2c_master_send 为例子我们来分析一下这个函数是怎么实现的。

该函数的形参分别是什么在函数前面的注释就已经有了,我们来看看它的函数体,前面的

    int ret;
	struct i2c_adapter *adap = client->adapter;
	struct i2c_msg msg;

	msg.addr = client->addr;
	msg.flags = client->flags & I2C_M_TEN;
	msg.len = count;
	msg.buf = (char *)buf;

这部分的内容就是将形参导入的数据填充到 i2c_msg 这个结构体中,那我们又来展开看看这个结构体是干什么用的:

/**
 * struct i2c_msg - an I2C transaction segment beginning with START
 *
 * @addr: Slave address, either seven or ten bits.  When this is a ten
 *	bit address, I2C_M_TEN must be set in @flags and the adapter
 *	must support I2C_FUNC_10BIT_ADDR.
 * @flags: I2C_M_RD is handled by all adapters.  No other flags may be
 *	provided unless the adapter exported the relevant I2C_FUNC_*
 *	flags through i2c_check_functionality().
 * @len: Number of data bytes in @buf being read from or written to the
 *	I2C slave address.  For read transactions where I2C_M_RECV_LEN
 *	is set, the caller guarantees that this buffer can hold up to
 *	32 bytes in addition to the initial length byte sent by the
 *	slave (plus, if used, the SMBus PEC); and this value will be
 *	incremented by the number of block data bytes received.
 * @buf: The buffer into which data is read, or from which it's written.
。。。。
*/
struct i2c_msg {
	__u16 addr;	/* slave address			*/
	__u16 flags;
#define I2C_M_TEN		0x0010	/* this is a ten bit chip address */
#define I2C_M_RD		0x0001	/* read data, from slave to master */
#define I2C_M_STOP		0x8000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_NOSTART */
#define I2C_M_REV_DIR_ADDR	0x2000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */
	__u16 len;		/* msg length				*/
	__u8 *buf;		/* pointer to msg data			*/
};

由注释这里就得知到了,这个结构体其实就是我们说的i2c的数据帧,i2c的通信其实就是在传输这个 i2c_msg 结构体。

那我们继续回到 i2c_master_send 中,该函数接下来调用了 i2c_transfer 这个函数,展开:

/**
 * i2c_transfer - execute a single or combined I2C message
 * @adap: Handle to I2C bus
 * @msgs: One or more messages to execute before STOP is issued to
 *	terminate the operation; each message begins with a START.
 * @num: Number of messages to be executed.
 *
 * Returns negative errno, else the number of messages executed.
 *
 * Note that there is no requirement that each message be sent to
 * the same slave address, although that is the most common model.
 */
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
	int ret;

	if (adap->algo->master_xfer) {
#ifdef DEBUG
		for (ret = 0; ret < num; ret++) {
			dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
				"len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
				? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
				(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
		}
#endif

		if (in_atomic() || irqs_disabled()) {
			ret = i2c_trylock_adapter(adap);
			if (!ret)
				/* I2C activity is ongoing. */
				return -EAGAIN;
		} else {
			i2c_lock_adapter(adap);
		}

		ret = __i2c_transfer(adap, msgs, num);
		i2c_unlock_adapter(adap);

		return ret;
	} else {
		dev_dbg(&adap->dev, "I2C level transfers not supported\n");
		return -EOPNOTSUPP;
	}
}

注释上写着 execute a single or combined I2C message ,其实就是实现了将上面封装好的 i2c_msg 发送到设备。(而i2c_master_recv 则是从设备接受 i2c_msg最后就实现了i2c_master_send这个函数的 issue a single I2C message in master transmit mode 功能。

接着回到我们的MPU6050上来,先看看这个部件里常用的一些寄存器:

#define SMPLRT_DIV      0x19 //采样频率寄存器-25 典型值:0x07(125Hz)
                                    //寄存器集合里的数据根据采样频率更新
#define CONFIG          0x1A    //配置寄存器-26-典型值:0x06(5Hz)
                                        //DLPF is disabled(DLPF_CFG=0 or 7)
#define GYRO_CONFIG     0x1B//陀螺仪配置-27,可以配置自检和满量程范围
                                    //典型值:0x18(不自检,2000deg/s)
#define ACCEL_CONFIG        0x1C    //加速度配置-28 可以配置自检和满量程范围及高通滤波频率
                                        //典型值:0x01(不自检,2G,5Hz)
#define ACCEL_XOUT_H    0x3B //59-65,加速度计测量值 XOUT_H
#define ACCEL_XOUT_L    0x3C  // XOUT_L
#define ACCEL_YOUT_H    0x3D  //YOUT_H
#define ACCEL_YOUT_L    0x3E  //YOUT_L
#define ACCEL_ZOUT_H    0x3F  //ZOUT_H
#define ACCEL_ZOUT_L    0x40 //ZOUT_L---64
#define TEMP_OUT_H      0x41 //温度测量值--65
#define TEMP_OUT_L      0x42
#define GYRO_XOUT_H     0x43 //陀螺仪值--67,采样频率(由寄存器 25 定义)写入到这些寄存器
#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 //陀螺仪值--72
#define PWR_MGMT_1      0x6B //电源管理 典型值:0x00(正常启用)

而要对其中的寄存器进行写,我们要在一个数据帧的data区中先写入一个寄存器(地址),在写入要写入寄存器的值。一步一步教你构建一个MPU6050(I2C类)驱动(三)_第1张图片

而读一个寄存器就要在一个数据帧中先读出(识别)这个寄存器,再读出相应的值。为了能更方便的读写寄存器,我们来对i2c_master_send 来做一个封装:

static int mpu6050_write_reg(struct i2c_client * client, char reg, char value)
{
	char buf[2];
	buf[0] = reg;
	buf[1] = value;
	return i2c_master_send(client, buf, 2);
	 
}

同理,写一个接受的函数

static int mpu6050_read_reg(const struct i2c_client * client, char reg)
{
	// 先写寄存器的地址, 然后在读寄存器的值

	int ret;
	struct i2c_adapter *adapter = client->adapter;
	struct i2c_msg msg[2];

	char rxbuf[1];

	msg[0].addr = client->addr;
	msg[0].flags = 0;
	msg[0].len = 1;
	msg[0].buf = ®

	msg[1].addr = client->addr;
	msg[1].flags = I2C_M_RD;
	msg[1].len = 1;
	msg[1].buf = rxbuf;
	
	ret = i2c_transfer(adapter, msg,  2);
	if(ret < 0)
	{
		printk("i2c_transfer read error\n");
		return ret;
	}

	return rxbuf[0];

}

 

做好了读写的函数后,我们先来对MPU6050做初始化。而这个初始化就是设定MPU6050中寄存器的值,使其达到能开始正常使用的状态。

static int mpu6050_init( struct i2c_client * client)
{
	//success --0    erro--1
	int ret;
	ret = mpu6050_write_reg(client,  PWR_MGMT_1 , 0x00 );
	if(ret == -1)
	 {
	 	printk("--%s--error",__FUNCTION__);
		return -1;
	 }
	ret = mpu6050_write_reg(client,  SMPLRT_DIV ,   0x07 );
	if(ret == -1)
	 {
	 	printk("--%s--error",__FUNCTION__);
		return -1;
	 }
	ret = mpu6050_write_reg(client,  CONFIG , 0x06 );
	if(ret == -1)
	 {
	 	printk("--%s--error",__FUNCTION__);
		return -1;
	 }
	ret = mpu6050_write_reg(client,  GYRO_CONFIG , 0x18 );
	if(ret == -1)
	 {
	 	printk("--%s--error",__FUNCTION__);
		return -1;
	 }
	ret = mpu6050_write_reg(client,  ACCEL_CONFIG , 0x01 );
	if(ret == -1)
	 {
	 	printk("--%s--error",__FUNCTION__);
		return -1;
	 }

	return 0;

}

现在,我们的驱动代码如下:

#include
#include
#include
#include
#include 
#include 	/* for struct device */
#include 	/* for completion */
#include 
#include 		/* for struct device_node */
#include 		/* for swab16 */
#include 

/*
	做一个i2c 的驱动
*/


//MPU6050寄存器
#define SMPLRT_DIV      0x19 //采样频率寄存器-25 典型值:0x07(125Hz)
                                    //寄存器集合里的数据根据采样频率更新
#define CONFIG          0x1A    //配置寄存器-26-典型值:0x06(5Hz)
                                        //DLPF is disabled(DLPF_CFG=0 or 7)
#define GYRO_CONFIG     0x1B//陀螺仪配置-27,可以配置自检和满量程范围
                                    //典型值:0x18(不自检,2000deg/s)
#define ACCEL_CONFIG        0x1C    //加速度配置-28 
									//可以配置自检和满量程范围及高通滤波频率
                                        //典型值:0x01(不自检,2G,5Hz)
#define ACCEL_XOUT_H    0x3B //59-65,加速度计测量值 XOUT_H
#define ACCEL_XOUT_L    0x3C  // XOUT_L
#define ACCEL_YOUT_H    0x3D  //YOUT_H
#define ACCEL_YOUT_L    0x3E  //YOUT_L
#define ACCEL_ZOUT_H    0x3F  //ZOUT_H
#define ACCEL_ZOUT_L    0x40 //ZOUT_L---64
#define TEMP_OUT_H      0x41 //温度测量值--65
#define TEMP_OUT_L      0x42
#define GYRO_XOUT_H     0x43 //陀螺仪值--67,采样频率(由寄存器 25定义)写入到这些寄存器
#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 //陀螺仪值--72
#define PWR_MGMT_1      0x6B //电源管理 典型值:0x00(正常启用



static int mpu6050_write_reg(struct i2c_client * client, char reg, char value)
{
	char buf[2];
	buf[0] = reg;
	buf[1] = value;
	return i2c_master_send(client, buf, 2);
	 
}

static int mpu6050_read_reg(const struct i2c_client * client, char reg)
{
	// 先写寄存器的地址, 然后在读寄存器的值

	int ret;
	struct i2c_adapter *adapter = client->adapter;
	struct i2c_msg msg[2];

	char rxbuf[1];

	msg[0].addr = client->addr;
	msg[0].flags = 0;
	msg[0].len = 1;
	msg[0].buf = ®

	msg[1].addr = client->addr;
	msg[1].flags = I2C_M_RD;
	msg[1].len = 1;
	msg[1].buf = rxbuf;
	
	ret = i2c_transfer(adapter, msg,  2);
	if(ret < 0)
	{
		printk("i2c_transfer read error\n");
		return ret;
	}

	return rxbuf[0];

}

static int mpu6050_init( struct i2c_client * client)
{
	printk("-----------%s-----------\n", __FUNCTION__);

	//success --0    erro--1
	int ret;
	ret = mpu6050_write_reg(client,  PWR_MGMT_1 , 0x00 );
	if(ret == -1)
	 {
	 	printk("--%s--error",__FUNCTION__);
		return -1;
	 }
	ret = mpu6050_write_reg(client,  SMPLRT_DIV ,   0x07 );
	if(ret == -1)
	 {
	 	printk("--%s--error",__FUNCTION__);
		return -1;
	 }
	ret = mpu6050_write_reg(client,  CONFIG , 0x06 );
	if(ret == -1)
	 {
	 	printk("--%s--error",__FUNCTION__);
		return -1;
	 }
	ret = mpu6050_write_reg(client,  GYRO_CONFIG , 0x18 );
	if(ret == -1)
	 {
	 	printk("--%s--error",__FUNCTION__);
		return -1;
	 }
	ret = mpu6050_write_reg(client,  ACCEL_CONFIG , 0x01 );
	if(ret == -1)
	 {
	 	printk("--%s--error",__FUNCTION__);
		return -1;
	 }

	return 0;

}


static const struct of_device_id mpu6050_of_match[] = {
	{ .compatible = "InvenSense,mpu6050" },
	{},
};

const struct i2c_device_id mpu6050_id_table[] = {
	{ "mpu6050", 0 },
	{},
};



static int mpu6050_probe(struct i2c_client *client,
				   const struct i2c_device_id *id)
{
	printk("-----------%s-----------\n", __FUNCTION__);

	if( mpu6050_init(client) != -1)
			printk("mpu6050 init success!\n");
	
		else{
			printk("mpu6050 init errer");
		}

	return 0;
}

int mpu6050_remove(struct i2c_client *client)
{
	printk("-----------%s-----------\n", __FUNCTION__);

	return 0;
}

struct i2c_driver mpu6050_drv = 
{
	.probe = mpu6050_probe,
	.remove = mpu6050_remove,
	.driver= {
		.name = "mpu6050_drv",//sys/bus/i2c/driver
		.of_match_table = of_match_ptr(mpu6050_of_match),
	},
	.id_table = mpu6050_id_table,
};



static int __init i2cdrv_init(void)
{
	printk("-----------%s-----------\n", __FUNCTION__);
	
	
	return i2c_register_driver(THIS_MODULE, &mpu6050_drv);
}


static void __exit i2cdrv_exit(void)
{
	printk("-----------%s-----------\n", __FUNCTION__);

	i2c_del_driver(&mpu6050_drv);
	
}

module_init(i2cdrv_init);
module_exit(i2cdrv_exit);
MODULE_LICENSE("GPL");

 

你可能感兴趣的:(嵌入式驱动开发)