1. 程式人生 > >MPU6050帶字元驅動的i2c從裝置驅動2

MPU6050帶字元驅動的i2c從裝置驅動2

#include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/mutex.h> #include <linux/workqueue.h> #include <linux/i2c.h> #include <linux/types.h> #include "log.h" #include "mpu6050_reg.h" MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kevin Liu"); struct axis_data { s16 value; int standby; }; struct sub_sensor { int st; // self-test int reset; // reset int sel; // full scale range struct axis_data x; struct axis_data y; struct axis_data z; }; struct temp_sensor { int enable; int reset; s16 value; }; struct pwr_mgmt { int reset; int sleep; int cycle; int cycle_HZ; int clksel; int all_standby; }; struct mpu6050_data { struct mutex lock; struct i2c_client *client; struct delayed_work work; struct workqueue_struct *wq; int delay_ms; struct sub_sensor gyro; struct sub_sensor accel; struct temp_sensor temp_s; struct pwr_mgmt power; int dlph; int dhph; }; enum { RANGE, LSB }; static float accel_sel[][2] = { {2, 16384}, {4, 8192}, {8, 4096}, {16, 2048} }; static float gyro_sel[][2] = { {250, 131}, {500, 65.5}, {1000, 32.8}, {2000, 16.4} }; static void mpu6050_enable(struct mpu6050_data *mpu6050) { struct i2c_client *client = mpu6050->client; i2c_smbus_write_byte_data(client, MPU6050_REG_PWR_MGMT_1, 0); } static void mpu6050_disable(struct mpu6050_data *mpu6050) { struct i2c_client *client = mpu6050->client; i2c_smbus_write_byte_data(client, MPU6050_REG_PWR_MGMT_1, 1 << PWR_1_SLEEP_OFFSET); } static void mpu6050_reset(struct mpu6050_data *mpu6050) { struct i2c_client *client = mpu6050->client; i2c_smbus_write_byte_data(client, MPU6050_REG_PWR_MGMT_1, 1 << PWR_1_DEVICE_RESET_OFFSET); } /* * Get gyro/accel/temprature data * @type : 0 - gyro * 1 - accel * 2 - temprature */ static int mpu6050_read_data(struct mpu6050_data *mpu6050, int type) { s16 values[3]; int i, addr, ret; struct i2c_client *client = mpu6050->client; switch(type) { case 0: addr = MPU6050_REG_GYRO_XOUT_H; break; case 1: addr = MPU6050_REG_ACCEL_XOUT_H; break; case 2: addr = MPU6050_REG_TEMP_OUT_H; break; default: addr = MPU6050_REG_GYRO_XOUT_H; break; } if (type == 0 || type == 1) { ret = i2c_smbus_read_i2c_block_data(client, addr, 6, (u8 *)values); if (ret < 0) { E("error read gyro\n"); return ret; } for (i = 0; i < 3; i++) { values[i] = be16_to_cpu(values[i]); } } else if (type == 2) { ret = i2c_smbus_read_i2c_block_data(client, addr, 2, (u8 *)values); if (ret < 0) { E("error read gyro\n"); return ret; } for (i = 0; i < 1; i++) { values[i] = be16_to_cpu(values[i]); } } switch(type) { case 0: mpu6050->gyro.x.value = values[0]; mpu6050->gyro.y.value = values[1]; mpu6050->gyro.z.value = values[2]; break; case 1: mpu6050->accel.x.value = values[0]; mpu6050->accel.y.value = values[1]; mpu6050->accel.z.value = values[2]; break; case 2: mpu6050->temp_s.value = values[0]; break; default: break; } return 0; } static int mpu6050_read_gyro(struct mpu6050_data *mpu6050) { return mpu6050_read_data(mpu6050, 0); } static int mpu6050_read_accel(struct mpu6050_data *mpu6050) { return mpu6050_read_data(mpu6050, 1); } static int mpu6050_read_temprature(struct mpu6050_data *mpu6050) { return mpu6050_read_data(mpu6050, 2); } static void mpu6050_dump_all(struct mpu6050_data *mpu6050) { D("Gyro(X:%d Y:%d Z:%d)\tAccel(X:%d Y:%d Z:%d)\tTemp:%d\n", mpu6050->gyro.x.value, mpu6050->gyro.y.value, mpu6050->gyro.z.value, mpu6050->accel.x.value, mpu6050->accel.y.value, mpu6050->accel.z.value, mpu6050->temp_s.value); } static void mpu6050_work(struct work_struct *work) { int ret; struct mpu6050_data *mpu6050 = container_of( (struct delayed_work *)work, struct mpu6050_data, work); mpu6050_read_gyro(mpu6050); mpu6050_read_accel(mpu6050); mpu6050_read_temprature(mpu6050); mpu6050_dump_all(mpu6050); schedule_delayed_work(&mpu6050->work, msecs_to_jiffies(mpu6050->delay_ms)); } static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct mpu6050_data *mpu6050; u16 version; D("Probe match happend, ID %s\n", id->name); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { E("I2C check error\n"); return -EINVAL; } mpu6050 = kzalloc(sizeof(*mpu6050), GFP_KERNEL); //申請記憶體 if (!mpu6050) { E("Mem error\n"); return -ENOMEM; } else D("Alloc OK\n"); mpu6050->client = client; i2c_set_clientdata(client, mpu6050); //mmpu6050在clent中註冊 mutex_init(&mpu6050->lock); mpu6050->delay_ms = 1000; D("Set OK\n"); INIT_DELAYED_WORK(&mpu6050->work, mpu6050_work); D("Work queue OK\n"); //INIT_DELAYED_WORK 初始化帶延時的工作佇列work,將mpu6050_work這個函式放到工作佇列中,然後等到呼叫schedule_delayed_work時執行。 version = i2c_smbus_read_byte_data(client, MPU6050_REG_WHO_AM_I); if (version != 0x68) { E("Version check error 0x%X, skip\n", version); goto free_all; } else D("Version Check OK\n"); // 讀ID mpu6050_reset(mpu6050); mpu6050_enable(mpu6050); schedule_delayed_work(&mpu6050->work, msecs_to_jiffies(mpu6050->delay_ms)); //這裡呼叫非同步執行mpu6050_work這個函式。 return 0; free_all: kfree(mpu6050); E("A oh!!!ooops...\n"); return -EINVAL; } static int mpu6050_remove(struct i2c_client *client) { struct mpu6050_data *mpu6050 = i2c_get_clientdata(client); mpu6050_disable(mpu6050); cancel_delayed_work(&mpu6050->work); kfree(mpu6050); return 0; } static struct i2c_device_id mpu6050_ids[] = { {SENSOR_NAME, 0}, { }, }; static struct i2c_driver mpu6050_driver = { .driver = { .name = SENSOR_NAME, .owner = THIS_MODULE, }, .class = I2C_CLASS_HWMON, .id_table = mpu6050_ids, .probe = mpu6050_probe, .remove = mpu6050_remove, }; /*上面定義i2c_driver結構體,整個檔案的目的就是實現i2c_driver結構體,並通過module_i2c_driver
註冊i2c驅動,當i2c_driver和i2c_client的name一樣,系統就對其進行probe,也就是執行mpu6050_probe函式。*/ module_i2c_driver(mpu6050_driver); 檢視整個驅動,實現了i2c_driver,掛載了i2c裝置獲得了i2c_cilent,使用了工作佇列,實現資料的延時連續讀取。這裡分別對mpu_client.c 和mpu_driver.c進行編譯得到mpu_client.ko,mpu_driver.ko。先載入mpu_client,再載入mpu_driver,得到: 可以看到驅動確實在工作,在不斷獲取陀螺儀資料,這裡並沒有將資料進行轉化。

