當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 嵌入式云IOT技術(shù)圈
[導(dǎo)讀]關(guān)于友善之臂出的這款contexA9開發(fā)板,目前在網(wǎng)絡(luò)上的資源較少,特別是內(nèi)核的,非常之少,鑒于這種情況,我將會(huì)寫一個(gè)系列的驅(qū)動(dòng)來(lái)做關(guān)于tiny4412這款板子開發(fā)的總結(jié)。 ? ? ?簡(jiǎn)單介紹一下: Tiny4412是一款高性能的四核Cortex-A9核心板,由廣州友善之臂設(shè)計(jì)、

關(guān)于友善之臂出的這款contexA9開發(fā)板,目前在網(wǎng)絡(luò)上的資源較少,特別是內(nèi)核的,非常之少,鑒于這種情況,我將會(huì)寫一個(gè)系列的驅(qū)動(dòng)來(lái)做關(guān)于tiny4412這款板子開發(fā)的總結(jié)。

     簡(jiǎn)單介紹一下:

Tiny4412是一款高性能的四核Cortex-A9核心板,由廣州友善之臂設(shè)計(jì)、生產(chǎn)和發(fā)行銷售。它采用三星Exynos4412作為主處理器,運(yùn)行主頻可高達(dá)1.5GHz,Exynos4412內(nèi)部集成了Mali-400 MP高性能圖形引擎,支持3D圖形流暢運(yùn)行,并可播放1080P大尺寸高清視頻。三星旗艦智能手機(jī)Galaxy S3即是采用此CPU設(shè)計(jì)。

我用的是普通版.也就是只有一個(gè)串口的.但是核心板是一樣的。

好了,介紹完畢,前面的文章我們已經(jīng)說(shuō)過(guò)了如何編寫一個(gè)字符設(shè)備的驅(qū)動(dòng)程序,這里就不再繼續(xù)扯字符驅(qū)動(dòng)怎么寫,非常簡(jiǎn)單了,看看就懂了。

我們進(jìn)入整題,今天,我們需要實(shí)現(xiàn)一個(gè)LED的驅(qū)動(dòng)程序。在友善之臂的核心板上,有4顆LED燈,如何編寫一個(gè)驅(qū)動(dòng)程序,讓它亮起來(lái),首先我們來(lái)看看核心板:

LED燈就位于右上角,第一個(gè)和第二個(gè)都是電源指示燈,我們不需要管它,我們只管后面那4個(gè)LED燈。

如何編寫?

1、首先找到板子的原理圖,找到對(duì)應(yīng)的引腳。

2、接著打開數(shù)據(jù)手冊(cè),找到對(duì)應(yīng)的寄存器。

3、開始編寫LED驅(qū)動(dòng)程序

4、編寫makefile

5、插入模塊insmod xxx.ko

6、查詢主設(shè)備號(hào) cat /proc/devices

7、創(chuàng)建設(shè)備節(jié)點(diǎn) mknod /dev/xxx c x x

8、執(zhí)行應(yīng)用程序app

對(duì)應(yīng)的原理圖:



從這里我們可以得出一個(gè)結(jié)論,LED燈是低電平點(diǎn)亮的,也就是往對(duì)應(yīng)的端口里寫0,LED燈就亮了。從最下面一幅圖可以知道,我們要找的寄存器是GPIO的GPM4開頭的這個(gè)寄存器,現(xiàn)在我們進(jìn)入查數(shù)據(jù)手冊(cè)的階段.

查手冊(cè):

我們找到手冊(cè)的第288頁(yè)GPIO章節(jié)的GPMCON這里:




這是我們要配置端口的模式的IO口,端口有以上的一些狀態(tài),在這里我們只考慮輸出,也就是只要配置Output那一項(xiàng)就可以了。

我們要配的寄存器有GPM4CON[0],GPM4CON[1],GPM4CON[2],GPM4CON[3],這四位,分別配置成output輸出模式.

接下來(lái)再看一個(gè)GPM4DAT,這個(gè)是端口的狀態(tài)寄存器,對(duì)狀態(tài)寄存器就是寫0或者寫1,那么LED就被驅(qū)動(dòng)了,我們來(lái)看看:


好了,寄存器我們已經(jīng)找到了,接下來(lái),可以進(jìn)入寫代碼的階段了:

首先編寫LED驅(qū)動(dòng)程序:


