基于linux的led驅(qū)動程序?qū)崿F(xiàn)_第1頁
基于linux的led驅(qū)動程序?qū)崿F(xiàn)_第2頁
基于linux的led驅(qū)動程序?qū)崿F(xiàn)_第3頁
基于linux的led驅(qū)動程序?qū)崿F(xiàn)_第4頁
基于linux的led驅(qū)動程序?qū)崿F(xiàn)_第5頁
已閱讀5頁,還剩2頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、基于linux的led驅(qū)動程序?qū)崿F(xiàn)一. 博創(chuàng)開發(fā)平臺硬件LED的實現(xiàn)博創(chuàng)開發(fā)平臺設(shè)置了3個GPIO控制的LED和一個可直接產(chǎn)生外部硬件中斷的按鍵,LED分別使用了S3C2410的GPC5,GPC6,GPC7三個GPIO,按鍵接到INT5中斷。下面對S3C2410 GPIO的各個寄存器作出說明,用GPIO控制的LED就是通過操作GPIO的各個寄存器進行配置和操作的。S3C2410包含GPA 、GPB 、GPH 八個I/O端口。它們的寄存器是相似的:GPxCON用于設(shè)置端口功能(00 表示輸入、01表示輸出、10 表示特殊功能、11 保留不用),GPxDAT 用于讀/寫數(shù)據(jù),GPxUP 用于決定是

2、否使用內(nèi)部上拉電阻(某位為0 時,相應(yīng)引腳無內(nèi)部上拉;為1時,相應(yīng)引腳使用內(nèi)部上拉)。這里要稍微注意一點的地方是PORTA和其他幾組端口的使用不太一樣,這里不討論A口,B到H組口的使用完全相同。以下是S3C2410手冊上的數(shù)據(jù)13:圖1.1 S3C2410端口GPC口有16個IO口,查datasheetS3C2410所用的地址為:圖1.2 C組GPIO的地址即GPCCON 地址為0x56000020, GPCDAT地址為0x56000024,各位的設(shè)置具體見下圖,則對應(yīng)的GPCCON寄存器的位為:圖1.3 GPCCON寄存器相應(yīng)的位這里用到了5,6,7三個口,CON寄存器要完成對對應(yīng)口的設(shè)置工

3、作,將相應(yīng)的口設(shè)置為輸出狀態(tài),其他的口不用考慮,設(shè)置為輸出的話就是 0x15<<10,這樣3個IO口就設(shè)置為了輸出。下面就可以通過向DATA口寫入低電平來點亮LED,GPCDAT的各位分布如下,每一個bit對應(yīng)一個口。圖1.4 GPCDAT的位分布GPCDAT有16位,我們這里要用到的就是5,6,7三位即將這3位設(shè)置為低電平點亮LED。具體使用情況見驅(qū)動的實現(xiàn)。這三個LED的硬件原理圖如下:圖1.5 GPIO控制的LED硬件原理圖二通過GPIO控制的LED驅(qū)動程序本驅(qū)動中沒有用到內(nèi)核提供的write_gpio宏,對硬件地址的操作完全自己實現(xiàn),可分為以下幾部分:模塊的初始化和退出:i

4、nt led_init(void)int ret;ret=register_chrdev(MAJOR_LED,NAME,&leds_fops);port_addr= (unsigned long )ioremap(0x56000020,0x8);if(ret<0)goto fail;printk(KERN_INFO NAME"initialized!n");return 0;fail:printk(NAME"Can not register major number %d!n",MAJOR_LED);unregister_chrdev(MA

5、JOR_LED,NAME);return ret;void led_exit(void)iounmap(port_addr);printk(KERN_INFO NAME"quit!n");unregister_chrdev(MAJOR_LED,NAME);module_init(led_init);module_exit(led_exit);module_init和module_exit為內(nèi)核提供的接口,以模塊方式插入到內(nèi)核中時內(nèi)核首先要找的就是這兩個宏,找到對應(yīng)的初始函數(shù)這里為led_init初始化模塊,和卸載函數(shù)這里為led_exit當(dāng)模塊撤出內(nèi)核時調(diào)用。這兩個函數(shù)名稱

