Bootstrap

使用eclipse 开发 嵌入式Linux驱动(注意事项)(make:***没有规则可言创建目标"all".停止 的解决方法)

几点补充

1.对于友善之臂mini2440 官方内核,和交叉编译工具链

autoconf.h位于.linux-2.6.32.2中的autoconf.h位于/include/linux/autoconf.h

2.ctrl + b 编译时,出现 make:***没有规则可言创建目标"all".停止 

解决方法:原因是make 没有找到makefile。右击工程,选择properties->c/c++ builder->Environment->查看PWD为工程目录下的Debug(or Release)

所以只要将.c文件和makefile都放到Debug目录里,就可以进行编译

3.在工程属性中将自动生成makefile选项去掉,否则自己创建的makefile是无效的

=====================================================================

http://blog.csdn.net/cp1300/article/details/8266806

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 plain copy
  1. 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 plain copy
  1. <language name="C 源文件">  
  2.   
  3.   
  4.   
  5. </language>  
添加

[html]  view plain copy
  1. <macro><name>__KERNEL__</name><value>1</value></macro>  

如下图


添加后



再将刚刚那个symbol.xml文件里面的所有代码复制到

[html]  view plain copy
  1. <macro><name>__KERNEL__</name><value>1</value></macro>  
这行的下一行,如下图


在上面的一个

[html]  view plain copy
  1. <language name="C 源文件">  
  2.   
  3.   
  4.   
  5. </language>  

添加

[cpp]  view plain copy
  1. <includepath>/home/cfan/linux/linux-3.0.1/include</includepath>  
  2. <includepath>/home/cfan/linux/linux-3.0.1/arch/arm/include</includepath>  
  3. <includepath>/home/cfan/linux/linux-3.0.1/arch/arm/plat-samsung/include</includepath>  
  4. <includepath>/home/cfan/linux/linux-3.0.1/arch/arm/mach-s3c64xx/include</includepath>  
这里面的路径要看自己实际的内核路径进行修改,也可以在工程属性中一个一个的添加,就是添加一个linux有关的路径而已。


保存退出即可。


再打开eclipse的刚刚那个导出的位置,现在将导出的文件导入即可


点击完成即可,如果导入出问题了,仔细对照我的教程。应用,退出即可,导入后会多了几个路径,内核目录里面的头文件路径




然后新建一个.c文件


代码是之前写的

