嵌入式系統(tǒng)原理及應(yīng)用課件:設(shè)備驅(qū)動程序設(shè)計_第1頁
嵌入式系統(tǒng)原理及應(yīng)用課件:設(shè)備驅(qū)動程序設(shè)計_第2頁
嵌入式系統(tǒng)原理及應(yīng)用課件:設(shè)備驅(qū)動程序設(shè)計_第3頁
嵌入式系統(tǒng)原理及應(yīng)用課件:設(shè)備驅(qū)動程序設(shè)計_第4頁
嵌入式系統(tǒng)原理及應(yīng)用課件:設(shè)備驅(qū)動程序設(shè)計_第5頁
已閱讀5頁,還剩41頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

設(shè)備驅(qū)動程序設(shè)計嵌入式系統(tǒng)原理與應(yīng)用目錄CONTENTS01.驅(qū)動開發(fā)概述02.內(nèi)核模塊03.字符設(shè)備驅(qū)動01PARTONELinux驅(qū)動概述設(shè)備驅(qū)動程序(DeviceDriver),簡稱驅(qū)動程序(Driver)。它是一個允許計算機軟件與硬件交互的程序。這種程序建立了一個硬件與硬件,硬件與軟件形成連接,這樣的連接使得硬件設(shè)備之間的數(shù)據(jù)交換成為可能。設(shè)備驅(qū)動程序是計算機硬件與應(yīng)用程序的接口,是軟件系統(tǒng)與硬件系統(tǒng)溝通的橋梁。字符設(shè)備塊設(shè)備網(wǎng)絡(luò)設(shè)備設(shè)備驅(qū)動分類02PARTTWO內(nèi)核模塊1、字符設(shè)備--c一、Linux設(shè)備驅(qū)動分類應(yīng)用程序和驅(qū)動程序進行數(shù)據(jù)讀寫時,是以“字節(jié)”為單位,按照固定的順序傳輸;數(shù)據(jù)是實時傳輸,沒有緩存。字符設(shè)備是沒有文件系統(tǒng)的。絕大部分設(shè)備驅(qū)動是字符設(shè)備:LED、BEEP、按鍵、鍵盤、觸摸屏、攝像頭、液晶屏、聲卡、IIC、SPI、...應(yīng)用程序:系統(tǒng)IO函數(shù)open("/dev/led_drv",O_RDWR)read()write()ioctl()mmap()close()2、塊設(shè)備--b一、Linux設(shè)備驅(qū)動分類應(yīng)用程序和驅(qū)動程序之間進行數(shù)據(jù)讀寫時,數(shù)據(jù)是以“塊”為單位,1block=1024KB。塊設(shè)備是有緩存的,塊設(shè)備是有文件系統(tǒng)的。大容量的存儲設(shè)備一般都是塊設(shè)備:nandflash、eMMC、SD、U盤、硬盤、....#cat/proc/partitionsmajorminor#blocksnammcblk0179165536mmcblk0p1應(yīng)用程序訪問塊設(shè)備[root@GEC6818/]#ls/dev/sda*-lbrw-rw-rw-1rootroot8,0Jan100:11/dev/sda--->U盤1)掛載---塊設(shè)備是有文件系統(tǒng)的。2)像訪問普通文件一樣訪問塊設(shè)備的內(nèi)容。3、網(wǎng)絡(luò)設(shè)備一、Linux設(shè)備驅(qū)動分類網(wǎng)卡類的設(shè)備:有線網(wǎng)卡、無線網(wǎng)卡、...,網(wǎng)絡(luò)設(shè)備是沒有設(shè)備文件的。應(yīng)用程序:

socket套接字:IP+端口號二、內(nèi)核模塊的定義1、linuxkernelmodule2、module編譯后會生成一個*.ko安裝驅(qū)動:#insmodled_drv.ko卸載驅(qū)動:#rmmodled_drv.ko查看系統(tǒng)中,已安裝的module:#lsmod驅(qū)動程序在內(nèi)核中是獨立的模塊例如:beep驅(qū)動和LED驅(qū)動,beep和led間沒有任何聯(lián)系,可以通過應(yīng)用