相關推薦

MPU6050字元驅動i2c裝置驅動1

開幹: 1、閒言碎語 這個驅動,越寫覺的越簡單,入門難,入門之後感覺還好。Linux開發還是比較友好的。 2、編寫MPU6050帶字元驅動的i2c從裝置驅動 要實現的功能就是,將MPU6050作為字元驅動,在應用層,對其進行讀資料。實現簡單的功能。在前面的分析和實踐中,可以看到實現字元驅動主要是實

MPU6050字元驅動i2c裝置驅動2

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

i2c驅動程式全面分析,adapter驅動程式到裝置驅動程式

開發板    :mini2440 核心版本:linux2.6.32.2 驅動程式參考:韋東山老師畢業班i2c 內容概括:    1、adapter client 簡介2、adapter 驅動框架      2.1 裝置側2.2 驅動側         2.2.1 probe

Linux下SPI裝置驅動的編寫

 SPI(Serial Peripheral Interface) 是一個同步的四線制序列線,用於連線微控制器和感測器、儲存器及外圍裝置。三條訊號線持有時鐘訊號(SCLK,經常在10MHz左右)和並行資

Linux功耗管理(25_Linux電源管理(14)_裝置驅動的角度看電源管理)

1. 前言 相信工作稍微久一點的linux驅動工程師都深有體會: 在舊時光裡,實現某一個裝置的電源管理功能,是非常簡單的一件事情。大多數裝置都被抽象為platform裝置,driver只需要提供suspend/resume/shutdown等回撥函式,並註冊到kerne

網路協議棧分析——裝置驅動到鏈路層

對應我們上面的網絡卡驅動分析。接收到的資料是存放在data至tail之間的區域。 Skb通常還有常用的幾個函式,一一列舉分析如下: struct sk_buff *alloc_skb(unsigned int size,int gfp_mask) 分配儲存空間為sixe的skb,記憶體分配級別為gf

