pcDuino的linux移植五GPIO驅動開發

調試完pcDuino的led裸板程序,再調pcDuino基於linux內核的gpio驅動開發,之前的問題迎刃而解。本文是在pcDuino的linux移植四簡單驅動開發的基礎上,作GPIO驅動開發。而後寫一個應用測試程序,經過敲命令控制pcduino的TX led亮、滅。同時若是你GPIO四、GPIO5接個LED,也會跟着亮、滅。node

開發環境:
系統:ubuntu 10.04.4
單板:pcDuino
編譯器:arm-2009q3-67-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2
linux

目標:敲命令控制pcDuino上的TX_LED亮、滅web

1、硬件介紹ubuntu

仔細看pcDuino上的原理圖和pcDuino的手冊,發現兩者不是徹底對應的,仍是以原理圖爲準。根據原理圖知道TX_LED是接到PH15上,能夠當作普通IO口用,不須要連跳線app

2、編寫GPIO驅動代碼oop

主要包括2部分,驅動代碼first_drv.c和應用測試程序firstdrvtest.c以及Makefile。測試

驅動代碼first_drv.cui

[plain]   view plain copy
<EMBED id=ZeroClipboardMovie_1 height=18 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=1&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
  1. #include <linux/module.h>  
  2. #include <linux/kernel.h>  
  3. #include <linux/fs.h>  
  4. #include <linux/init.h>  
  5. #include <linux/delay.h>  
  6. #include <asm/uaccess.h>  
  7. #include <asm/irq.h>  
  8. #include <asm/io.h>  
  9. #include <mach/gpio.h>  
  10. #include <mach/hardware.h>  
  11. #include <linux/device.h>  
  12.   
  13. static struct class *firstdrv_class;  
  14. static struct class_device *firstdrv_class_dev;  
  15.   
  16. volatile unsigned long *gphcfg1;//0x100 ph9 [6:4]001  
  17. volatile unsigned long *gphdat; //0x10c  
  18. static int first_drv_open(struct inode *inode, struct file *file)  
  19. {  
  20.     printk("first_drv_open\n");  
  21.     /* 配置GPh9爲輸出引腳 gpio4*/  
  22.     *gphcfg1 |= ((0x1<<4)|(0x1<<8)|(0X1<<28));  
  23.     return 0;  
  24. }  
  25.   
  26. static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos)  
  27. {  
  28.     int val;  
  29.     printk("first_drv_write\n");  
  30.     copy_from_user(&val, buf, count); //    copy_to_user();  
  31.   
  32.     if (val == 1)  
  33.     {  
  34.         // 點燈  
  35.         *gphdat &= ~((0X1<<9)|(0X1<<10)|(1<<15));  
  36.     }  
  37.     else  
  38.     {  
  39.         // 滅燈  
  40.         *gphdat |= ((0X1<<9)|(0X1<<10)|(1<<15));  
  41.     }  
  42.       
  43.     return 0;  
  44. }  
  45.   
  46. static struct file_operations first_drv_fops ={  
  47.     .owner = THIS_MODULE,  
  48.     .open  = first_drv_open,  
  49.     .write = first_drv_write,  
  50. };  
  51.   
  52. int major;  
  53. static int first_drv_init(void)  
  54. {  
  55.     major = register_chrdev(0, "first_drv", &first_drv_fops);  
  56.     firstdrv_class = class_create(THIS_MODULE, "firstdrv");  
  57.     firstdrv_class_dev = device_create(firstdrv_class,NULL,MKDEV(major, 0), NULL, "xyz");  
  58.     gphcfg1 = (volatile unsigned long *)ioremap(0x01c20900, 16);  
  59.     gphdat = (volatile unsigned long *)ioremap(0x01c2090c, 16);//gphcfg1 + 3;  
  60.     return 0;  
  61. }  
  62.   
  63. static void first_drv_exit(void)  
  64. {  
  65.     unregister_chrdev(major,"first_drv");  
  66.     device_unregister(firstdrv_class_dev);  
  67.     class_destroy(firstdrv_class);  
  68.     iounmap(gphcfg1);  
[plain]   view plain copy
<EMBED id=ZeroClipboardMovie_2 height=18 name=ZeroClipboardMovie_2 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=2&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
  1.     iounmap(gphdat);  
  2. }  
  3.   
  4. module_init(first_drv_init);  
  5. module_exit(first_drv_exit);  
  6.   
  7. MODULE_LICENSE("GPL");  

