1. 程式人生 > >x4412 i2c裝置驅動開發例項(mpu6050)

x4412 i2c裝置驅動開發例項(mpu6050)

        MPU6050 包括陀螺儀和加速度感測器功能,陀螺儀和加速度感測器分別用三個 16bit 的資料表示,量程和精度都是可程式設計的,可按需求設定,具體 MPU6050 引數參照晶片手冊。Exynos4412 共有八組 I2C 控制器,我們使用x4412引出的i2c6連線MPU6050,如下圖所示。

首先需要修改裝置樹,新增I2C6節點,如下

[email protected] {
		samsung,i2c-sda-delay = <100>;
		samsung,i2c-max-bus-freq = <20000>;
		pinctrl-0 = <&i2c6_bus>;
		pinctrl-names = "default";
		status = "okay";

		
[email protected]
{ compatible = "invensense,mpu6050"; reg = <0x68>; interrupt-parent = <&gpx3>; interrupts = <3 2>; }; };

接下來開發對應的驅動程式,配置初始化mpu6050。配置程式碼如下

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

#include <linux/fs.h>
#include <linux/cdev.h>

#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/delay.h>

#include "mpu6050.h"

#define FSRTC_MAJOR	256
#define FSRTC_MINOR	9
#define FSRTC_DEV_NAME	"mpu6050"

#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

struct mpu6050_dev {
	struct i2c_client *client;
	atomic_t available;
	struct cdev cdev;
	struct device *device;
};
static struct class *mpu6050_cls;

static int mpu6050_open(struct inode *inode, struct file *filp)
{
	struct mpu6050_dev *mpu6050 = container_of(inode->i_cdev, struct mpu6050_dev, cdev);

	filp->private_data = mpu6050;
	if (atomic_dec_and_test(&mpu6050->available))//dec1 and check is it zero,if it is zero,return true
		return 0;
	else {
		atomic_inc(&mpu6050->available);//inc ,
		return -EBUSY;
	}
}

static int mpu6050_release(struct inode *inode, struct file *filp)
{
	struct mpu6050_dev *mpu6050 = filp->private_data;

	atomic_inc(&mpu6050->available);
	return 0;
}

static long mpu6050_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
	struct mpu6050_dev *mpu6050 = filp->private_data;
	struct atg_val val;

	if (_IOC_TYPE(cmd) != MPU6050_MAGIC)
		return -ENOTTY;

	switch (cmd) {
	case MPU6050_GET_VAL:
		val.accelx = i2c_smbus_read_word_data(mpu6050->client, ACCEL_XOUT_H);//read
		val.accely = i2c_smbus_read_word_data(mpu6050->client, ACCEL_YOUT_H);
		val.accelz = i2c_smbus_read_word_data(mpu6050->client, ACCEL_ZOUT_H);
		val.temp   = i2c_smbus_read_word_data(mpu6050->client, TEMP_OUT_H);
		val.gyrox  = i2c_smbus_read_word_data(mpu6050->client, GYRO_XOUT_H);
		val.gyroy  = i2c_smbus_read_word_data(mpu6050->client, GYRO_YOUT_H);
		val.gyroz  = i2c_smbus_read_word_data(mpu6050->client, GYRO_ZOUT_H);
		val.accelx = be16_to_cpu(val.accelx);//轉換成大段格式
		val.accely = be16_to_cpu(val.accely);
		val.accelz = be16_to_cpu(val.accelz);
		val.temp   = be16_to_cpu(val.temp);
		val.gyrox  = be16_to_cpu(val.gyrox);
		val.gyroy  = be16_to_cpu(val.gyroy);
		val.gyroz  = be16_to_cpu(val.gyroz);
		if (copy_to_user((struct atg_val __user *)arg, &val, sizeof(struct atg_val)))
			return -EFAULT;
		break;
	default:
		return -ENOTTY;
	}

	return 0;
}

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

static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	int ret;
	dev_t dev;
	struct mpu6050_dev *mpu6050;

	dev = MKDEV(FSRTC_MAJOR, FSRTC_MINOR);
	ret = register_chrdev_region(dev, 1, FSRTC_DEV_NAME);
	if (ret)
		goto reg_err;

	
	mpu6050_cls = class_create(THIS_MODULE,"mpu6050");
	if(IS_ERR(mpu6050_cls)){
		ret = PTR_ERR(mpu6050_cls);
		goto mem_err;
	}


	mpu6050 = kzalloc(sizeof(struct mpu6050_dev), GFP_KERNEL);
	if (!mpu6050) {
		ret = -ENOMEM;
		goto cls_err;
	}

	mpu6050->device = device_create(mpu6050_cls, NULL, dev, NULL, "mpu6050");
	if (IS_ERR(mpu6050->device)) {
        	ret = PTR_ERR(mpu6050->device);
        	goto add_err;
    	}

	i2c_set_clientdata(client, mpu6050);
	mpu6050->client = client;

	cdev_init(&mpu6050->cdev, &mpu6050_ops);
	mpu6050->cdev.owner = THIS_MODULE;
	ret = cdev_add(&mpu6050->cdev, dev, 1);
	if (ret)
		goto add_err;

	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
		ret = -ENOSYS;
		goto fun_err;
	}

	i2c_smbus_write_byte_data(client, PWR_MGMT_1, 0x80);
	msleep(200);
	i2c_smbus_write_byte_data(client, PWR_MGMT_1, 0x40);
	i2c_smbus_write_byte_data(client, PWR_MGMT_1, 0x00);

	i2c_smbus_write_byte_data(client, SMPLRT_DIV,   0x7);
	i2c_smbus_write_byte_data(client, CONFIG,       0x6);
	i2c_smbus_write_byte_data(client, GYRO_CONFIG,  0x3 << 3); 
	i2c_smbus_write_byte_data(client, ACCEL_CONFIG, 0x3 << 3);

	atomic_set(&mpu6050->available, 1);

	return 0;