字元裝置驅動與塊裝置驅動、網路裝置驅動的區別

在Linux作業系統下有3類主要的裝置檔案型別:塊裝置、字元裝置和網路裝置。這種分類方法可以將控制輸入/輸出裝置的驅動程式與其他作業系統軟體分離開來。字元裝置是指存取時沒有快取的裝置。典型的字元裝置包括滑鼠、鍵盤、序列口等。字元裝置與塊裝置的主要區別是:在對字元裝置發出讀/

[轉]字元裝置驅動和塊裝置驅動的區…

    系統中能夠隨機(不需要按順序)訪問固定大小資料片(chunks)的裝置被稱作塊裝置,這些資料片就稱作塊。最常見的塊裝置是硬碟,除此以外,還有軟盤驅動器、CD-ROM驅動器和快閃記憶體等等許多其他塊裝置。注意,它們都是以安裝檔案系統的方式使用的——這也是塊裝置的一般訪問方式。   另一種基本的裝置型

(二)USB驅動程式_USB裝置驅動(Host)

USB裝置驅動(Host) 深入,並且廣泛 -沉默犀牛 有了第一篇文章的基礎,我們這篇文章來看一下USB裝置驅動的原始碼。與其他的Driver一樣,USB的driver也表現為一個結構體:struct usb_driver 驅動整體結構 在編寫新的USB

STM32F1與I2C裝置通訊無應答?

最近做了STM32F103與DAC的I2C通訊,起先使用的是硬體I2C來驅動,按照時序寫好程式通訊正常,但由於電路板需求,需要將I2C的SCL和SDA線拉長,導致硬體I2C通訊經常掛死,於是考慮採用模擬I2C,(硬體I2C和模擬I2C的程式在我另外兩篇部落格上有),但是也經常掛死,最後終於找到原因,

Linux驅動開發04:塊裝置驅動和網路裝置驅動

介紹 因為塊裝置驅動和網路裝置驅動實際中用得較少,所以只給出驅動模板,我也沒有具體測試,等到實際用到是再研究吧,溜了溜了。 塊裝置驅動模板 struct xxx_dev { int size; struct request_q

Linux驅動開發----塊裝置驅動(記憶體模擬)Tiny6410

寫了好久的字元裝置驅動,是時候看下塊裝置驅動程式設計方法了,塊裝置驅動和字元裝置不同,字元裝置是直接和虛擬檔案系統進行互動,而塊裝置驅動則是通過塊緩衝/排程層間接和虛擬檔案系統互動;塊裝置驅動資料訪問都是以塊為單位;多個塊I/O需要組成一個請求佇列,這個功能是塊緩衝/排程層

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

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

平臺裝置驅動和混雜裝置驅動

1. 平臺裝置驅動 在linux2.6以後的裝置驅動模型中,只關心裝置、驅動和匯流排這三個實體,匯流排將裝置驅動繫結。在向系統註冊一個裝置時會由匯流排匹配對應的驅動,相反當向系統註冊一個驅動時由匯流排匹配出對應的裝置。 在linux裝置和驅動通常要掛接在某條總線上,對於II

Linux應用層讀寫i2c裝置(eeprom)

/***************************************************************************** i2c讀函式,引數1:從裝置地址,引數2:暫存器地址,引數3:讀取資料緩衝區,引數4:讀取資料大小

linux驅動之塊裝置驅動

塊裝置驅動的系統架構 VFS: 是對各種具體檔案系統的一種封裝,使用者程式訪問檔案提供統一的介面。例如: EXT2,FAT,NFS等 系統架構—Cache: 當用戶發起檔案訪問請求的時候,首先回到Cache中定址檔案是否被快取了,如果在Ca

【linux】驅動-6-匯流排-裝置-驅動

[toc] --- ## 前言 ## 6. 匯流排-裝置-驅動 **匯流排-裝置-驅動** 又稱為 **裝置驅動模型**。 ### 6.1 概念 * ![](https://img2020.cnblogs.com/blog/2085252/202103/2085252-2021033012262324

【linux】驅動-7-平臺裝置驅動

[toc] --- ## 前言 區分**裝置驅動模型**和**平臺裝置驅動模型**。 **裝置驅動模型** 可以理解為 **匯流排、裝置、驅動**。 **平臺裝置驅動模型** 就是那些 Linux 核心管理沒有物理匯流排(*即是不需要特殊時序控制的裝置*)(*也是Linux核心沒有自動建立相應驅動匯流

MPU6050字符驅動i2c設備驅動1

val 添加 space res add 操作方法 驅動 move 初始化 開幹: 1、閑言碎語 這個驅動,越寫覺的越簡單,入門難,入門之後感覺還好。Linux開發還是比較友好的。 2、編寫MPU6050帶字符驅動的i2c從設備驅動 要實現的功能就是,將MP

I2C裝置驅動字元裝置簡寫

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