6、可以自己定義,但是module_init這個兩個宏的名字不能改變,并且led_init的返回值類型必須為int型,led_exit的返回類型必須為空。這兩個函數(shù)只是告訴內(nèi)核驅(qū)動模塊在內(nèi)核中了,但并不一定在使用它,而open和release是當(dāng)設(shè)備被打開和關(guān)閉的時候才回被調(diào)用,模塊不會退出內(nèi)核。初始化函數(shù)led_init中主要完成的工作為:注冊設(shè)備號和文件操作結(jié)構(gòu);映射內(nèi)存地址空間;做出一定的錯誤處理。設(shè)備注冊的工作由register_chrdev來完成,如果返回值是負(fù)值表示錯誤,0或者返回值為正值表示操作成功,其中MAJOR_LED為靜態(tài)申請的主設(shè)備號定義為#define MAJOR_LED

7、237,NAME為設(shè)備的名稱定義為#define NAME "leds",leds_fops為file_operations類結(jié)構(gòu)體定義如下:static struct file_operations leds_fops=owner:THIS_MODULE,open: led_open,release:led_close,ioctl: led_ioctl,;可以看出,此設(shè)備驅(qū)動要完成的工作只是簡單的打開(open)、關(guān)閉(release)、通過應(yīng)用程序傳參數(shù)來控制LED(ioctl)。各函數(shù)的具體實現(xiàn)下面講解。port_addr= (unsigned long )iorem

8、ap(0x56000020,0x8);完成物理地址到虛擬地址的映射,前面已經(jīng)提到,linux系統(tǒng)只認(rèn)虛擬地址而不人物理地址,所以利用這個內(nèi)核API來完成映射,0x56000020是GPCCON寄存器的物理地址,這個可以通過圖4.3知道,0x8表示從上面那個物理地址開始的8個字節(jié)的地址空間要映射到內(nèi)核虛擬地址空間,這個空間中包括了GPCDAT寄存器,可以通過返回的地址加4得到,這個返回的虛地址存放在port_addr中,以后對硬件的操作都是通過對這個地址的操作實現(xiàn)的。地址定義格式如下:#defineGPC_CON (*(volatile unsigned long *)port_addr)#de