程序?qū)蓚€驅(qū)動聯(lián)系在一起。beep驅(qū)動和led驅(qū)動各自是獨立的module。說明:每個驅(qū)動程序都是一個獨立模塊,每設(shè)計一個驅(qū)動程序,首先設(shè)計一個module,驅(qū)動程序是包含在module中。三、Sourceinsight創(chuàng)建工程1、SI設(shè)置Options--->DocumentOptions--->DocumentType:CSourceFile:*.c;*.h;*.S;*.s

X86AsmSourceFile:*.asm;*.inc;*.S;*.s2、創(chuàng)建一個工程project-->newproject-->工程文件放在源碼包中(I:\GEC6818物聯(lián)網(wǎng)綜合實驗箱(多模塊版本)-201708\1、嵌入式6818網(wǎng)關(guān)平臺\源碼\kernel6818\kernel6818)addtree(稍微等一下)--->close3、文件的同步project--->synchronizeFiles(同步文件)4、內(nèi)核源碼在kernel中I:\GEC6818物聯(lián)網(wǎng)綜合實驗箱(多模塊版本)-201708\1、嵌入式6818網(wǎng)關(guān)平臺\源碼\6818GEC\kernel四、設(shè)計一個module并編譯注意:參考內(nèi)核源碼,首先使用sourceinsight創(chuàng)建一個內(nèi)核源碼的工程例子:/drivers/watchdog/mxp_wdt.c1、設(shè)計module2、Makefile3、編譯1、指定安裝驅(qū)動的入口函數(shù),用宏module_init(安裝驅(qū)動的入口函數(shù)名)2、指定卸載驅(qū)動的入口函數(shù),用宏module_exit(卸載驅(qū)動的入口函數(shù)名)3、定義對應(yīng)入口函數(shù)4、驅(qū)動的描述

MODULE_AUTHOR("bobeyfeng@163.com");//作者聯(lián)系方式MODULE_DESCRIPTION("LEDdriverforGEC6818");//驅(qū)動描述MODULE_LICENSE(“GPL”);//GPL協(xié)議MODULE_VERSION("V1.0");#include<linux/module.h>#include<linux/kernel.h>#include<linux/init.h>//入口函數(shù)--->安裝驅(qū)動staticint__initgec6818_led_init(void){ printk(“<4>”“gec6818leddriverinit\n”);//內(nèi)核程序打印printk,應(yīng)用程序printf return0;}//出口函數(shù)--->卸載驅(qū)動staticvoid__exitgec6818_led_exit(void){ printk("gec6818leddriverexit\n");}

//驅(qū)動程序的入口:#insmodled_drv.ko-->module_init()-->gec6818_led_init()module_init(gec6818_led_init);//驅(qū)動程序的出口:#rmmodled_drv.ko--->module_exit()-->gec6818_led_exit()module_exit(gec6818_led_exit);

//module的描述。#modinfoled_drv.koMODULE_AUTHOR("bobeyfeng@163.com");//作者聯(lián)系方式MODULE_DESCRIPTION("LEDdriverforGEC6818");//驅(qū)動描述MODULE_LICENSE(“GPL”);//GPL協(xié)議MODULE_VERSION("V1.0");1、設(shè)計moduleINSTALLDIR

=

/tftpboot

ifneq($(KERNELRELEASE),)obj-m:=hello.oelseKERNELDIR:=/home/cw/kernel/CROSS_COMPILE:=/home/cw/6818GEC/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-

PWD:=$(shellpwd)

default:

#mkdir-p$(INSTALLDIR)

$(MAKE)ARCH=armCROSS_COMPILE=$(CROSS_COMPILE)-C$(KERNELDIR)M=$(PWD)modules

#cp--target-dir=$(INSTALLDIR)hello.ko

clean:

rm-rf*.o*.ko*.order.*.cmd*.mod.c*.symversendif2、Makefile---版本1目標:依賴Tab命令3)交叉編譯工具2)內(nèi)核源碼的路徑1)將源程序的目標文件led_drv.o,編譯成一個module(ko)4)當前路徑5)向內(nèi)核源碼路徑下的Makefile文件傳遞兩個參數(shù),并調(diào)用內(nèi)核源碼下的Makefile文件,使用該Makfile中的工具,回到當前路徑下,將源程序編譯成一個module

