【OK210试用体验】功能篇(1)Linux字符驱动之LED灯驱动 - 在线问答 - 电子技术论坛 - 最好最受欢迎电子论坛!

【OK210试用体验】功能篇(1)Linux字符驱动之LED灯驱动

gjianw217 ( 楼主 ) 2015-8-13 00:48:06  只看该作者 倒序浏览
本帖最后由 gjianw217 于 2015-8-22 02:24 编辑

    前面进行了OK210试用体验的入门篇介绍,算是初步入门,分别包含:
【OK210试用体验】的第一篇:开箱验板
   【OK210试用体验】的第二篇:板载资源
   【OK210试用体验】的第三篇:开发环境(软件安装,开发环境,烧写系统)
   【OK210试用体验】的第四篇:编程入门(NFS登录,驱动入门)
    虽然在【OK210试用体验】问题篇(1)速求飞凌技术支持或大神解答中,也集中问了几个问题,但仍然rmmod这个命令不能用,飞凌的技术支持也没有给出正确的使用方法,看来只能自己慢慢摸索了。也希望有知道的,不吝赐教!
    申请到板子有一段时间了,看着大家每天的试用报告,多数还停留在环境搭建上,而且有些人一个简单的功能,都能写一篇试用报告,我真是服了。接下来,将开启我的试用体验第二阶段:功能篇,主要围绕智能家居的一些应用模块进行功能的测试检验,以硬件分析+软件基础的形式引入,以驱动程序+应用源码的形式呈现。
    今天是功能篇的第一篇,字符驱动之LED灯的控制,主要分3部分:硬件分析,软件基础,驱动编程。
一、硬件分析
    【OK210试用体验】的第二篇:板载资源中,简单分析了LED功能和作用。其实对LED的操作,就是对GPIO的最基本操作,也是入门操作。
首先查看S5Pv210的用户手册,对其GPIO口有一个整体了解,在用户手册的92页,对S5PV210GPIO进行了概要的说明,总的来说,S5PV210237个多功能输入输出端口,142个存储器端口引脚,控制146GPIO中断,控制32个外部中断。
    接着从OK210的底板原理图中可知,如下图,

      OK210开发板LED接到了XM0ADDR4-7引脚上,而这些引脚通过插座接到了核心板上,如下图,
   
   从用户手册中,如下图得知,这些引脚是由EBIExternal Bus Interface)来管理,详见用户手册的第六章。

    所以,要对4LED控制,就是对XM0ADDR4-74个引脚进行操作。
