1.準備工作
? 首先得安裝好gcc工具鏈,以及開發環境,可以看看我的前面的幾步。
?? 還得編譯好內核,一般開發板都帶了,現在我還不知道配置內核,只能按照開發板默認的去編譯,編譯前需要先編譯uboot,建議像我一樣的新手先學會驅動編寫,慢慢的去學習 內核的配置裁剪,我覺得到時候這個肯定是非常簡單的過程,只不過沒有找到門道而已,等我會了一定和大家分享,如果有會的可以教我一下,在下感激不盡。
我的嵌入式內核編譯的路徑為:/home/cfan/linux/linux-3.0.1/? ,這個待會會用到的。
今天我就教大家使用eclipse開發一個最簡單的驅動程序,LED驅動,其實使用eclipse編譯這種簡單的驅動可能顯得有點麻煩,如果是大工程我想集成開發環境的優勢就會體現出來了,還有就是eclipse的編輯器界面比較友好,跟RVDS4.0一樣。
2.建立驅動工程,設置eclipse
?打開eclipse
?可以在桌面上面建立一個指向eclipse的快捷鍵,或者到eclipse的目錄執行 ./eclipse 即可啟動,我設置了eclipse的全局變量,因此只需要在終端中輸入eclipse即可啟動,如下圖
建議將工程目錄選擇在NFS共享的那個目錄,這樣方便從開發板加載驅動或者執行程序,我的就選擇在nfs6410這個共享目錄里面。
新建一個C項目,空項目
一直下一步,直到下圖位置,填好自己的arm-linux-gcc的路徑。
設置完成后點擊完成。
到這一步新建工程完成了,此時還有重要的一部要做,先別急著添加.c文件。在工程上面右鍵,屬性,到 C/C++常規---->Code Analysis---->路徑和符號
點擊下方ExportSettings,將設置導出為xml文件.我的道出到桌面上面了,這個大家隨意
點擊確定 應用 退出即可。
到你剛才保存的位置處打開那個.xml文件,用文本編輯器打開即可,我的在桌面上面,右鍵單擊,使用文本編輯器打開
現在我們還需要將autoconf.h中的宏定義加入到Eclipse中,執行如下步驟
打開內核的這個目錄 include/generated/ 這個按個人實際情況而定,我的是 cd /home/cfan/linux/linux-3.0.1/include/generated/ ,另外打開一個終端 cd到這個目錄
在剛剛這個終端中執行
[cpp]?view plaincopy
cat?autoconf.h?|grep?define?|awk?'{print?"<macro><name>"?$2?"</name><value>"?$3?"</value></macro>"}'?>?symbol.xml??
此時打開這個目錄/home/cfan/linux/linux-3.0.1/include/generated,會多了一個文件
將 symbol.xml這個文件用文本編輯器打開
此時文本編輯器里面打開了兩個xml文件了,將之前導出eclipse的那個xml文件打開,需要添加一行代碼,在這兩行代碼之間(如果有兩個,是下面的那個)
[html]?view plaincopy
<language?name="C?源文件">?? ?? ?? ?? </language>??
添加
[html]?view plaincopy
<macro><name>__KERNEL__</name><value>1</value></macro>??
如下圖
添加后
再將剛剛那個symbol.xml文件里面的所有代碼復制到
[html]?view plaincopy
<macro><name>__KERNEL__</name><value>1</value></macro>??
這行的下一行,如下圖
在上面的一個
[html]?view plaincopy
<language?name="C?源文件">?? ?? ?? ?? </language>??
添加
[cpp]?view plaincopy
<includepath>/home/cfan/linux/linux-3.0.1/include</includepath>?? <includepath>/home/cfan/linux/linux-3.0.1/arch/arm/include</includepath>?? <includepath>/home/cfan/linux/linux-3.0.1/arch/arm/plat-samsung/include</includepath>?? <includepath>/home/cfan/linux/linux-3.0.1/arch/arm/mach-s3c64xx/include</includepath>??
這里面的路徑要看自己實際的內核路徑進行修改,也可以在工程屬性中一個一個的添加,就是添加一個linux有關的路徑而已。
保存退出即可。
再打開eclipse的剛剛那個導出的位置,現在將導出的文件導入即可
點擊完成即可,如果導入出問題了,仔細對照我的教程。應用,退出即可,導入后會多了幾個路徑,內核目錄里面的頭文件路徑
然后新建一個.c文件
代碼是之前寫的
[cpp]?view plaincopy
? ? ? ? ? ? ? ?? ?? ?? #include?<linux/miscdevice.h>?? #include?<linux/delay.h>?? #include?<asm/irq.h>?? #include?<mach/hardware.h>?? #include?<linux/kernel.h>?? #include?<linux/module.h>?? #include?<linux/init.h>?? #include?<linux/mm.h>?? #include?<linux/fs.h>?? #include?<linux/types.h>?? #include?<linux/delay.h>?? #include?<linux/moduleparam.h>?? #include?<linux/slab.h>?? #include?<linux/errno.h>?? #include?<linux/ioctl.h>?? #include?<linux/cdev.h>?? #include?<linux/string.h>?? #include?<linux/list.h>?? #include?<linux/pci.h>?? #include?<asm/uaccess.h>?? #include?<asm/atomic.h>?? #include?<asm/unistd.h>?? ?? #include?<mach/map.h>?? #include?<mach/regs-clock.h>?? #include?<mach/regs-gpio.h>?? ?? #include?<plat/gpio-cfg.h>?? #include?<mach/gpio-bank-e.h>?? #include?<mach/gpio-bank-m.h>?? ?? ?? ?? ?? #define?DEVICE_NAME?"OK6410_LED"?? ?? ?? ?? static?long?OK6410_LED_ioctl(?? ????????struct?file?*file,?? ????????unsigned?int?cmd,?? ????????unsigned?long?arg);?? static?ssize_t?OK6410_LED_write(?? ????????struct?file?*file,?? ????????const?char?__user?*buff,?? ????????size_t?size,?? ????????loff_t?*loff);?? static?ssize_t?OK6410_LED_read(?? ????????struct?file?*file,?? ????????char?__user?*buff,?? ????????size_t?size,?? ????????loff_t?*loff);?? ?? ?? ?? ? ? ? ?? static?struct?file_operations?dev_fops?=?{?? ????????.owner??????????????=?THIS_MODULE,???????? ????????.unlocked_ioctl?????=?OK6410_LED_ioctl,?? ????????.read???????????????=?OK6410_LED_read,?? ????????.write??????????????=?OK6410_LED_write?? };?? ?? ?? static?struct?miscdevice?misc?=?{?? ????????.minor?=?MISC_DYNAMIC_MINOR,?? ????????.name?=?DEVICE_NAME,?????????????????????????? ????????.fops?=?&dev_fops,?? };?? ?? ?? struct?semaphore?led_sem;?? ?? ?? ? ? ? ? ? ? ? ? ? ? ?? static?int??__init?OK6410_LED_init(void)?? {?? ????int?ret;?? ????unsigned?int?reg;?? ?? ?????? ????reg?=?readl(S3C64XX_GPMCON);?????? ????reg?&=?(~0xffff);????????????????????? ????reg?|=?0x1111;???????????????????? ????writel(reg,S3C64XX_GPMCON);??????? ????reg?=?readl(S3C64XX_GPMDAT);?????? ????reg?|=?0xf;?? ????writel(reg,S3C64XX_GPMDAT);??????? ?? ????ret?=?misc_register(&misc);??????? ????if(ret?<?0)?? ????{?? ????????printk(DEVICE_NAME?"?can't?initialized?LED!\n");?? ????????return?ret;?? ????}?? ????init_MUTEX(&led_sem);????????????? ????printk(DEVICE_NAME?"?initialized\n");?? ????return?0;????????????????????????????? }?? ?? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? static?long?OK6410_LED_ioctl(?? ????????struct?file?*file,?? ????????unsigned?int?cmd,?? ????????unsigned?long?arg)?? {?? ????return?0;?? }?? ?? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? static?ssize_t?OK6410_LED_write(?? ????????struct?file?*file,?? ????????const?char?__user?*buff,?? ????????size_t?size,?? ????????loff_t?*loff)?? {?? ????unsigned?int?reg;?? ?? ????if(down_interruptible(&led_sem))?????? ????????return?-ERESTARTSYS;?? ????reg?=?readl(S3C64XX_GPMDAT);?? ????reg?&=?(~0xf);?? ????reg?|=?buff[0]?&?0xf;?? ????writel(reg,S3C64XX_GPMDAT);?? ????up(&led_sem);????????????????????????????? ?? ????return?0;?? }?? ?? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? static?ssize_t?OK6410_LED_read(?? ????????struct?file?*file,?? ????????char?__user?*buff,?? ????????size_t?size,?? ????????loff_t?*loff)?? {?? ????unsigned?int?reg;?? ?? ????if(down_interruptible(&led_sem))?????? ????????return?-ERESTARTSYS;?? ????reg?=?readl(S3C64XX_GPMDAT);?? ????buff[0]?=?reg?|?0xfffffff0;?? ????up(&led_sem);????????????????????????????? ?? ????return?0;?? }?? ?? ?? ?? ? ? ? ? ? ? ? ? ? ? ?? static?void?__exit?OK6410_LED_exit(void)?? {?? ????unsigned?int?reg;?? ?? ?????? ????reg?=?readl(S3C64XX_GPMCON);?????? ????reg?&=?(~0xffff);????????????????????? ????writel(reg,S3C64XX_GPMCON);??????? ????misc_deregister(&misc);??????????? }?? ?? ?? ?? ?? module_init(OK6410_LED_init);?? module_exit(OK6410_LED_exit);?? ?? MODULE_AUTHOR("cp1300@139.com");?????????????????????????? MODULE_DESCRIPTION("OK6410(S3C6410)?LED?Driver");????? MODULE_LICENSE("GPL");????
此時會有警告,不管他。
在工程屬性中將自動生成makefile選項去掉
3.新建一個makefile文件修改makefile,編譯驅動文件
[cpp]?view plaincopy
ARCH=arm?? CROSS_COMPILE=arm-linux-?? obj-m?:=?led.o?? KDIR?:=/home/cfan/linux/linux-3.0.1??? PWD?:=$(shell?pwd)?? all:?? ????$(MAKE)?-C?$(KDIR)?M=$(PWD)?modules?? clean:?? ????$(MAKE)?-C?$(KDIR)?M=$(PWD)?clean??
led.o文件就是你的編譯文件的名稱,按照自己實際情況修開
保存后按 ctrl+B編譯工程。
完成后會發現目錄里面多了一個led.ko,這就是編譯好的LED驅動模塊。
4.加載驅動
在開發板上面加載驅動,沒有NFS的童鞋將led.ko復制到開發板中,不管是SD卡還是U盤,有NFS的就好辦了,在串口終端中CD到工程目錄
執行 insmod led.ko 加載驅動,加載成功后會發現LED燈都滅了,后面會添加這個驅動的測試程序
到這里使用eclipse編寫驅動就完成了,新手肯定會覺得太繁瑣,其實一共就三步,只不過我寫的比較詳細而已,以后每次建立工程可以直接復制工程或者導入之前的那個xml文件皆可,麻煩也之麻煩這一次,希望對大家有所幫助。
5.附加,解決OK6410驅動無法卸載問題。
?在嵌入式驅動開發過程中需要頻繁的加載卸載驅動,但是使用rmmod的時候你會發現,驅動無法卸載,如 rmmod led,卸載的時候不需要.ko,直接是模塊名,我的寫錯了。
這個可以看我的這篇文章:http://blog.csdn.net/cp1300/article/details/7994014
解決后就可以卸載驅動了。
總結
以上是生活随笔為你收集整理的使用eclipse集成开发环境开发第一个嵌入式Linux驱动的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。