ROOTFS_DIR=/opt/4412/rootfs

ifeq($(KERNELRELEASE),)

KERNEL_DIR=/home/cw/kernel

CUR_DIR=$(shellpwd)

all:

make-C

$(KERNEL_DIR)M=$(CUR_DIR)modulesclean:

make-C

$(KERNEL_DIR)M=$(CUR_DIR)cleaninstall:

cp-raf*.ko

$(ROOTFS_DIR)/drv_moduleelse

obj-m+=hello.oendif2、Makefile---版本23、編譯$make得到.ko下載到實驗箱中(實驗課)$fileled_drv.koled_drv.ko:ELF32-bitLSBrelocatable,ARM,EABI5version1(SYSV),BuildID[sha1]=04ff90444af056f8c1c04f119c7307950bfe16a5,notstripped$sizeled_drv.kotext data bss dec hex filename344 360 0 704 2c0 led_drv.ko$modinfoled_drv.kofilename:/mnt/hgfs/linux內(nèi)核驅(qū)動/4module/demo/led_drv.koversion:V1.0license:GPLdescription:LEDdriverforGEC6818author:bobeyfeng@163.comsrcversion:5D5F2D6C66A08F289709359depends:vermagic:3.4.39-gecSMPpreemptmod_unloadARMv7p2v8vermagic--->versionmagic(魔數(shù)):驅(qū)動可以安裝的linux版本:3.4.39-gec,其中:-gec--->localversion,配置內(nèi)核的時候ARMv7---->硬件的版本3、編譯GEC6818平臺:[root@GEC6818/]#uname-aLinuxGEC68183.4.39-gec#4SMPPREEMPTTueOct2421:09:31CST2017armv7lGNU/Linux[root@GEC6818/]#insmodled_drv.ko[292.145000]gec6818leddriverinit[root@GEC6818/]#lsmodled_drv7600-Live0xbf000000(O)

[root@GEC6818/]#rmmodled_drv.ko[364.399000]gec6818leddriverexit1)簡單方法[root@GEC6818/]#cat/proc/sys/kernel/printk

7717[root@GEC6818/]#echo7417>/proc/sys/kernel/printk