[cpp] view plain copy print?

  1. #include <linux/init.h>  

  2. #include <linux/module.h>  

  3. #include <linux/kernel.h>  

  4. #include <linux/fs.h>  

  5. #include <linux/io.h>  

  6. #include <asm/uaccess.h>  

  7. #include <asm/irq.h>  

  8. #include <asm/io.h>  

  9. //這個(gè)是設(shè)備的名稱,也就是對(duì)應(yīng)在/dev/test-dev  

  10. #define DEV_NAME    "test-dev"  

  11. //LED燈IO口的地址,也就是剛剛我們?cè)谏厦娴男酒謨?cè)看到的Address  

  12. #define GPM4COM     0x110002E0  

  13. //定義配置模式的指針變量  

  14. volatile unsigned long *led_config = NULL ;   

  15. //定義配置狀態(tài)的指針變量  

  16. volatile unsigned long *led_dat = NULL ;   

  17. //open方法,對(duì)LED燈進(jìn)行初始化  

  18. int led_open(struct inode *inode, struct file *filp)  

  19. {  

  20.     printk("led_open\n");//上層程序?qū)ED進(jìn)行Open操作的時(shí)候會(huì)執(zhí)行這個(gè)函數(shù)  

  21.     //先對(duì)LED的端口進(jìn)行清0操作  

  22.     *led_config &= ~(0xffff);  

  23.     //將4個(gè)IO口16位都設(shè)置為Output輸出狀態(tài)  

  24.     *led_config |= (0x1111);  

  25.     return 0;  

  26. }  

  27. //write方法  

  28. int led_write(struct file *filp , const char __user *buf , size_t count , loff_t *f_pos)  

  29. {  

  30.     int val ;   

  31.     //注意,這里是在內(nèi)核中進(jìn)行操作,我們需要使用copy_from_user這個(gè)函數(shù)將用戶態(tài)的內(nèi)容拷貝到內(nèi)核態(tài)  

  32.     copy_from_user(&val , buf , count);   

  33.     //以下就是當(dāng)val是哪個(gè)值的時(shí)候,led就執(zhí)行相應(yīng)的操作,這里不多說(shuō)  

  34.     switch(val)  

  35.     {  

  36.         case 0 :   

  37.                 //對(duì)狀態(tài)寄存器進(jìn)行賦值,以下雷同  

  38.                 printk(KERN_EMERG"led1_on\n");  

  39.                 *led_dat &= ~0x1 ;  

  40.                 break ;  

  41.         case 1 :  

  42.                 printk(KERN_EMERG"led2_on\n");  

  43.                 *led_dat &= ~0x2 ;  

  44.                 break ;  

  45.         case 2 :  

  46.                 printk(KERN_EMERG"led3_on\n");  

  47.                 *led_dat &= ~0x4 ;  

  48.                 break ;  

  49.         case 3 :  

  50.                 printk(KERN_EMERG"led4_on\n");  

  51.                 *led_dat &= ~0x8 ;   

  52.                 break ;  

  53.         case 4 :  

  54.                 printk(KERN_EMERG"ledall_on\n");  

  55.                 *led_dat &= ~0xf ;  

  56.                 break ;  

  57.         case 5 :   

  58.                 printk(KERN_EMERG"ledall_off\n");  

  59.                 *led_dat |= 0xf ;  

  60.                 break ;  

  61.   

  62.     }  

  63. }  

  64. //close方法  

  65. int led_close(struct inode *inode, struct file *filp)  

  66. {  

  67.     printk("led_close\n");  

  68.     *led_dat |= 0xf ;  //全滅,因?yàn)楦唠娖绞菧绲模?xf ----> 1111  

  69.     return 0;  

  70. }  

  71. //用ioctl這個(gè)方法也可以實(shí)現(xiàn)LED的操作的,自己去實(shí)現(xiàn)吧  

  72. #if 0  

  73. long led_ioctl(struct file *filp, unsigned int request, unsigned long arg)  

  74. {  

  75.     switch(request)  

  76.     {  

  77.         case 0:  

  78.             printk(KERN_EMERG"led1 on\n");  

  79.             *led_dat &=~0x1 ;  

  80.             break;  

  81.   

  82.         case 1:  

  83.             printk(KERN_EMERG"led2 on\n");  

  84.             *led_dat &=~0x2 ;  

  85.             break;  

  86.   

  87.         case 3:  

  88.             printk(KERN_EMERG"led3 on\n");  

  89.             *led_dat &=~0xf ;  

  90.             break;  

  91.   

  92.         case 4:  

  93.             printk(KERN_EMERG"led4 on\n");  

  94.             *led_dat &=~0x8 ;  

  95.             break ;  

  96.         default :   

  97.             *led_dat |= 0xf ;  

  98.     }     

  99. }  

  100. #endif  

  101. //對(duì)方法進(jìn)行初始化  

  102. struct file_operations fops = {  

  103.     .owner = THIS_MODULE ,  

  104.     .open = led_open,  

  105.     .release = led_close,  

  106. //  .unlocked_ioctl = led_ioctl,  

  107.     .write = led_write,  

  108. };  

  109. //主設(shè)備號(hào)  

  110. int major ;  

  111. //啟動(dòng)函數(shù)  

  112. static __init int test_init(void)  

  113. {  

  114.     printk("led_init\n");  

  115.     major = register_chrdev(major, DEV_NAME, &fops);  

  116.     led_config = (volatile unsigned long *)ioremap(GPM4COM , 16);  

  117.     led_dat = led_config + 1 ;    

  118.     return 0;  

  119. }  

  120. //注銷函數(shù)  

  121. static __exit void test_exit(void)  

  122. {  

  123.     printk("led_exit\n");  

  124.     unregister_chrdev(major, DEV_NAME);  

  125.     iounmap(led_config);  

  126. }  

  127.   

  128. module_init(test_init);  

  129. module_exit(test_exit);  

  130.   

  131. MODULE_LICENSE("GPL");  

  132. MODULE_AUTHOR("Y.X.YANG");  

  133. MODULE_VERSION("2016.1.15");</span>  