[cpp]  view plain copy
  1. /**************************************************************************************************************** 
  2.  * 文件名称 :   led_drive.c 
  3.  * 简介       :   OK6410 LED驱动 
  4.  * 作者       :   异灵元([email protected] 
  5.  * 创建时间 :   2012/08/27 17:28 
  6.  * 修改时间 :   2012/08/27 
  7.  * 说明       :   OK6410 开发板(S3C6410)LED(GPIO)驱动 
  8.  ****************************************************************************************************************/  
  9.   
  10. //系统头文件  
  11. #include <linux/miscdevice.h>  
  12. #include <linux/delay.h>  
  13. #include <asm/irq.h>  
  14. #include <mach/hardware.h>  
  15. #include <linux/kernel.h>  
  16. #include <linux/module.h>  
  17. #include <linux/init.h>  
  18. #include <linux/mm.h>  
  19. #include <linux/fs.h>  
  20. #include <linux/types.h>  
  21. #include <linux/delay.h>  
  22. #include <linux/moduleparam.h>  
  23. #include <linux/slab.h>  
  24. #include <linux/errno.h>  
  25. #include <linux/ioctl.h>  
  26. #include <linux/cdev.h>  
  27. #include <linux/string.h>  
  28. #include <linux/list.h>  
  29. #include <linux/pci.h>  
  30. #include <asm/uaccess.h>  
  31. #include <asm/atomic.h>  
  32. #include <asm/unistd.h>  
  33. //--------------------------//  
  34. #include <mach/map.h>  
  35. #include <mach/regs-clock.h>  
  36. #include <mach/regs-gpio.h>  
  37. //--------------------------//  
  38. #include <plat/gpio-cfg.h>  
  39. #include <mach/gpio-bank-e.h>  
  40. #include <mach/gpio-bank-m.h>  
  41.   
  42.   
  43. ///  
  44. //驱动模块名称  
  45. #define DEVICE_NAME "OK6410_LED"  
  46.   
  47. //函数声明  
  48. ///  
  49. static long OK6410_LED_ioctl(  
  50.         struct file *file,  
  51.         unsigned int cmd,  
  52.         unsigned long arg);  
  53. static ssize_t OK6410_LED_write(  
  54.         struct file *file,  
  55.         const char __user *buff,  
  56.         size_t size,  
  57.         loff_t *loff);  
  58. static ssize_t OK6410_LED_read(  
  59.         struct file *file,  
  60.         char __user *buff,  
  61.         size_t size,  
  62.         loff_t *loff);  
  63. ///  
  64.   
  65.   
  66. /*  这个结构是字符设备驱动的核心 
  67. *   当应用程序操作设备文件所提供的open,read,write等函数, 
  68. *   最终会调用到这个结构中的对应函数 
  69. */  
  70. static struct file_operations dev_fops = {  
  71.         .owner              = THIS_MODULE,      //这是一个宏,指向编译模块时自动创建的__this_module变量  
  72.         .unlocked_ioctl     = OK6410_LED_ioctl,  
  73.         .read               = OK6410_LED_read,  
  74.         .write              = OK6410_LED_write  
  75. };  
  76.   
  77. //注册驱动所使用的相关信息  
  78. static struct miscdevice misc = {  
  79.         .minor = MISC_DYNAMIC_MINOR,  
  80.         .name = DEVICE_NAME,                        //驱动模块名称  
  81.         .fops = &dev_fops,  
  82. };  
  83.   
  84. //LED设备访问信号量  
  85. struct semaphore led_sem;  
  86.   
  87.   
  88. /**************************************************************************************************************** 
  89. *函数名        :   static int  __init OK6410_LED_init(void) 
  90. *功能       : LED模块初始化函数 
  91. *参数       : 无 
  92. *返回       : 0:成功;<0:失败 
  93. *依赖       :     linux底层宏定义 
  94. *作者       : 异灵元([email protected] 
  95. *创建时间   :   2012/08/27 17:28 
  96. *最后修改时间:    2012/08/27 17:28 
  97. *说明     :   初始化LED硬件,注册LED驱动 
  98. ****************************************************************************************************************/  
  99. static int  __init OK6410_LED_init(void)  
  100. {  
  101.     int ret;  
  102.     unsigned int reg;  
  103.   
  104.     //GPIOM0-3 推挽输出  
  105.     reg = readl(S3C64XX_GPMCON);    //获取GPIOM寄存器数据  
  106.     reg &= (~0xffff);                   //清除之前设置  
  107.     reg |= 0x1111;                  //推挽输出  
  108.     writel(reg,S3C64XX_GPMCON);     //配置IO模式  
  109.     reg = readl(S3C64XX_GPMDAT);    //读取输出寄存器之前数据  
  110.     reg |= 0xf;  
  111.     writel(reg,S3C64XX_GPMDAT);     //写入1,让所有的灯都熄灭  
  112.   
  113.     ret = misc_register(&misc);     //注册驱动  
  114.     if(ret < 0)  
  115.     {  
  116.         printk(DEVICE_NAME " can't initialized LED!\n");  
  117.         return ret;  
  118.     }  
  119.     init_MUTEX(&led_sem);           //注册信号量  
  120.     printk(DEVICE_NAME " initialized\n");  
  121.     return 0;                           //返回成功  
  122. }  
  123.   
  124.   
  125. /**************************************************************************************************************** 
  126. *函数名        :   static long OK6410_LED_ioctl( 
  127.                         struct file *file, 
  128.                         unsigned int cmd, 
  129.                         unsigned long arg) 
  130. *功能       : 发送命令给LED驱动模块,无实际作用,直接返回0 
  131. *参数       : 无作用 
  132. *返回       : 0 
  133. *依赖       :     无 
  134. *作者       : 异灵元([email protected] 
  135. *创建时间   :   2012/08/27 17:28 
  136. *最后修改时间:    2012/08/27 17:28 
  137. *说明     :   无 
  138. ****************************************************************************************************************/  
  139. static long OK6410_LED_ioctl(  
  140.         struct file *file,  
  141.         unsigned int cmd,  
  142.         unsigned long arg)  
  143. {  
  144.     return 0;  
  145. }  
  146.   
  147.   
  148. /**************************************************************************************************************** 
  149. *函数名        :   static ssize_t OK6410_LED_write( 
  150.                         struct file *file, 
  151.                         const char __user *buff, 
  152.                         size_t size, 
  153.                         loff_t *loff) 
  154. *功能       : 写数据到LED驱动模块,低电平灯亮 
  155. *参数       : file:文件指针(无作用);buff:数据缓冲区指针;buff:数据数量;loff:无作用 
  156. *返回       : 0:成功;<0:失败 
  157. *依赖       :     linux底层宏 
  158. *作者       : 异灵元([email protected] 
  159. *创建时间   :   2012/08/27 17:43 
  160. *最后修改时间:    2012/08/27 17:43 
  161. *说明     :   点灯函数,低电平亮,0-3BIT有效;对应4个LED 
  162. ****************************************************************************************************************/  
  163. static ssize_t OK6410_LED_write(  
  164.         struct file *file,  
  165.         const char __user *buff,  
  166.         size_t size,  
  167.         loff_t *loff)  
  168. {  
  169.     unsigned int reg;  
  170.   
  171.     if(down_interruptible(&led_sem))    //获取信号量  
  172.         return -ERESTARTSYS;  
  173.     reg = readl(S3C64XX_GPMDAT);  
  174.     reg &= (~0xf);  
  175.     reg |= buff[0] & 0xf;  
  176.     writel(reg,S3C64XX_GPMDAT);  
  177.     up(&led_sem);                           //释放信号量  
  178.   
  179.     return 0;  
  180. }  
  181.   
  182.   
  183. /**************************************************************************************************************** 
  184. *函数名        :   static ssize_t OK6410_LED_read( 
  185.                         struct file *file, 
  186.                         char __user *buff, 
  187.                         size_t size, 
  188.                         loff_t *loff) 
  189. *功能       : 读LED状态,低电平灯亮 
  190. *参数       : file:文件指针(无作用);buff:数据缓冲区指针;buff:数据数量;loff:无作用 
  191. *返回       : 0:成功;<0:失败 
  192. *依赖       :     linux底层宏 
  193. *作者       : 异灵元([email protected] 
  194. *创建时间   :   2012/08/27 17:48 
  195. *最后修改时间:    2012/08/27 17:48 
  196. *说明     :   读取灯的状态,低电平灯亮,0-3bit有效;对应4个LED 
  197. ****************************************************************************************************************/  
  198. static ssize_t OK6410_LED_read(  
  199.         struct file *file,  
  200.         char __user *buff,  
  201.         size_t size,  
  202.         loff_t *loff)  
  203. {  
  204.     unsigned int reg;  
  205.   
  206.     if(down_interruptible(&led_sem))    //获取信号量  
  207.         return -ERESTARTSYS;  
  208.     reg = readl(S3C64XX_GPMDAT);  
  209.     buff[0] = reg | 0xfffffff0;  
  210.     up(&led_sem);                           //释放信号量  
  211.   
  212.     return 0;  
  213. }  
  214.   
  215.   
  216.   
  217. /**************************************************************************************************************** 
  218. *函数名        :   static void __exit OK6410_LED_exit(void) 
  219. *功能       : 卸载LED驱动 
  220. *参数       : 无 
  221. *返回       : 无 
  222. *依赖       :     linux底层宏 
  223. *作者       : 异灵元([email protected] 
  224. *创建时间   :   2012/08/27 17:50 
  225. *最后修改时间:    2012/08/27 17:50 
  226. *说明     :   卸载驱动 
  227. ****************************************************************************************************************/  
  228. static void __exit OK6410_LED_exit(void)  
  229. {  
  230.     unsigned int reg;  
  231.   
  232.     //GPIOM0-3 输入  
  233.     reg = readl(S3C64XX_GPMCON);    //获取GPIOM寄存器数据  
  234.     reg &= (~0xffff);                   //清除之前设置  
  235.     writel(reg,S3C64XX_GPMCON);     //配置IO模式  
  236.     misc_deregister(&misc);         //卸载驱动  
  237. }  
  238.   
  239.   
  240.   
  241. //动态加载驱动接口(必须)  
  242. module_init(OK6410_LED_init);  
  243. module_exit(OK6410_LED_exit);  
  244. //其它信息(非必需)  
  245. MODULE_AUTHOR("[email protected]");                        //驱动程序作者  
  246. MODULE_DESCRIPTION("OK6410(S3C6410) LED Driver");   //一些描述信息  
  247. MODULE_LICENSE("GPL");  //遵循的协议  


此时会有警告,不管他。



在工程属性中将自动生成makefile选项去掉



3.新建一个makefile文件修改makefile,编译驱动文件

[cpp]  view plain copy
  1. ARCH=arm  
  2. CROSS_COMPILE=arm-linux-  
  3. obj-m := led.o  
  4. KDIR :=/home/cfan/linux/linux-3.0.1   
  5. PWD :=$(shell pwd)  
  6. all:  
  7.     $(MAKE) -C $(KDIR) M=$(PWD) modules  
  8. clean:  
  9.     $(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

解决后就可以卸载驱动了。


悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;