將echo7417>/proc/sys/kernel/printk寫入:/etc/profile2)printk加優(yōu)先級printk(KERN_WARNING"gec6818leddriverinit\n");printk("<4>""gec6818leddriverexit\n");3)配置linux內(nèi)核,修改優(yōu)先級--->一勞永逸(1)使用默認的配置文件bobey@ubuntu:~/6818GEC/kernel$cparch/arm/configs/GEC6818_defconfig.config(2)makemenuconfig-->配置內(nèi)核sudoapt-getupdatesudoapt-getinstalllibncurses5-dev#makemenuconfigKernelhacking--->(4)Defaultmessageloglevel(1-7)(3)保存退出(4)復(fù)制配置文件cp.configarch/arm/configs/GEC6818_defconfig(5)編譯內(nèi)核./mk-k/home/bobey/6818GEC/out/release/boot.img--->燒寫到emmc設(shè)置printk的優(yōu)先級驅(qū)動程序有入口和出口,但是應(yīng)用程序只有入口--main()五、驅(qū)動程序和應(yīng)用程序的區(qū)別編譯方法應(yīng)用程序:gcc驅(qū)動程序:使用內(nèi)核源碼包提供的頭文件、使用內(nèi)核源碼的編譯工具:Makefile驅(qū)動程序是一個個獨立的模塊。各個驅(qū)動程序之間,一般是沒有關(guān)系設(shè)計驅(qū)動程序時,只能使用內(nèi)核源碼提供的頭文件,不能使用標準的C庫:stdio.h,printf()03PARTTHERE字符設(shè)備驅(qū)動一、字符設(shè)備驅(qū)動的設(shè)計流程-------定義并初始化一個字符設(shè)備---------1、定義一個字符設(shè)備--->structcdev2、定義并初始化字符設(shè)備的文件操作集--->structfile_operations3、給字符設(shè)備申請一個設(shè)備號--->設(shè)備號=主設(shè)備號<<20+次設(shè)備號4、初始化字符設(shè)備5、將字符設(shè)備加入內(nèi)核-------自動生成設(shè)備文件---------6、創(chuàng)建class7、創(chuàng)建device,其中device是屬于class的-------得到物理地址對應(yīng)的虛擬地址-------8、申請物理內(nèi)存區(qū),申請SFR的地址區(qū)。SFR---SpecialFunctionRegister:GPIOEOUT9、內(nèi)存的動態(tài)映射,得到物理地址對應(yīng)的虛擬地址10、訪問虛擬地址二、編寫LED驅(qū)動程序1、描述字符設(shè)備的結(jié)構(gòu)體--cdev#include<linux/cdev.h>structcdev{ structkobjectkobj; --->內(nèi)核管理驅(qū)動的時候,使用的一個object structmodule*owner; --->cdev是屬于哪個module,一般寫成THIS_MODULE conststructfile_operations*ops; --->cdev的文件操作集 structlist_headlist; --->內(nèi)核管理cdev的鏈表 dev_tdev; --->設(shè)備號 unsignedintcount; --->次設(shè)備的數(shù)量};在linux內(nèi)核中,使用cdev來描述一個字符設(shè)備,每個字符設(shè)備都有一個自己的cdev。設(shè)計字符設(shè)備首先定義一個cdev。例:staticstructcdevgec6818_led_cdev;二、編寫LED驅(qū)動程序2、定義并初始化一個文件操作集(1)文件操作集#include<linux/fs.h>structfile_operations{ structmodule*owner; ............................... ssize_t(*read)(structfile*,char__user*,size_t,loff_t*); ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*); int(*mmap)(structfile*,structvm_area_struct*); int(*open)(structinode*,structfile*); int(*release)(structinode*,structfile*); long(*unlocked_ioctl)(structfile*,unsignedint,unsignedlong); ..............................}二、編寫LED驅(qū)動程序2、定義并初始化一個文件操作集(2)文件操作集的作用每個cdev都有一個文件操作集,文件操作集是驅(qū)動程序給應(yīng)用程序提供的接口。應(yīng)用程序open()會找到驅(qū)動程序的open(),驅(qū)動程序的open()可以用來訪問硬件。(3)例intgec6818_led_open(structinode*inode,structfile*filp){ return0;}ssize_tgec6818_led_read(structfile*filp,char__user*user_buf,size_tsize,loff_t*off){}ssize_tgec6818_led_write(structfile*filp,constchar__user*user_buf,size_tsize,loff_t*off){

}二、編寫LED驅(qū)動程序2、定義并初始化一個文件操作集intgec6818_led_release(structinode*inode,structfile*filp){

return0;}staticconststructfile_operationsgec6818_led_fops={ .owner=THIS_MODULE,//此處是逗號 .open=gec6818_led_open, .read=gec6818_led_read, .write=gec6818_led_write, .release=gec6818_led_release,};二、編寫LED驅(qū)動程序3、給字符設(shè)備申請一個設(shè)備號---dev_tdev(1)什么是設(shè)備號每個設(shè)備文件(字符設(shè)備or塊設(shè)備)都有一個設(shè)備號,相當于設(shè)備文件ID。設(shè)備號是一個32bits的無符號整型值,設(shè)備號有主設(shè)備號(高12位)和次設(shè)備號(低20位)組成的。 typedef__u32__kernel_dev_t; typedef__kernel_dev_t

dev_t;(2)設(shè)備號運算的函數(shù) 1)由主設(shè)備號和次設(shè)備號生成設(shè)備號 #defineMKDEV(ma,mi) (((ma)<<MINORBITS)|(mi))//MINORBITS=20 2)由設(shè)備號得到主設(shè)備號和次設(shè)備號 #defineMAJOR(dev) ((unsignedint)((dev)>>MINORBITS)) #defineMINOR(dev) ((unsignedint)((dev)&MINORMASK))二、編寫LED驅(qū)動程序3、給字符設(shè)備申請一個設(shè)備號---dev_tdev(3)主設(shè)備號和次設(shè)備號的作用