二、软件基础
1 Linux中的GPIO引脚定义
    Linux中,GPIO分成若干个group,每个group包含几个io port,访问某个port时要指明哪个group哪个portkernel处理方法是把所有io port整理成一个线性的空间,即一组线性的数值,每个io port对应于一个数值。S5PV210引脚的具体定义,位于linux/arch/arm/mach-s5pv210/include/mach/gpio.h
    在该头文件中,首先进行分组及每组包含的端口数,如下所示
      #define S5PV210_GPIO_A0_NR (8)
       表示GPIOA0口,含有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 LinuxGPIO函数定义
    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. #include
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include
  7. #include
  8. #include
  9. #include
  10. #include
  11. #include
  12. #include

  13. #define DEVICE_NAME "leds"
  14. /* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */
  15. /*the second parameter that application program execute*/
  16. #define IOCTL_GPIO_ON         1
  17. #define IOCTL_GPIO_OFF        0
  18. /* 用来指定LED所用的GPIO引脚 */
  19. /*appoint the pin the LED will use*/
  20. static unsigned long leds_table [] =
  21. {
  22.         S5PV210_MP04(4),
  23.         S5PV210_MP04(5),
  24.         S5PV210_MP04(6),
  25.         S5PV210_MP04(7),
  26.         //archarmmach-s5pv210includemachgpio.h
  27. };
  28. static char leds_name[][4]={{"LED1"},{"LED2"},{"LED2"},{"LED3"}};
  29. #define LED_NUM                ARRAY_SIZE(leds_table)
  30. /**
  31. *函数功能:打开/dev/led设备
  32. *fuction:open /dev/leds device
  33. *设备名是:/dev/leds
  34. *devce name: /dev/leds
  35. **/
  36. static int my_gpio_open(struct inode *inode, struct file *file)
  37. {
  38.      int i;
  39.      int err;

  40.      for (i = 0; i < LED_NUM; i++)
  41.      {
  42.          err = gpio_request(leds_table[i], leds_name[i]);
  43.          //drivers/gpio/gpiolib.c
  44.          if(err)
  45.          {
  46.             printk(KERN_ERR "failed to request S5PV210_GPH2(%d) for LED%d n",i-1,i);
  47.             return err;
  48.          }
  49.      }

  50.      for (i = 0; i < LED_NUM; i++)
  51.      {
  52. //        s3c_gpio_cfgpin(leds_table[i], gpio_cfg_table[i]);//Configuration pin function:input output multiplex
  53. //        s3c_gpio_setpin(leds_table[i], 0);//Set the pin level
  54.         //archarmplat-samsunggpio-config.c
  55.         gpio_direction_output(leds_table[i], 0);//write a value to GPIO port ,also set the port to output mode
  56.         gpio_set_value(leds_table[i], 0);
  57.         //drivers/gpio/gpiolib.c

  58.      }
  59.     printk(KERN_INFO "LEDs driver successfully closen");
  60.      return 0;
  61. }
  62. /**
  63. *函数功能:用于控制led的亮灭
  64. *fuction:control the led /turn on & turn off
  65. *控制字为cmd,arg为控制哪个灯的亮灭取值范围为0-1:cmd为IOCTL_GPIO_ON时亮,cmd为IOCTL_GPIO_OFF为灭
  66. *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.
  67. **/
  68. static int my_gpio_ioctl(
  69.          struct inode *inode,
  70.          struct file *file,
  71.          unsigned int cmd,
  72.          unsigned long arg)
  73. {
  74.      arg -= 1;
  75.      if (arg > LED_NUM)
  76.      {
  77.         return -EINVAL;
  78.      }
  79.      switch(cmd)
  80.      {
  81.         case IOCTL_GPIO_ON:
  82.         {
  83.             // 设置指定引脚的输出电平为1
  84.             gpio_direction_output(leds_table[arg], 1);
  85.             //s3c_gpio_setpin(leds_table[arg], 1);
  86.             return 0;
  87.         }

  88.         case IOCTL_GPIO_OFF:
  89.         {
  90.             // 设置指定引脚的输出电平为0
  91.             gpio_direction_output(leds_table[arg], 0);
  92.             //s3c_gpio_setpin(leds_table[arg], 0);
  93.             return 0;
  94.         }

  95.         default:return -EINVAL;
  96.      }
  97. }
  98. /**
  99. *函数功能:/dev/led设备
  100. *fuction:open /dev/led device
  101. **/
  102. static int my_gpio_close(struct inode *inode, struct file *file)
  103. {
  104.      gpio_free(leds_table[0]);
  105.      gpio_free(leds_table[1]);
  106.      gpio_free(leds_table[2]);
  107.      gpio_free(leds_table[3]);
  108.      printk(KERN_INFO "LEDs driver successfully closen");
  109.      return 0;
  110. }
  111. /*驱动接口设置*/
  112. /*setting the interface of the driver*/
  113. static struct file_operations my_dev_fops = {
  114.          .owner     =       THIS_MODULE,
  115.          .ioctl     =       my_gpio_ioctl,
  116.          .open      =       my_gpio_open,
  117.          .release   =       my_gpio_close,
  118. };
  119. /*设备结构的设置*/
  120. /*setting the architecture of the device*/
  121. static struct miscdevice misc = {
  122.          .minor = MISC_DYNAMIC_MINOR,
  123.          .name = DEVICE_NAME,
  124.          .fops = &my_dev_fops,
  125. };
  126. /*初始化设备,配置对应的IO,以及注册设备*/
  127. /*init the device, config the right IO and register the device*/
  128. static int __init dev_init(void)
  129. {
  130.      int ret;

  131.      ret = misc_register(&misc);
  132.      printk(KERN_INFO "LEDs driver successfully probedn");
  133.      return ret;
  134.     }
  135. /*注销设备*/
  136. /*log out the device*/
  137. static void __exit dev_exit(void)
  138. {
  139.      misc_deregister(&misc);
  140.      gpio_free(leds_table[0]);
  141.      gpio_free(leds_table[1]);
  142.      gpio_free(leds_table[2]);
  143.      gpio_free(leds_table[3]);
  144.      printk(KERN_INFO "LEDs driver successfully exitn");
  145. }
  146. module_init(dev_init);
  147. module_exit(dev_exit);
  148. MODULE_LICENSE("GPL");
  149. MODULE_AUTHOR("gjianw217@163.com");
  150. MODULE_DESCRIPTION("LEDS' Driver");
