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>