例:cd/dev---ls-l crw-rw----1rootroot204,64Jan11970ttySAC0串口0 crw-rw----1rootroot204,65Jan11970ttySAC1 crw-rw----1rootroot204,66Jan11970ttySAC2 crw-rw----1rootroot204,67Jan11970ttySAC3串口3主設(shè)備號描述一個硬件設(shè)備的類型:如uart、IIC、攝像頭、...次設(shè)備號描述這種硬件類型下的具體某個硬件/dev/sys/class/主設(shè)備號一樣,說明使用同一個類。二、編寫LED驅(qū)動程序3、給字符設(shè)備申請一個設(shè)備號---dev_tdev(4)如何申請設(shè)備號

1)靜態(tài)注冊--->指定設(shè)備號,注冊到內(nèi)核中。如果內(nèi)核已經(jīng)使用該設(shè)備號,注冊就不成功。intregister_chrdev_region(dev_tfrom,unsignedcount,constchar*name)參數(shù)說明: dev_tfrom--->注冊的設(shè)備號;如果一次注冊多個設(shè)備號,from就是注冊設(shè)備號的開始值 unsignedcount--->次設(shè)備的數(shù)量 constchar*name---->設(shè)備名稱,但不是設(shè)備文件的名字。#cat/proc/devices返回值:

成功返回0,失敗返回復(fù)數(shù)錯誤碼。例:crw-rw----1rootroot204,64Jan11970ttySAC0串口0crw-rw----1rootroot204,65Jan11970ttySAC1crw-rw----1rootroot204,66Jan11970ttySAC2crw-rw----1rootroot204,67Jan11970ttySAC3串口3register_chrdev_region(MKDEV(204,64),4,"ttySAC")//ttySAC--->設(shè)備名稱

///dev/ttySAC0--->設(shè)備文件二、編寫LED驅(qū)動程序3、給字符設(shè)備申請一個設(shè)備號---dev_tdev(4)如何申請設(shè)備號

2)動態(tài)分配--->內(nèi)核自動分配空閑的設(shè)備號intalloc_chrdev_region(dev_t*dev,unsignedbaseminor,unsignedcount,

constchar*name)參數(shù)說明: dev_t*dev --->分配后的設(shè)備號 unsignedbaseminor --->次設(shè)備號的開始值 unsignedcount --->次設(shè)備的數(shù)量 constchar*name ---->設(shè)備名稱,但不是設(shè)備文件的名字。#cat/proc/devices返回值:

成功返回0,失敗返回復(fù)數(shù)錯誤碼。

3)設(shè)備號的注銷voidunregister_chrdev_region(dev_tfrom,unsignedcount)參數(shù)說明: dev_tfrom --->注冊的設(shè)備號;如果一次注冊多個設(shè)備號,from就是注冊設(shè)備號的開始值 unsignedcount --->次設(shè)備的數(shù)量二、編寫LED驅(qū)動程序4、初始化字符設(shè)備voidcdev_init(structcdev*cdev,conststructfile_operations*fops)思考:staticstructcdevgec6818_led_cdev;//有內(nèi)存cdev_init(&gec6818_led_cdev,conststructfile_operations*fops);或:staticstructcdev*gec6818_led_cdev;//沒有內(nèi)存cdev_init(gec6818_led_cdev,conststructfile_operations*fops);//segmentfaultok:staticstructcdev*gec6818_led_cdev;gec6818_led_cdev=(structcdev*)kmalloc(sizeof(structcdev),GFP_KERNEL)if(gec6818_led_cdev==NULL){

}cdev_init(gec6818_led_cdev,conststructfile_operations*fops);//segmentfault二、編寫LED驅(qū)動程序5、將字符設(shè)備加入內(nèi)核(1)字符設(shè)備加入到內(nèi)核intcdev_add(structcdev*p,dev_tdev,unsignedcount)參數(shù): structcdev*p--->定義初始化好的字符設(shè)備 dev_tdev--->設(shè)備號 unsignedcount--->次設(shè)備的數(shù)量返回值:

錯誤返回錯誤碼(2)

從內(nèi)核中移除字符設(shè)備voidcdev_del(structcdev*p)二、編寫LED驅(qū)動程序6、創(chuàng)建class