9、fine GPC_DAT (*(volatile unsigned long *)(port_addr+0x4)這里將地址定義為long類型,是因為ARM為4字節(jié)對齊方式,并且GPCCON寄存器為32位,所以下面GPCDAT寄存器地址直接加4就可以訪問到了,并且ARM寄存不支持直接對字中字節(jié)進行直接訪問,這需要使用專門的訪問函數(shù)。Led_init中還做了簡單的錯誤處理,如果注冊失敗則解除注冊并且返回。模塊卸載函數(shù)只是做了解除工作,即釋放主設(shè)備號,并且解除地址映射。接口函數(shù)的實現(xiàn):static int led_open(struct inode *inode,struct file *filp)

10、GPC_CON=GPC5_OUT|GPC6_OUT|GPC7_OUT;printk("major number %dn",inode->i_rdev);printk(NAME"open success!n");return 0;static int led_close(struct inode *inode,struct file *filp)printk(NAME"release!n");return 0;static int led_ioctl(struct inode *inode,struct file *filp,un

11、signed int cmd,unsigned long arg)switch(cmd)case 0:if(arg>3)return -EINVAL;GPC_DAT=LED1_OFF|LED2_OFF|LED3_OFF;break;case 1:if(arg>3)return -EINVAL;GPC_DAT=LED1_ON&LED2_ON&LED3_ON;break;default:return -EINVAL;return 0;以上函數(shù)的接口集合在file_operations結(jié)構(gòu)中,實現(xiàn)了系統(tǒng)提供給用戶程序的接口。Open函數(shù)在file_operations結(jié)構(gòu)

12、中的原型為 int (* open)(struct inode *,struct file *);這是設(shè)備的第一個操作,但是并不是要求驅(qū)動程序必須去實現(xiàn)這個方法,如果這個入口為NULL,那么設(shè)備的打開操作將永遠成功,一般驅(qū)動程序中open要完成的工作有:增加使用計數(shù);檢查設(shè)備特定的錯誤;如果設(shè)備是首次打開,則對其進行初始化;識別次設(shè)備號,并且如果必要,更新f_op指針;分配并填寫被置于filp->private_data里的數(shù)據(jù)結(jié)構(gòu)。我的理解是,open函數(shù)就是要完成設(shè)備驅(qū)動和文件系統(tǒng)的關(guān)聯(lián),上面已經(jīng)講過file和inode兩個結(jié)構(gòu)的關(guān)系,這里參數(shù)中的兩個結(jié)構(gòu)正是系統(tǒng)在/dev創(chuàng)建設(shè)備節(jié)

13、點后提供給驅(qū)動的文件結(jié)構(gòu)。本驅(qū)動中的open實現(xiàn)只是完成了對C組GPIO的GPC_CON寄存器進行初始化,將3個LED對應(yīng)的3個口設(shè)置為輸出模式,定義格式如下:GPC_CON=GPC5_OUT|GPC6_OUT|GPC7_OUT;其中GPCX_OUT的定義為:#define GPC5_OUT(1<<(5*2)#define GPC6_OUT(1<<(6*2)#define GPC7_OUT(1<<(7*2)具體的位模式可以查看圖1.3,這樣要設(shè)置后的寄存器內(nèi)容為010101,這樣就將3個口設(shè)置為輸出模式了。Open剩下的工作就是打印設(shè)備號。Release函數(shù)

14、即驅(qū)動中的close函數(shù)要完成的工作就是:釋放由open分配的、保存在filp->private_data中的所有內(nèi)容;在最后一次關(guān)閉操作時關(guān)閉設(shè)備;使用計數(shù)器減1。這里和上面的open函數(shù)都提到了一個模塊計數(shù),意思就是內(nèi)核要統(tǒng)計這個模塊被打開的次數(shù),這樣才不會在還有使用的情況下卸載模塊,在早期的linux版本中,模塊計數(shù)的工作要由驅(qū)動程序自己完成,用到類似于MOD_INC_USE_COUNT的宏來實現(xiàn),現(xiàn)在的內(nèi)核版本是內(nèi)核自動維護這個計數(shù),不用在驅(qū)動中實現(xiàn),所以本驅(qū)動中的release函數(shù)并沒有實現(xiàn)具體的操作。Ioctl在接口結(jié)構(gòu)中的原型為:int (* ioctl)(struct i

15、node *,struct file *,unsigned int, unsigned long);為用戶程序的ioctl系統(tǒng)調(diào)用提供了一種執(zhí)行設(shè)備特定命令的方法(即讀寫之外的操作),并且,內(nèi)核還能識別一部分ioctl命令,而不必調(diào)用fops表中的ioctl。如果設(shè)備不提供ioctl入口點,則對于任何內(nèi)核未定義的請求,ioctl系統(tǒng)調(diào)用將返回錯誤,如果該設(shè)備方法返回一個非負(fù)值,那么相同的值會被調(diào)用返回給調(diào)用程序以表示調(diào)用成功。本驅(qū)動中的關(guān)鍵部分就是這個函數(shù)。用戶空間系統(tǒng)調(diào)用ioctl的原型為:Int ioctl(int fd , int cmd, );Inode 和file兩個指針的值對應(yīng)于應(yīng)

16、用程序所傳遞的文件描述符fd,參數(shù)cmd會不經(jīng)修改地傳遞給驅(qū)動程序,可選參數(shù)無論是指針還是整數(shù)都以unsigned long的形式被傳遞給驅(qū)動程序,其實, ioctl實現(xiàn)的是一種switch語句選擇功能。本驅(qū)動中此函數(shù)的功能為接受用戶程序傳下來的命令cmd和arg參數(shù),然后選擇命令對應(yīng)的操作。Cmd參數(shù)在用戶空間對應(yīng)0或1,表示LED的亮還是滅,arg可以用來選擇是哪個LED,但是在本驅(qū)動中沒有使用,無論哪個LED都是對全部LED的操作。以下是關(guān)操作:GPC_DAT=LED1_OFF|LED2_OFF|LED3_OFF;其中LEDx_OFF的定義為:#define LED1_OFF(1<

17、<5)#define LED2_OFF(1<<6)#define LED3_OFF(1<<7)這樣DAT中對應(yīng)的位就被設(shè)置為1即高電平LED滅。以下是開操作:GPC_DAT=LED1_ON&LED2_ON&LED3_ON;其中LEDx_ON的定義為:#define LED1_ON(1<<5)#define LED2_ON(1<<6)#define LED3_ON(1<<7)這樣DAT中對應(yīng)的位就被設(shè)置為0即低電平LED亮。三對于GPIO LED的測試App_gpio.c實現(xiàn)的功能為通過命令行參數(shù)控制LED的亮滅,這里要說明的一點是由于測試程序主要是完成的測試驅(qū)動是否正常工作的事情,所以測試程序中對某個LED選擇的參數(shù)實際上是沒作用的,不管針對哪個LED都是對全部的LED進行操作的。代碼的具體實現(xiàn)見附錄,這里只做簡單

溫馨提示

  • 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)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論