文件Makefile:spa

[plain]   view plain copy
<EMBED id=ZeroClipboardMovie_3 height=18 name=ZeroClipboardMovie_3 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=3&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
  1. KERN_DIR = /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0  
  2.   
  3. all:  
  4.     make -C $(KERN_DIR) M=`pwd` modules  
  5.       
  6. clean:  
  7.     make -C $(KERN_DIR) M=`pwd`  modules clean  
  8.     rm -rf modules.order  
  9.   
  10. obj-m   += first_drv.o  

應用測試程序firstdrvtest.c:.net

[plain]   view plain copy
<EMBED id=ZeroClipboardMovie_4 height=18 name=ZeroClipboardMovie_4 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=4&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
  1. #include <sys/types.h>  
  2. #include <sys/stat.h>  
  3. #include <fcntl.h>  
  4. #include <stdio.h>  
  5.   
  6. /* firstdrvtest on  
  7.   * firstdrvtest off  
  8.   */  
  9. int main(int argc, char **argv)  
  10. {  
  11.     int fd;  
  12.     int val = 1;  
  13.     fd = open("/dev/xyz", O_RDWR);  
  14.     if (fd < 0)  
  15.     {  
  16.         printf("can't open!\n");  
  17.     }  
  18.     if (argc != 2)  
  19.     {  
  20.         printf("Usage :\n");  
  21.         printf("%s <on|off>\n", argv[0]);  
  22.         return 0;  
  23.     }  
  24.   
  25.     if (strcmp(argv[1], "on") == 0)  
  26.     {  
  27.         val  = 1;  
  28.     }  
  29.     else  
  30.     {  
  31.         val = 0;  
  32.     }  
  33.       
  34.     write(fd, &val, 4);  
  35.     return 0;  
  36. }  

3、編譯測試

1.編譯驅動first_drv.c

change@change :~/Si/A10/2_led$ cd ../pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/
change@change :~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv$ ls
first_drv.c   first_drv.mod.c  first_drv.o   firstdrvtest.c  modules.order
first_drv.ko  first_drv.mod.o  firstdrvtest  Makefile        Module.symvers
change@change:~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv$ make clean
make -C /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0 M=`pwd`  modules clean
make[1]: Entering directory `/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0'
  LD      /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/built-in.o
  CC [M]  /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.o
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c: In function 'first_drv_write':
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c:30: warning: ignoring return value of 'copy_from_user', declared with attribute warn_unused_result
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c: In function 'first_drv_init':
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c:57: warning: assignment from incompatible pointer type
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c: In function 'first_drv_exit':
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c:66: warning: passing argument 1 of 'device_unregister' from incompatible pointer type
include/linux/device.h:692: note: expected 'struct device *' but argument is of type 'struct class_device *'
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.mod.o
  LD [M]  /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.ko
  CLEAN   /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/.tmp_versions
  CLEAN   /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/Module.symvers
make[1]: Leaving directory `/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0'
rm -rf modules.order

change@change:~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv$ make
make -C /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0 M=`pwd` modules
make[1]: Entering directory `/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0'
  CC [M]  /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.o
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c: In function 'first_drv_write':
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c:30: warning: ignoring return value of 'copy_from_user', declared with attribute warn_unused_result
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c: In function 'first_drv_init':
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c:57: warning: assignment from incompatible pointer type
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c: In function 'first_drv_exit':
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c:66: warning: passing argument 1 of 'device_unregister' from incompatible pointer type
include/linux/device.h:692: note: expected 'struct device *' but argument is of type 'struct class_device *'
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.mod.o
  LD [M]  /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.ko
make[1]: Leaving directory `/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0'

2.編譯應用測試程序firstdrvtest.c