創(chuàng)建class和device的目的是在安裝的驅(qū)動的時候,可以自動生成設(shè)備文件,在卸載驅(qū)動的時候,可以自動的刪除設(shè)備文件。

如果不自動生成設(shè)備文件:也可以手動創(chuàng)建:#mkmodc/dev/led_drv主設(shè)備號

次設(shè)備號

創(chuàng)建的class生成在:/sys/class/#include<linux/device.h>(1)創(chuàng)建classstructclass*class_create(structmodule*owner,constchar*name)參數(shù)說明: structmodule*owner--->創(chuàng)建的class屬于哪個module,一般為THIS_MODULE。 constchar*name--->自定義的class的名字返回值:

得到的class(2)class的刪除voidclass_destroy(structclass*cls);二、編寫LED驅(qū)動程序7、創(chuàng)建devicedevice是輸于class的,當驅(qū)動程序有了class和device以后,內(nèi)核使用mdev這個工具,根據(jù)class和device創(chuàng)建該驅(qū)動的設(shè)備文件。創(chuàng)建的device怎么查看:/sys/class/***/#include<linux/device.h>(1)創(chuàng)建devicestructdevice*device_create(structclass*class,structdevice*parent,dev_tdevt,void*drvdata,constchar*fmt,...)參數(shù)說明: structclass*class --->device屬于哪個class structdevice*parent --->device的父設(shè)備,一般為NULL dev_tdevt --->設(shè)備號 void*drvdata --->驅(qū)動的data,一般為NULL constchar*fmt --->設(shè)備文件的名字返回值: structdevice* --->創(chuàng)建好的device(2)刪除devicevoiddevice_destroy(structclass*class,dev_tdevt)二、編寫LED驅(qū)動程序8、申請物理內(nèi)存區(qū)回憶:裸機控制硬件的流程:

分析原理圖-->找到控制硬件的GPIO-->找GPIO的寄存器--->分析寄存器--->理解寄存器的控制順序--->通過寄存器的地址來訪問該寄存器注意:裸機使用的是物理地址,所以直接使用CPU手冊查到的地址可以編程。linux驅(qū)動使用的虛擬地址,不能直接使用物理地址。想辦法,如果通過CPU手冊查到的物理地址找到其對應(yīng)虛擬地址???一般分成兩個過程:

申請物理地址區(qū)作為一個資源----->將物理內(nèi)存區(qū)做內(nèi)存的動態(tài)映射,得到虛擬地址。注意:

資源---有限的,一旦一個物理內(nèi)存區(qū)已經(jīng)申請了,后面就不能再次申請。二、編寫LED驅(qū)動程序8、申請物理內(nèi)存區(qū)(1)申請物理內(nèi)存區(qū)作為資源structresource*request_mem_region(resource_size_tstart,resource_size_tn, constchar*name)參數(shù)說明: resource_size_tstart --->物理內(nèi)存區(qū)的開始地址 resource_size_tn --->物理內(nèi)存區(qū)的大小 constchar*name --->自定義的物理內(nèi)存區(qū)的名字返回值: structresource* --->物理內(nèi)存區(qū)作為了資源思考:LED驅(qū)動,申請哪個物理內(nèi)存區(qū)??? D8-->GPIOC17,D9-->GPIOC8,D10-->GPIOC7,D11-->GPIOC12 startaddress --->0xC001C000 addresssize --->結(jié)束地址:0xC001CFFF,大?。?x1000 name --->"GPIOC_MEM"(2)釋放申請的物理內(nèi)存區(qū)voidrelease_mem_region(resource_size_tstart,resource_size_tn)二、編寫LED驅(qū)動程序9、io內(nèi)存動態(tài)映射,得到虛擬地址#include<linux/io.h>(1)IO內(nèi)存動態(tài)映射