fun_err:
	cdev_del(&mpu6050->cdev);
add_err:
	kfree(mpu6050);
cls_err:
	class_destroy(mpu6050_cls);
mem_err:
	unregister_chrdev_region(dev, 1);
reg_err:
	printk("erro\n");
	return ret;
}

static int mpu6050_remove(struct i2c_client *client)
{
	dev_t dev;
	struct mpu6050_dev *mpu6050 = i2c_get_clientdata(client);

	dev = MKDEV(FSRTC_MAJOR, FSRTC_MINOR);

	cdev_del(&mpu6050->cdev);
	kfree(mpu6050);
	unregister_chrdev_region(dev, 1);
	device_unregister(mpu6050->device);
	class_destroy(mpu6050_cls);
	return 0;
}

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

MODULE_DEVICE_TABLE(i2c, mpu6050_id);

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

module_i2c_driver(mpu6050_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kevin Jiang <
[email protected]
>"); MODULE_DESCRIPTION("MPU6050 driver");

然後重新編譯dtb並生成裝置驅動檔案,替換原本的dtb並載入驅動程式。由於上述程式使用了自動建立裝置節點的class_create,所以不再需要手動到/dev新增裝置節點,驅動程式載入成功後會自動生成mpu6050裝置檔案。我們通過讀寫該檔案就可以使用mpu6050。

        接下來我們需要新增測試驅動檔案,檢查驅動是否正常工作。測試原始碼如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>

struct atg_val {
	short accelx;
	short accely;
	short accelz;
	short temp;
	short gyrox;
	short gyroy;
	short gyroz;
};

#define MPU6050_MAGIC	'm'

#define MPU6050_GET_VAL	_IOR(MPU6050_MAGIC, 0, struct atg_val)


int main(int argc, char *argv[])
{
	int fd;
	struct atg_val val;


	fd = open("/dev/mpu6050", O_RDWR);

	while (2) {
		ioctl(fd, MPU6050_GET_VAL, &val);

		printf("accelx: %.2f\n", val.accelx / 2048.0);
		printf("accely: %.2f\n", val.accely / 2048.0);
		printf("accelz: %.2f\n", val.accelz / 2048.0);
		printf("temp: %.2f\n", val.temp / 340.0 + 36.53); 
		printf("gyrox: %.2f\n", val.gyrox / 16.4);
		printf("gyroy: %.2f\n", val.gyroy / 16.4);
		printf("gyroz: %.2f\n", val.gyroz / 16.4);


		sleep(1);
	}
}

利用arm-linux-gcc編譯生成測試程式,在x4412上執行,如果可以在終端上動態顯示相關資訊,可知該驅動工作正常

相關推薦

x4412 i2c裝置驅動開發例項(mpu6050)

        MPU6050 包括陀螺儀和加速度感測器功能,陀螺儀和加速度感測器分別用三個 16bit 的資料表示,量程和精度都是可程式設計的,可按需求設定,具體 MPU6050 引數參照晶片手冊。Exynos4412 共有八組 I2C 控制器,我們使用x4412引出的i2

簡單i2c裝置驅動例項

  相關文章: 平臺: msm8916 OS:安卓5.1 usb4604在裝置上作用是切換裝置為主從模式。 裝置樹檔案如下: [email protected] { compatible = "microchip,usb4604

Linux 裝置驅動開發 —— platform裝置驅動應用例項解析

       前面我們已經學習了platform裝置的理論知識Linux 裝置驅動開發 —— platform 裝置驅動 ,下面將通過一個例項來深入我們的學習。 一、platform 驅動的工作過程         platform模型驅動程式設計,需要實現platfor

《linux裝置驅動開發詳解》筆記——15 linux i2c驅動

  結合實際程式碼和書中描述,可能跟書上有一定出入。本文後續晶片相關程式碼參考ZYNQ。 15.1 總體結構   如下圖,i2c驅動分為如下幾個重要模組 核心層core,完成i2c匯流排、裝置、驅動模型,對使用者提供sys檔案系統訪問支援;為i2c內部adpter等提供註冊介面。  adpter,介面卡,實

Linux I2C裝置驅動編寫(三)-例項分析AM3359

TI-AM3359 I2C介面卡例項分析 I2C Spec簡述 特性: 相容飛利浦I2C 2.1版本規格支援標準模式(100K bits/s)和快速模式(400K bits/s)多路接收、傳送模式支援7bit、10bit裝置地址模式32位元組FIFO緩衝區可程式設計時鐘發生

四極管: Android開發除錯I2C裝置驅動 i2cdetect 工具的使用

使用步驟:          1、在網上搜索一個i2cdetect工具包。我下載的是i2c-tools-3.0.2.tar.bz2。放到windows與ubuntu共享目錄。               tar -xvf i2c-tools-3.0.2.tar.bz2   

嵌入式Linux裝置驅動開發之:按鍵驅動程式例項

11.6  按鍵驅動程式例項 11.6.1  按鍵工作原理 高電平和低電平相接怎麼會變成低電平呢 就像你把電源正極的負極相連一樣會把電壓拉低。大電流會從高電平引腳流向低電平引腳,把高電平引腳拉低。 LED和蜂鳴器是最簡單的GPIO的應用,都不需要任何外部

linux裝置驅動開發學習--記憶體和IO訪問

一 I/O 埠 1. 讀寫位元組埠(8 位寬) unsigned inb(unsigned port); void outb(unsigned char byte, unsigned port); 2. 讀寫字埠(16 位寬) unsigned inw(unsigne

《linux裝置驅動開發》,基於最新的linux 4.0核心-----筆記

第二章 Linux 的核心結構及構建 ---->這一章是自己總結的 1、核心結構(主要是下面這幾個部分) 系統呼叫介面<–>System call interface 程序管理<------>Process manag

嵌入式Linux開發——(十七)Linux裝置驅動開發

一、字元裝置驅動程式 1)應用程式、庫、核心、驅動程式的關係 2)Linux驅動程式的分類和開發步驟     ①Linux的外設可分為3類:字元裝置(character device)、塊裝置(block device)、網路介面(network interfa

Linux裝置驅動開發詳解 第3版 (即 Linux裝置驅動開發詳解 基於最新的Linux 4 0核心 )進展同步更

                本博實時更新《Linux裝置驅動開發詳解(第3版)》的最新進展。 目前已經完成稿件。 2015

嵌入式Linux裝置驅動開發——selec/poll

應用程式呼叫select,select系統呼叫的原型: int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout); fd_set資料

i2c裝置驅動

跟所有的 bus-dev-drv模型一樣,當我們拿到一個模組我們需要做的就是dev_drv即裝置驅動程式 一、裝置(device) 方法一、自己寫一個i2c_device.c #include <linux/kernel.h> #include &l

Linux裝置驅動開發學習筆記

2016.6.25 這部門主要是之前學習linux裝置驅動開發時候的一些筆記,主要學習的參考書是《Linux裝置驅動開發詳解第2版》 書連結:http://note.youdao.com/noteshare?id=bbf134da309035b2093c5abcd5c7c8ac&

i2c裝置驅動probe函式中platform_data

i2c裝置驅動一般在probe函式的開頭都會先獲取platform_data資料。 1、在沒有使用dts的kernel 驅動中, 要麼直接賦值:client->dev.platform_data = pdata;  要麼使用介面設定:platform_device_

Linux 裝置驅動篇之-------I2c裝置驅動(待續)

Linux 裝置驅動篇之-------I2c裝置驅動 雖然I2C硬體體系結構和協議都很容易理解,但是Linux I2C驅動體系結構卻有相當的複雜度,它主要由3部分組成,即I2C裝置驅動、I2C匯流

Linux I2C裝置驅動編寫(一)

在Linux驅動中I2C系統中主要包含以下幾個成員: I2C adapter 即I2C介面卡 I2C driver 某個I2C裝置的裝置驅動,可以以driver理解。 I2C client 某個I2C裝置的裝置宣告,可以以device理解。 I2C adapter 是

Linux系統I2C裝置驅動編寫方法

硬體平臺:飛思卡爾IMX6 核心版本:kernel3.0.35 Linux的I2C子系統分為三層,I2C核心層,I2C匯流排驅動層和I2C裝置驅動層。I2C核心層由核心開發者提供,I2C匯流排驅動層有晶片廠商提供,而I2C裝置驅動層由於裝置的差異性,就只能是具體的開發需求

linux I2C 裝置驅動學習筆記

一:I2C 概述           I2C是philips提出的外設匯流排.使用SCL時鐘線,SDA序列資料線這兩根訊號線就實現了裝置之間的資料互動,被非常廣泛地應用在CPU與EEPROM,實時鐘,小型LCD等裝置通訊中。  二:在linux下的驅動思路     linu

I2C裝置驅動之字元裝置簡寫

最近有機會需要寫一個 掛載在I2C匯流排的I2C裝置驅動,外設晶片是MCP23017 IO擴充套件晶片,測試是否可以通訊成功,以下是部分程式碼以及除錯的一些注意項: #include <linux/kernel.h> #include <linux/init.h>