生活随笔
收集整理的這篇文章主要介紹了
树莓派linux驱动学习之LED控制
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
? ? ? ? 前面我們編寫了hello world的程序,接下來繼續(xù)研究GPIO功能,通過GPIO來控制LED的亮滅,這在單片機(jī)中應(yīng)該算是十分簡(jiǎn)單的一個(gè)程序了,但是在Linux系統(tǒng)中控制GPIO沒有那么簡(jiǎn)單,難點(diǎn)就在于GPIO地址的獲取,也是我一直在糾結(jié)的問題。
一、GPIO地址
? ? ? ? 我看了中嵌的嵌入式開發(fā)視頻,里面使用三星2440控制LED的亮滅,但是驅(qū)動(dòng)程序中沒有寫清楚具體的底層是如何實(shí)現(xiàn)的,這也是我查找的重點(diǎn)。我首先翻閱了樹莓派CPU(bcm2835)的芯片手冊(cè),查到了GPIO的物理地址:
? ? ? ? 但是在芯片資料的最開始,有提到芯片內(nèi)部已經(jīng)把上圖中的物理總線地址抽象到了面對(duì)操作系統(tǒng)的物理地址:
? ? ? ? 所以,我們?cè)诰帉戲?qū)動(dòng)程序的時(shí)候,IO空間的起始地址是0x20000000,加上GPIO的偏移量2000000,所以GPIO的物理地址應(yīng)該是從0x20200000開始的,然后在這個(gè)基礎(chǔ)上進(jìn)行Linux系統(tǒng)的MMU內(nèi)存虛擬化管理,銀蛇到虛擬地址上。
二、硬件平臺(tái)
? ? ? ? 我在樹莓派的擴(kuò)展口的GPIO 17上接上了一個(gè)LED:
三、編寫驅(qū)動(dòng)代碼
? ? ? ? 一般的設(shè)備驅(qū)動(dòng)我們需要設(shè)置主設(shè)備號(hào)和次設(shè)備號(hào),在編寫應(yīng)用程序的時(shí)候還要生成設(shè)備文件,比較麻煩。Linux針對(duì)像LED這樣的操作,有一種設(shè)備叫做混雜設(shè)備:是一種特殊的字符設(shè)備,雜設(shè)備早已經(jīng)存在,是為了給開發(fā)者一個(gè)較為簡(jiǎn)單的操作方式,因?yàn)椴挥迷僦匦律暾?qǐng)一個(gè)設(shè)備號(hào)了(misc就是混雜設(shè)備的意思)。
? ? ? ? 驅(qū)動(dòng)代碼:
[cpp]?view plaincopy
#include?<linux/miscdevice.h>?? #include?<linux/delay.h>?? #include?<asm/irq.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?<asm/io.h>?? #include?<asm/uaccess.h>?? #include?<linux/ioport.h>?? ?? #include?"bcm2835.h"?? ?? ?? #define?PIN?RPI_GPIO_P1_11?? ?? int?open_state?=?0;??????????? ?? static?int?leds_open(struct?inode?*inode,?struct?file?*filp)?? {?? ????if(open_state?==?0)???? ????{???? ????????open_state?=??1;???? ????????printk("Open?file?suc!\n");???? ????????return?0;???? ????}???? ????else???? ????{???? ????????printk("The?file?has?opened!\n");???? ????????return?-1;???? ????}???? }?? ?? static?int?leds_ioctl(struct?file*filp,?unsigned?int?cmd,?unsigned?long?arg)?? {?? ????switch(cmd)???? ????{???? ????????case?0:???? ????????????bcm2835_gpio_clr(PIN);?? ????????????printk("LED?OFF!\n");?? ????????????break;???? ????????case?1:???? ????????????bcm2835_gpio_set(PIN);?? ????????????printk("LED?ON!\n");?? ????????????break;???? ?? ????????default:???? ????????????return-EINVAL;???? ????}???? ?? ????return?0;?? }?? ?? static?int?leds_release(struct?inode?*inode,?struct?file?*filp)?? {?? ????if(open_state?==?1)???? ????{???? ????????open_state?=??0;???? ????????printk("close?file?suc!\n");???? ????????return?0;???? ????}???? ????else???? ????{???? ????????printk("The?file?has?closed!\n");???? ????????return?-1;???? ????}???? }?? ?? static?const?struct?file_operations?leds_fops?=?{?? ????.owner?=?THIS_MODULE,?? ????.open?=?leds_open,?? ????.unlocked_ioctl?=?leds_ioctl,?? ????.release?=?leds_release,?? };?? ?? static?struct?miscdevice?misc?=?{?? ????.minor?=MISC_DYNAMIC_MINOR,?? ????.name?="my_leds",?? ????.fops?=&leds_fops,?? };?? ?? ?? static?int?__init?leds_init(void)?? {?? ????int?ret;?? ?? ?????? ????ret?=misc_register(&misc);?? ?? ?????? ????bcm2835_gpio_fsel(PIN,?BCM2835_GPIO_FSEL_OUTP);?? ?? ?????? ????bcm2835_gpio_set(PIN);?? ?? ????printk("ledsinit.\n");?? ????return?ret;?? }?? ?? static?void?leds_exit(void)?? {?? ?????? ????bcm2835_gpio_clr(PIN);?? ?? ????misc_deregister(&misc);?????????? ?? ????printk("leds_exit\n");?? }?? ?? module_init(leds_init);?? module_exit(leds_exit);?? ?? MODULE_AUTHOR("Hu?Chunxu");?? MODULE_LICENSE("GPL");?? ? ? 硬件相關(guān)操作:
[cpp]?view plaincopy
#include?<linux/miscdevice.h>?? #include?<linux/delay.h>?? #include?<asm/irq.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?<asm/io.h>?? #include?<asm/uaccess.h>?? #include?<linux/ioport.h>?? ?? #include?"bcm2835.h"?? ?? int?bcm2835_gpio_fsel(uint8_t?pin,?uint8_t?mode)?? {?? ?????? ????volatile?uint32_t?*?bcm2835_gpio?=?(volatile?uint32_t?*)ioremap(BCM2835_GPIO_BASE,?16);?? ????volatile?uint32_t?*?bcm2835_gpio_fsel?=?bcm2835_gpio?+?BCM2835_GPFSEL0/4?+?(pin/10);?? ????uint8_t???shift?=?(pin?%?10)?*?3;?? ????uint32_t??value?=?mode?<<?shift;?? ????*bcm2835_gpio_fsel?=?*bcm2835_gpio_fsel?|?value;?? ?? ????printk("fsel?address:?0x%lx?:?%x\n",?bcm2835_gpio_fsel,?*bcm2835_gpio_fsel);?? ?? ????return?0;?? }?? ?? int?bcm2835_gpio_set(uint8_t?pin)?? {?? ?????? ????volatile?uint32_t?*?bcm2835_gpio?=?(volatile?uint32_t?*)ioremap(BCM2835_GPIO_BASE,?16);?? ????volatile?uint32_t?*?bcm2835_gpio_set?=?bcm2835_gpio?+?BCM2835_GPSET0/4?+?pin/32;?? ????uint8_t???shift?=?pin?%?32;?? ????uint32_t??value?=?1?<<?shift;?? ????*bcm2835_gpio_set?=?*bcm2835_gpio_set?|?value;?? ?? ????printk("set?address:??0x%lx?:?%x\n",?bcm2835_gpio_set,?*bcm2835_gpio_set);?? ?? ????return?0;?? }?? ?? int?bcm2835_gpio_clr(uint8_t?pin)?? {?? ????? ????volatile?uint32_t?*?bcm2835_gpio?=?(volatile?uint32_t?*)ioremap(BCM2835_GPIO_BASE,?16);?? ????volatile?uint32_t?*?bcm2835_gpio_clr?=?bcm2835_gpio?+?BCM2835_GPCLR0/4?+?pin/32;?? ????uint8_t???shift?=?pin?%?32;?? ????uint32_t??value?=?1?<<?shift;?? ????*bcm2835_gpio_clr?=?*bcm2835_gpio_clr?|?value;?? ?????? ????printk("clr?address:??0x%lx?:?%x\n",?bcm2835_gpio_clr,?*bcm2835_gpio_clr);?? ?? ????return?0;?? }?? ? ? ? ? 應(yīng)用測(cè)試程序:
[cpp]?view plaincopy
#include?<stdio.h>?? #include?<stdlib.h>?? #include?<unistd.h>?? #include?<sys/ioctl.h>?? ?? int?main(int?argc,?char?**argv)?? {?? ????int?on;?? ????int?fd;?? ????if?(argc?!=?2?||?sscanf(argv[1],"%d",?&on)?!=?1?||on?<?0?||?on?>?1?)?{?? ????????fprintf(stderr,?"Usage:%s?0|1\n",argv[0]);?? ????????exit(1);?? ????}?? ????fd?=?open("/dev/my_leds",?0);?? ????if?(fd?<?0)?{?? ????????perror("open?device?leds");?? ????????exit(1);?? ????}?? ?????? ????if(on){?? ????????printf("turn?on?leds!\n");?? ????????ioctl(fd,?1);?? ????}?? ????else?{?? ????????printf("turn?off?leds!\n");?? ????????ioctl(fd,?0);?? ????}?? ????close(fd);?? ????return?0;?? }?? ? ? ? 分別編譯,插入模塊,然后運(yùn)行測(cè)試程序,可以控制LED的亮滅了。
----------------------------------------------------------------
歡迎大家轉(zhuǎn)載我的文章。
總結(jié)
以上是生活随笔為你收集整理的树莓派linux驱动学习之LED控制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。