复制代码
2 应用程序:
  1. #include
  2. #include
  3. #include
  4. #include

  5. #define DEVICENAME "/dev/leds"
  6. #define IOCTL_LED_ON 1
  7. #define IOCTL_LED_OFF 0

  8. int main(int argc, char **argv)
  9. {
  10.     int fd;
  11.     int times=1;
  12.     fd = open(DEVICENAME,0);
  13.     if(fd<0)
  14.     {
  15.         printf("driver not or dev name notn");
  16.         return fd;
  17.     }

  18.     printf("LED flow statring to workn");
  19.     while(1)
  20.     {
  21.         printf("LED flow work %d timesn",times++);
  22.         ioctl(fd,IOCTL_LED_ON,1);
  23.         ioctl(fd,IOCTL_LED_OFF,2);
  24.         ioctl(fd,IOCTL_LED_OFF,3);
  25.         ioctl(fd,IOCTL_LED_OFF,4);
  26.         sleep(1);
  27.         ioctl(fd,IOCTL_LED_OFF,1);
  28.         ioctl(fd,IOCTL_LED_ON,2);
  29.         ioctl(fd,IOCTL_LED_OFF,3);
  30.         ioctl(fd,IOCTL_LED_OFF,4);

  31.         sleep(1);
  32.         ioctl(fd,IOCTL_LED_OFF,1);
  33.         ioctl(fd,IOCTL_LED_OFF,2);
  34.         ioctl(fd,IOCTL_LED_ON,3);
  35.         ioctl(fd,IOCTL_LED_OFF,4);
  36.         sleep(1);
  37.         ioctl(fd,IOCTL_LED_OFF,1);
  38.         ioctl(fd,IOCTL_LED_OFF,2);
  39.         ioctl(fd,IOCTL_LED_OFF,3);
  40.         ioctl(fd,IOCTL_LED_ON,4);
  41.         sleep(1);

  42.     }
  43.     close(fd);
  44.     return 0;
  45. }
复制代码
3 Makefile:
  1. #leds Makefile
  2. ARCH=arm
  3. CROSS_COMPILE=/home/ok210/arm-2009q3/bin/arm-none-linux-gnueabi-
  4. APP_COMPILE=/home/ok210/arm-2009q3/bin/arm-none-linux-gnueabi-
  5. #obj-m := app-drv.o
  6. obj-m := keys-drv.o
  7. #KDIR := /path/to/kernel/linux/
  8. KDIR := /home/ok210/android-kernel-samsung-dev/
  9. PWD := $(shell pwd)
  10. default:
  11.         make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
  12. app:keys-app.c
  13.         $(APP_COMPILE)gcc -o app keys-app.c
  14. clean:
  15.         $(MAKE) -C $(KDIR) M=$(PWD) clean
复制代码
欢迎大家关注本人的微信公众号【口袋物联】,微信号为koudaiwulian

4个回复

chkconfig 发表于 2015-8-21 13:21:11
S5PV210引脚的具体定义在哪里找的,资料中好像没有那个路径
gjianw217 发表于 2015-8-21 15:11:06
本帖最后由 gjianw217 于 2015-8-23 11:35 编辑
chkconfig 发表于 2015-8-21 13:21
S5PV210引脚的具体定义在哪里找的,资料中好像没有那个路径

麻烦你认真读一下上面的文章,尤其是:“二、软件基础中的1 Linux中的GPIO引脚定义”的第一段的最后一句话!
chkconfig 发表于 2015-8-27 22:29:24
gjianw217 发表于 2015-8-21 15:11
麻烦你认真读一下上面的文章,尤其是:“二、软件基础中的1 Linux中的GPIO引脚定义”的第一段的最后一句话!

我的是OK210 V1.1Linux内核源码linux2.6.35.7android-kernel-samsung-devarcharmmach-s5pv210includemach,可能稍微点出入,但也找到了,,多谢
刘德义 发表于 2016-4-30 17:35:25
感谢楼主分享,写的非常好
您需要登录后才可以回帖 登录 | 注册

本版积分规则


关闭

站长推荐上一条 /6 下一条

小黑屋|手机版|Archiver|电子发烧友 ( 湘ICP备2023018690号 )

GMT+8, 2024-11-30 18:08 , Processed in 0.712316 second(s), Total 70, Slave 49 queries .

Powered by 电子发烧友网

© 2015 bbs.elecfans.com

微信扫描
快速回复 返回顶部 返回列表