將一段物理地址內(nèi)存區(qū)映射成一段虛擬地址內(nèi)存區(qū)void__iomem*ioremap(phys_addr_toffset,unsignedlongsize)參數(shù)說明: phys_addr_toffset --->要映射的物理內(nèi)存區(qū)開始地址 unsignedlongsize --->物理內(nèi)存區(qū)的大小返回值: void__iomem* --->映射后,虛擬地址內(nèi)存區(qū)的首地址(2)解除IO內(nèi)存動態(tài)映射voidiounmap(void__iomem*addr)二、編寫LED驅(qū)動程序10、使用虛擬地址(1)得到虛擬地址 gpioc_base_va=ioremap(phys_addr_toffset,unsignedlongsize) if(gpioc_base_va==NULL){ printk("ioremaperror\n"); release_mem_region(0xC001C000,0x1000); device_destroy(leds_class,led_num); class_destroy(leds_class); cdev_del(&gec6818_led_cdev); unregister_chrdev_region(led_num,1); return-EBUSY; } //得到每個寄存器的虛擬地址 gpiocout_va=gpioc_base_va+0x00; gpiocoutenb_va=gpioc_base_va+0x04; gpiocaltfn0_va=gpioc_base_va+0x20; gpiocaltfn1_va=gpioc_base_va+0x24; gpiocpad_va=gpioc_base_va+0x18;二、編寫LED驅(qū)動程序10、使用虛擬地址(2)虛擬地址的類型:void__iomem*(3)訪問虛擬地址的方法:與訪問物理地址的方法一樣 //10.訪問虛擬地址 //10.1GPIOC7,8.12,17--->function1,作為普通的GPIO

*(unsignedint*)gpiocaltfn0_va&=~((3<<14)|(3<<16)|(3<<24)); *(unsignedint*)gpiocaltfn1_va&=~(3<<2); *(unsignedint*)gpiocaltfn0_va|=((1<<14)|(1<<16)|(1<<24)); *(unsignedint*)gpiocaltfn1_va|=(1<<2); //10.2GPIOC7,8.12,17--->設(shè)置為輸出

*(unsignedint*)gpiocoutenb_va|=((1<<7)|(1<<8)|(1<<12)|(1<<17)); //10.3GPIOC7,8.12,17--->設(shè)置為輸出高電平,D8~D11off

*(unsignedint*)gpiocout_va|=((1<<7)|(1<<8)|(1<<12)|(1<<17));(4)虛擬地址的訪問方法:使用內(nèi)核提供的函數(shù)u32readl(constvolatilevoid__iomem*addr)voidwritel(u32b,volatilevoid__iomem*addr)或者:void__raw_writel(u32b,volatilevoid__iomem*addr)u32__raw_readl(constvolatilevoid__iomem*addr)三、常見錯誤碼#include<linux/errno.h>#define EPERM 1 /*Operationnotpermitted*/#define ENOENT

2 /*Nosuchfileordirectory*/#define ESRCH 3 /*Nosuchprocess*/#define EINTR 4 /*Interruptedsystemcall*/#define EIO 5 /*I/Oerror*/#define ENXIO 6 /*Nosuchdeviceoraddress*/#define E2BIG 7 /*Argumentlisttoolong*/#define ENOEXEC 8 /*Execformaterror*/#define EBADF 9 /*Badfilenumber*/#define ECHILD 10 /*Nochildprocesses*/#define EAGAIN 11 /*Tryagain*/#define ENOMEM 12 /*Outofmemory*/#define EACCES 13 /*Permissiondenied*/#define EFAULT 14 /*Badaddress*/#define ENOTBLK 15 /*Blockdevicerequired*/#define EBUSY 16 /*Deviceorresourcebusy*/#define EEXIST 17 /*Fileexists*/三、常見錯誤碼#define EXDEV 18 /*Cross-devicelink*/#define ENODEV 19 /*Nosuchdevice*/#define ENOTDIR 20 /*Notadirectory*/#define EISDIR 21 /*Isadirectory*/#define EINVAL 22 /*Invalidargument*/#define ENFILE 23 /*Filetableoverflow*/#define EMFILE 24 /*Toomanyopenfiles*/#define ENOTTY 25 /*Notatypewriter*/#define ETXTBSY 26 /*Textfilebusy*/#define EFBIG 27 /*Filetoolarge*/#define ENOSPC 28 /*Nospaceleftondevice*/#define ESPIPE 29 /*Illegalseek*/#define EROFS 30 /*Read-onlyfilesystem*/#define EMLINK 31 /*Toomanylinks*/#define EPIPE 32 /*Brokenpipe*/#define EDOM 33 /

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論