1. 程式人生 > >一週搞定MPU6050Linux驅動(2)

一週搞定MPU6050Linux驅動(2)

第2-3日 參考: 《Linux裝置驅動程式》 第三版 有了前面的原始碼學習和分析,對i2c驅動有了大概的認識。那麼接下來,我們就開始我們自己的mpu6500/6050驅動的編寫。這裡說一下,mpu6500和mpu6050在暫存器上基本沒什麼區別,只有version ID不同,6500的是0x70,6050是0x68。 之前分析了airk000的原始碼,發現他的驅動方式是在後臺完成6050的資料定時讀取。那麼,我們所需要實現的驅動,是對mpu6050/6500進行中斷讀取。並且包含了字元裝置驅動,用來在使用者空間獲取資料。 1、學習字元裝置驅動,實現fifo 在建立一個字元裝置之前,需要獲得一個或多個裝置編號。可以選擇靜態分配和動態分配,推薦動態分配。使用alloc_chrdev_region函式來進行裝置號的動態分配。 字元驅動的三個核心資料結構file_operations,file,inode file_operations定義操作方法,包括字元的open,wirte,ioctrl等。 file結構表示一個開啟的檔案 inode在核心表示一個檔案實體,包含了大量的有關檔案的資訊。
  1. 在虛擬檔案系統VFS中的查詢對應與字元裝置對應 struct inode節點
  2. 遍歷字元裝置列表(chardevs陣列),根據inod節點中的 cdev_t裝置號找到cdev物件
  3. 建立struct file物件(系統採用一個數組來管理一個程序中的多個被開啟的裝置,每個檔案秒速符作為陣列下標標識了一個裝置物件)
  4. 初始化struct file物件,將 struct file物件中的 file_operations成員指向 struct cdev物件中的 file_operations成員(file->fops =  cdev->fops)
  5. 回撥file->fops->open函式
我們可以看到我們必須實現幾個結構中的方法,尤其是file_operations,然後例項化cdev,file結構體,並將他們建立聯絡。 那麼一個字元裝置檔案的建立,需要以下幾個步驟: 1、呼叫alloc_chrdev_region(&dev, myfifomajor,1,"myfifo");來動態分配裝置號。 2、 cdev_init(&myfifo_dev->cdev,&myfifo_fops); 初始化cdev,一般cdev會定義在自己的資料結構中,本文中定義在Fifo_Dev中。 3、cdev_add(&myfifo_dev->cdev,devno,1);將cdev新增到核心中。 有了前三個步驟,載入模組的時候,會在/proc/device中出現myfifo。如果想在/dev中建立節點。那麼還需要另外兩個步驟: 4、class_create(THIS_MODULE, "myfifo"); 建立類目錄 5、 device_create(cls,NULL,devno,NULL,"myfifo");建立device 執行完以上程式碼之後,即可完成裝置的初始化。 初始化程式碼如下: int myfifo_init_module(void) { int result, i,err; dev_t dev,devno; //×¢²ácdev£¬ »ñÈ¡É豸ºÅ£¬0´ú±í×Ô¶¯·ÖÅä printk("hello fifo\n"); result = alloc_chrdev_region(&dev, myfifomajor,1,"myfifo"); if (result < 0) { printk(KERN_WARNING "myfifo: can't get major %d\n",myfifomajor); return result; } printk(KERN_DEBUG "ALLOC SUCCEED\n"); if(myfifomajor == 0) myfifomajor = MAJOR(dev); //·ÖÅämyfifodev myfifo_dev = kmalloc(sizeof(Fifo_Dev), GFP_KERNEL); if (!myfifo_dev) { result = -ENOMEM; goto fail; } myfifo_dev->data = kmalloc(MYFIFOSIZE,GFP_KERNEL); if (!myfifo_dev->data) { result = -ENOMEM; goto fail; } //memset(myfifo_dev, 0, sizeof(Fifo_Dev)); memset(myfifo_dev->data, 0, MYFIFOSIZE); myfifo_dev->head = 0; myfifo_dev->tail = 0; sema_init(&myfifo_dev->sem,1); // initial signal devno = MKDEV(myfifomajor, 0); cdev_init(&myfifo_dev->cdev,&myfifo_fops); myfifo_dev->cdev.owner = THIS_MODULE;//ËùÊôÄ£¿é myfifo_dev->cdev.ops = &myfifo_fops; err = cdev_add(&myfifo_dev->cdev,devno,1);//×¢²áÉ豸,·µ»Ø0±íʾ³É¹¦,·Ç0±íʾʧ°Ü printk(KERN_DEBUG "init SUCCEED\n"); if(err){ printk(KERN_NOTICE "Error %d adding fifo",err); goto fail; } cls = class_create(THIS_MODULE, "myfifo"); if(IS_ERR(cls)) { goto fail; } printk("class create.\n"); test_device = device_create(cls,NULL,devno,NULL,"myfifo");//mknod /dev/hello if(IS_ERR(test_device)) { class_destroy(cls); goto fail; } printk(KERN_DEBUG "my fifo device alloc succeed!\n"); return 0; /* succeed */ fail: myfifo_cleanup_module(); return result; } 將 struct file_operations myfifo_fops = { .owner = THIS_MODULE, .read = myfifo_read, .write = myfifo_write, .open = myfifo_open, .release = myfifo_release, };結構體中的open,read,write,release實現好之後。按照《一週搞定MPU6500驅動(1)》中的方法進行編譯。 通過filezila下載到開發板中,載入模組。 編寫測試檔案,功能是向myfifo裝置中寫20個數,再讀出20個數,檢視是否相同。如下: #include <stdio.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(int argc,char *argv[]) { unsigned char buf[50]; int fd; int i; for(i=0; i<20; i++) { buf[i] = i; } fd = open("/dev/myfifo",O_RDWR); if(fd<0) { printf("error!\n"); } write(fd,buf,20); read(fd,buf+20,20); for(i=0; i<20; i++) { printf(" %d",*(buf+20+i)); } return 1; } 可以得到結果:
讀出的數與寫入的數相同,說明核心函式能夠正常執行。 這裡需要注意的是,執行程式需要以sudo來執行,因為裝置驅動的許可權是root。第一次執行的時候,我沒有使用sudo,一直報錯,裝置無法開啟,fd返回-1。這個要注意。 折騰了兩個晚上,明天開始寫mpu6050/6500的驅動。 有什麼疑問或者交流的加我QQ475292178,請註明“交流探討”