change@change:~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv$  /home/change/tools/arm-2009q3/bin/arm-none-linux-gnueabi-gcc -o firstdrvtest firstdrvtest.c

其中/home/change/tools/arm-2009q3/bin/arm-none-linux-gnueabi-gcc是個人交叉編譯路徑,根據本身狀況修改。

change@change:~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv$ ls
first_drv.c   first_drv.mod.c  first_drv.o   firstdrvtest.c  modules.order
first_drv.ko  first_drv.mod.o  firstdrvtest  Makefile        Module.symvers
change@change:~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv$ cp first_drv.ko firstdrvtest /home/change/work/rootfs_dir/fs_mini/home/linux-3.0.62/pcduino/
change@change:~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv$

其中/home/change/work/rootfs_dir/fs_mini是個人NFS共享目錄,詳細配置見個人ubuntu 開發環境配置。程序比較簡單,就不分析了,有問題直接留言吧,開始測試吧。

3.測試

啓動前面pcDuino的linux移植1、2、3、四搭建的驅動開發平臺,上電進入pcDuino啓動控制檯,串口輸出以下

/ # ifconfig eth0 172.16.1.111
<4>wemac wemac.0: WARNING: no IRQ resource flags set.
[   18.250000] wemac wemac.0: WARNING: no IRQ resource flags set.
<6>wemac wemac.0: eth0: link up, 100Mbps, full-duplex, lpa 0x45E1
[   18.400000] wemac wemac.0: eth0: link up, 100Mbps, full-duplex, lpa 0x45E1
/ # ping 172.16.1<7>eth0: no IPv6 routers present
[   28.860000] eth0: no IPv6 routers present

PING 172.16.1 (172.16.0.1): 56 data bytes
^C
--- 172.16.1 ping statistics ---
4 packets transmitted, 0 packets received, 100% packet loss
/ # ping 172.16.1.137
PING 172.16.1.137 (172.16.1.137): 56 data bytes
64 bytes from 172.16.1.137: seq=0 ttl=64 time=10.015 ms
64 bytes from 172.16.1.137: seq=1 ttl=64 time=1.013 ms
64 bytes from 172.16.1.137: seq=2 ttl=64 time=1.735 ms
64 bytes from 172.16.1.137: seq=3 ttl=64 time=0.814 ms
^C
--- 172.16.1.137 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.814/3.394/10.015 ms
/ # ls
bin      etc      lib      mnt      run      sys      usr
dev      home     linuxrc  proc     sbin     tmp      var
/ # mount -t nfs -o nolock 172.16.1.137:/home/change/work/rootfs_dir/fs_mini /mn
t/
/ # ls /mnt/
bin      etc      lib      mnt      root     sys      usr
dev      home     linuxrc  proc     sbin     tmp
/ # cd /mnt/home/linux-3.0.62/pcduino/
/mnt/home/linux-3.0.62/pcduino # ls
first_drv.ko  firstdrvtest  gpio_drv.ko   gpiodrvtest
/mnt/home/linux-3.0.62/pcduino # insmod first_drv.ko 
/mnt/home/linux-3.0.62/pcduino # lsmod 
first_drv 1768 0 - Live 0xbf000000
/mnt/home/linux-3.0.62/pcduino # ./firstdrvtest off
first_drv_open
[  303.610000] first_drv_open
first_drv_write
[  303.610000] first_drv_write
/mnt/home/linux-3.0.62/pcduino # ./firstdrvtest on
first_drv_open
[  309.510000] first_drv_open
first_drv_write
[  309.510000] first_drv_write
/mnt/home/linux-3.0.62/pcduino #

能夠看到執行./firstdrvtest off ,pcDuino上的TX LED就滅,執行./firstdrvtest on,pcDuino上的TX LED就亮。測試基本正常,卸載剛剛加載的驅動以下;

/mnt/home/linux-3.0.62/pcduino # rmmod first_drv
/mnt/home/linux-3.0.62/pcduino # lsmod 
/mnt/home/linux-3.0.62/pcduino #

基本OK了,下一步繼續完善驅動。

相關文章
相關標籤/搜索