以上就是led這個(gè)設(shè)備驅(qū)動(dòng)的編寫框架。看不懂的可以去學(xué)學(xué)linux內(nèi)核設(shè)備驅(qū)動(dòng)再來(lái)看就很簡(jiǎn)單了。其實(shí)跟單片機(jī)的編程差不了多少的,只不過(guò)內(nèi)核驅(qū)動(dòng)是按照框架來(lái)編寫的,有所驅(qū)動(dòng)就在這里。


驅(qū)動(dòng)程序編寫完了,接下來(lái)我們編寫上層應(yīng)用層的程序:


[cpp] view plain copy print?

  1. #include <stdio.h>  

  2. #include <sys/types.h>  

  3. #include <sys/stat.h>  

  4. #include <fcntl.h>  

  5.   

  6. int main(int argc, char **argv)  

  7. {  

  8.     int fd;  

  9.     int val = 0 ;  

  10.     //打開對(duì)應(yīng)的設(shè)備  

  11.     fd = open("/dev/test-dev",O_RDWR) ;  

  12.     if(-1 == fd)  

  13.     {  

  14.         printf("open fair!\n");  

  15.         return -1 ;  

  16.     }  

  17.     while(1){  

  18.         val = 0 ;  

  19.         //寫write方法就會(huì)調(diào)用到驅(qū)動(dòng)程序的led_write  

  20.         //最后我們能看到的結(jié)果是led燈做流水燈的實(shí)現(xiàn),然后全滅,再周而復(fù)始  

  21.         write(fd , &val , 4);  

  22.         sleep(1);  

  23.         val = 1 ;  

  24.         write(fd , &val , 4);  

  25.         sleep(1);  

  26.         val = 2 ;  

  27.         write(fd , &val , 4);  

  28.         sleep(1);  

  29.         val = 3 ;  

  30.         write(fd , &val , 4);  

  31.         sleep(1);  

  32.         val = 5 ;  

  33.         write(fd , &val , 4);  

  34.         sleep(1);  

  35.     }  

  36.     return 0;  

  37. }</span>  




好了,程序已經(jīng)寫完了,我們來(lái)看看makefile怎么寫.


[cpp] view plain copy print?

  1. #將你所寫的驅(qū)動(dòng)程序編譯成模塊形式  

  2. obj-m   += leds.o  

  3. #你需要的文件系統(tǒng)  

  4. ROOTFS = /disk/A9/filesystem  

  5. #你需要的內(nèi)核  

  6. KERNEL = /disk/A9/linux-3.5/  

  7. #模塊編譯  

  8. all:  

  9.     make -C $(KERNEL) M=`pwd` modules  

  10. #模塊清除  

  11. clean:  

  12.     make -C $(KERNEL) M=`pwd` clean  

  13.     rm -rf my_led  

  14. #模塊更新  

  15. install:  

  16.     make -C $(KERNEL) M=`pwd` modules_install INSTALL_MOD_PATH=$(ROOTFS)  

  17. #編譯上層app應(yīng)用程序  

  18. my_led:  

  19.     arm-linux-gcc my_led.c -o my_led</span>  


好了,所有的一切都編寫完成,我們來(lái)看看接下來(lái)的操作:


1、先編譯整個(gè)工程:執(zhí)行make命令

2、編譯app


3、啟動(dòng)minicom,打開開發(fā)板的電源,開發(fā)板bootload開始啟動(dòng)

4、開發(fā)板內(nèi)核啟動(dòng)


5、進(jìn)入文件系統(tǒng),執(zhí)行insmod插入模塊和顯示插入后的模塊的操作


6、看看主設(shè)備號(hào)


從這里可以看到,我們的設(shè)備test-dev的主設(shè)備號(hào)是250

所以我們創(chuàng)建設(shè)備節(jié)點(diǎn) : mknod /dev/test-dev c 250 0 ,創(chuàng)建完成后

7、執(zhí)行app應(yīng)用程序


在這里,我們可以看到程序開始跑起來(lái)了,我們來(lái)看看開發(fā)板上的led是怎么變化的:






好,寫了好多,也整理了不少東西出來(lái)了,有點(diǎn)累了,以后還要慢慢寫.....今天就到這里...


免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
關(guān)閉
關(guān)閉