[OK210开发板体验]功能篇(1)Linux字符驱动之LED灯驱动
【OK210开发板体验】的第一篇:开箱验板
【OK210开发板体验】的第二篇:板载资源
【OK210开发板体验】的第三篇:开发环境(软件安装,开发环境,烧写系统)
【OK210开发板体验】的第四篇:编程入门(NFS登录,驱动入门)
虽然在【OK210试用体验】问题篇(1)速求飞凌技术支持或大神解答中,也集中问了几个问题,但仍然rmmod这个命令不能用,飞凌的技术支持也没有给出正确的使用方法,看来只能自己慢慢摸索了。也希望有知道的,不吝赐教!
申请到板子有一段时间了,看着大家每天的试用报告,多数还停留在环境搭建上,而且有些人一个简单的功能,都能写一篇试用报告,我真是服了。接下来,将开启我的试用体验第二阶段:功能篇,主要围绕智能家居的一些应用模块进行功能的测试检验,以硬件分析+软件基础的形式引入,以驱动程序+应用源码的形式呈现。
今天是功能篇的第一篇,字符驱动之LED灯的控制,主要分3部分:硬件分析,软件基础,驱动编程。
一、硬件分析
在【OK210试用体验】的第二篇:板载资源中,简单分析了LED功能和作用。其实对LED的操作,就是对GPIO的最基本操作,也是入门操作。
首先查看S5Pv210的用户手册,对其GPIO口有一个整体了解,在用户手册的92页,对S5PV210的GPIO进行了概要的说明,总的来说,S5PV210有237个多功能输入输出端口,142个存储器端口引脚,控制146个GPIO中断,控制32个外部中断。
接着从OK210的底板原理图中可知,
OK210开发板将LED接到了XM0ADDR4-7引脚上,而这些引脚通过插座接到了核心板上,
从用户手册中,如下图得知,这些引脚是由EBI(External Bus Interface)来管理,详见用户手册的第六章。
所以,要对4个LED控制,就是对XM0ADDR4-7这4个引脚进行操作。
二、软件基础
1 Linux中的GPIO引脚定义
在Linux中,GPIO分成若干个group,每个group包含几个io port,访问某个port时要指明哪个group哪个port。kernel处理方法是把所有io port整理成一个线性的空间,即一组线性的数值,每个io port对应于一个数值。S5PV210引脚的具体定义,位于linux/arch/arm/mach-s5pv210/include/mach/gpio.h。
在该头文件中,首先进行分组及每组包含的端口数,如下所示
#define S5PV210_GPIO_A0_NR (8)
表示GPIO的A0口,含有8个引脚(端口)
接着定义每组GPIO的起始号码,其中S5PV210_GPIO_NEXT定义为如下形式
#defineS5PV210_GPIO_NEXT(__gpio) ((__gpio##_START) +(__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
ps:用##粘贴符号来运算的,以A组的0起始,依次加每组的GPIO个数。
如:S5PV210_GPIO_A1_START=S5PV210_GPIO_NEXT(S5PV210_GPIO_A0)=
S5PV210_GPIO_A0_START+S5PV210_GPIO_A0_NR+CONFIG_S3C_GPIO_SPACE+ 1
全部的GPIO的起始号在s5p_gpio_number枚举中定义:
enum s5p_gpio_number {
S5PV210_GPIO_A0_START =0,
S5PV210_GPIO_A1_START =S5PV210_GPIO_NEXT(S5PV210_GPIO_A0),/*0+8+1 = 9*/
S5PV210_GPIO_B_START = S5PV210_GPIO_NEXT(S5PV210_GPIO_A1),/*9+4+1 = 14*/
......
S5PV210_GPIO_ETC2_START =S5PV210_GPIO_NEXT(S5PV210_GPIO_ETC1),/*438+8+1 = 447*/
S5PV210_GPIO_ETC4_START =S5PV210_GPIO_NEXT(S5PV210_GPIO_ETC2),/*447+8+1 = 456*/
/*总数是456+6+1 = 463*/
};
最后定义了单个GPIO脚的起始号
#define S5PV210_GPA0(_nr) (S5PV210_GPIO_A0_START + (_nr))
#define S5PV210_GPA1(_nr) (S5PV210_GPIO_A1_START + (_nr))
#define S5PV210_GPB(_nr) (S5PV210_GPIO_B_START + (_nr))
......
#define S5PV210_ETC2(_nr) (S5PV210_GPIO_ETC2_START + (_nr))
#define S5PV210_ETC4(_nr) (S5PV210_GPIO_ETC4_START + (_nr))
2 Linux中GPIO函数定义
Linux使用Struct gpio_chip结构体来描述各种不同体系结构和电路板的抽象接口,也说是各种电路板都要提供自己接口实现,三星公司的芯片都使用自己的接口实现。主要在include/asm-generic/gpio.h中声明。而Linux将系统中所有的IO口都统一指定编号,一般情况是组名+编号。Linux将所有的IO称为资源,系统的任何模块使用资源,都要先申请,用完归还资源,
int gpio_request(unsigned gpio, const char*label)
void gpio_free(unsigned gpio)
所有的gpio都可以指定方向,
int gpio_direction_input(unsigned gpio)
int gpio_direction_output(unsigned gpio,int value)
所有的gpio都提供读写数据
int gpio_get_value(unsigned gpio)
void gpio_set_value(unsigned gpio, int on)
以上几个关键函数,在linux/gpio.h声明,在drivers/gpio/gpiolib.c定义
同时三星公司还封装了自己的gpio接口,定义位于arch/arm/plat-s3c/gpio-config.c,主要有
int s3c_gpio_cfgpin(unsigned int pin,unsigned int config)
int s3c_gpio_setpull(unsigned int pin,s3c_gpio_pull_t pull)
int s3c_gpio_setpin(unsigned int pin,s3c_gpio_pull_t level)
三、驱动编程
驱动代码由飞凌提供的驱动改编而来,只要根据硬件,设置对应的GPIO口,使其更方便移植;应用程序实现简单的流程灯功能;Makefile配置成可编译驱动程序和应用程序的形式。
具体的代码如下,具体的使用见上一篇【OK210试用体验】的第四篇:编程入门(NFS登录,驱动入门):
1
驱动程序:
1.
2. #include <linux/miscdevice.h>
3. #include <linux/input.h>
4. #include <linux/clk.h>
5. #include <linux/delay.h>
6. #include <asm/io.h>
7. #include <asm/uaccess.h>
8. #include <mach/map.h>
9. #include <mach/gpio.h>
10. #include <mach/regs-gpio.h>
11. #include <plat/gpio-core.h>
12. #include <plat/gpio-cfg.h>
13. #include <plat/gpio-cfg-helpers.h>
14.
15. #define DEVICE_NAME "leds"
16. /* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */
17. /*the second parameter that application program execute*/
18. #define IOCTL_GPIO_ON 1
19. #define IOCTL_GPIO_OFF 0
20. /* 用来指定LED所用的GPIO引脚 */
21. /*appoint the pin the LED will use*/
22. static unsigned long leds_table [] =
23. {
24. S5PV210_MP04(4),
25. S5PV210_MP04(5),
26. S5PV210_MP04(6),
27. S5PV210_MP04(7),
28. //arch\arm\mach-s5pv210\include\mach\gpio.h
29. };
30. static char leds_name[][4]={{"LED1"},{"LED2"},{"LED2"},{"LED3"}};
31. #define LED_NUM ARRAY_SIZE(leds_table)
32. /**
33. *函数功能:打开/dev/led设备
34. *fuction:open /dev/leds device
35. *设备名是:/dev/leds
36. *devce name: /dev/leds
37. **/
38. static int my_gpio_open(struct inode *inode, struct file *file)
39. {
40. int i;
41. int err;
42.
43. for (i = 0; i < LED_NUM; i++)
44. {
45. err = gpio_request(leds_table[i], leds_name[i]);
46. //drivers/gpio/gpiolib.c
47. if(err)
48. {
49. printk(KERN_ERR "failed to request S5PV210_GPH2(%d) for LED%d \n",i-1,i);
50. return err;
51. }
52. }
53.
54. for (i = 0; i < LED_NUM; i++)
55. {
56. // s3c_gpio_cfgpin(leds_table[i], gpio_cfg_table[i]);//Configuration pin function:input output multiplex
57. // s3c_gpio_setpin(leds_table[i], 0);//Set the pin level
58. //arch\arm\plat-samsung\gpio-config.c
59. gpio_direction_output(leds_table[i], 0);//write a value to GPIO port ,also set the port to output mode
60. gpio_set_value(leds_table[i], 0);
61. //drivers/gpio/gpiolib.c
62.
63. }
64. printk(KERN_INFO "LEDs driver successfully close\n");
65. return 0;
66. }
67. /**
68. *函数功能:用于控制led的亮灭
69. *fuction:control the led /turn on & turn off
70. *控制字为cmd,arg为控制哪个灯的亮灭取值范围为0-1:cmd为IOCTL_GPIO_ON时亮,cmd为IOCTL_GPIO_OFF为灭
71. *control byte is cmd; arg appointed which led wile be turn on or off,it can be 0 and 1;IOCTL_GPIO_ON:turn on,IOCTL_GPIO_OFF:turn off.
72. **/
73. static int my_gpio_ioctl(
74. struct inode *inode,
75. struct file *file,
76. unsigned int cmd,
77. unsigned long arg)
78. {
79. arg -= 1;
80. if (arg > LED_NUM)
81. {
82. return -EINVAL;
83. }
84. switch(cmd)
85. {
86. case IOCTL_GPIO_ON:
87. {
88. // 设置指定引脚的输出电平为1
89. gpio_direction_output(leds_table[arg], 1);
90. //s3c_gpio_setpin(leds_table[arg], 1);
91. return 0;