首页 > 代码库 > LED驱动程序 S3C6410

LED驱动程序 S3C6410

这两天写了个LED驱动程序,网上也看了好多的帖子。

开始思路很清晰了,就是先看电路图,发现LED灯是接在GPM端口上的,

然后看S3C6410数据手册,先向GPMCON口写命令字,让GPM0-5设置为输出,再向GPMDAT口写数据字,在GPM0-5引脚拉低或拉高电平,

从而控制LED的亮灭。

1、电路图

很显然LED灯是接在GPM口引脚下面的

2、数据手册

3、LED驱动程序

 

 
  1. #include <linux/module.h>  
  2. #include <linux/kernel.h>  
  3. #include <linux/fs.h>  
  4. #include <linux/uaccess.h>    /*copy_to_user,copy_from_user*/  
  5. #include <linux/io.h>         /*inl(),outl()*/  
  6. #include <linux/miscdevice.h>  
  7. #include <linux/pci.h>  
  8.   
  9. static long S3C64XX_GPMCON=0xF4500820;   /*这里是虚拟地址,物理地址可以再S3C6410数据手册上找到。也可以根据物理地址,ioremap()获得虚拟地址。*/  
  10. static long S3C64XX_GPMDAT=0xF4500824;  
  11. #define LED_MAJOR 240                    /*主设备号*/  
  12.   
  13. int led_open(struct inode *inode,struct file *file)  
  14. {  
  15.     unsigned tmp;  
  16.     tmp=inl(S3C64XX_GPMCON);  
  17.     printk("the pre GPMCON is %x",tmp);  
  18.     tmp=inl(S3C64XX_GPMDAT);  
  19.     printk("the pre GPMDAT is %x",tmp);  
  20.     outl(0x00111111,S3C64XX_GPMCON);         /*向GPMCON命令端口写命令字,设置GPM0-5为output口*/  
  21.     printk("#############open#############");  
  22.     return 0;  
  23. }  
  24.   
  25. static ssize_t led_read(struct file *file,char __user *buf,size_t count,loff_t * f_pos)  
  26. {  
  27.     unsigned tmp=inl(S3C64XX_GPMDAT);  
  28.         int num=copy_to_user(buf,&tmp,count);  
  29.     if(num==0)  
  30.        printk("copy successfully");  
  31.     else printk("sorry  copy failly");  
  32.   
  33.     printk("the GPMDAT is %x.",tmp);  
  34.     return count;  
  35. }  
  36. static ssize_t led_write(struct file * file,const char __user * buf,size_t count,loff_t * f_pos)/*我是通过write()来控制LED灯的,也可以通过ioctl()来控制*/  
  37. {  
  38.     char kbuf[10];  
  39.     printk("###########write###########");  
  40.     int num=copy_from_user(kbuf,buf,count);  
  41.     if(num==0)  
  42.          printk("copy successfully");  
  43.         else printk("sorry  copy failly");  
  44.     printk("##the kbuf is %c",kbuf[0]);  
  45.     switch(kbuf[0])  
  46.     {  
  47.         case 0://off  
  48.             outl(0xff,S3C64XX_GPMDAT);  /*拉高GPMDAT[0:5]的引脚,使LED灯灭,因为LED是低电平有电流通过*/  
  49.             break;  
  50.         case 1://on  
  51.             outl(0x00,S3C64XX_GPMDAT);  /*拉低GPMDAT[0:5]的引脚,使LED灯亮*/  
  52.             break;  
  53.         default:  
  54.             break;  
  55.     }  
  56.     return count;  
  57. }  
  58.   
  59. int led_release(struct inode *inode,struct file *file)  
  60. {  
  61.     printk("#######release##########");  
  62.     return 0;  
  63. }  
  64.   
  65. struct file_operations led_fops={  
  66.     .owner = THIS_MODULE,  
  67.     .open = led_open,  
  68.     .read = led_read,  
  69.     .write = led_write,  
  70.     .release = led_release,  
  71. };  
  72. int __init led_init(void)  
  73. {  
  74.     int rc;  
  75.     printk("Test led dev\n");  
  76.     rc=register_chrdev(LED_MAJOR,"led",&led_fops);  
  77.     if(rc<0)  
  78.     {  
  79.         printk("register %s char dev error\n","led");  
  80.         return -1;  
  81.     }  
  82.     printk("OK!\n");  
  83.     return 0;  
  84. }  
  85.   
  86. void __exit led_exit(void)  
  87. {  
  88.     unregister_chrdev(LED_MAJOR,"led");  
  89.     printk("module exit\n");  
  90. }  
  91.   
  92. module_init(led_init);  
  93. module_exit(led_exit);  
 

写好源码后,写Makefile

 

 
  1. obj-m:=led_driver.o  
  2. KDIR:=/home/tmp/linux2.6.28  
  3. all:  
  4.     make -C $(KDIR) M=$(shell pwd) modules CROSS_COMPILE=/usr/local/arm/4.4.1/bin/arm-linux-  
 

/*之前make,出现一些问题,比如说缺少什么头文件啦之类,原来是没有建立内核树,到内核源码目录里面make一下就好了*/

 

写好驱动源代码和Makefile文件后就在本目录下make

之后生成了led_driver.ko文件,下载到开发板上

4、测试驱动程序

 

 
  1. #include <stdio.h>  
  2. #include <sys/types.h>  
  3. #include <sys/stat.h>  
  4. #include <fcntl.h>  
  5. /*#include <unistd.h>*/  
  6.   
  7. int main()  
  8. {  
  9.     printf("hello led device .");  
  10.     char buf[10]={0,1,0,1};  
  11.     int fd=open("/dev/led",2,0777);  
  12.     if(fd<0){  
  13.     printf("can‘t open led device");  
  14.     return -1;  
  15.     }  
  16.     printf("open the led device successfully.");  
  17.   
  18.     while(1)  
  19.     {  
  20.         int num=write(fd,&buf[0],1);  
  21.         if(num<0)  
  22.             printf("we set the led failly.");  
  23.         else printf("we set the led off");  
  24.         sleep(1);  
  25.         write(fd,&buf[1],1);  
  26.         printf("we set the led on");  
  27.         sleep(1);  
  28.     }  
  29.     close(fd);  
  30.     printf("bye led device .");  
  31.     return 0;  
  32. }     
 

 

arm-linux-gcc -o led_test.o led_test.c

编译好后,把led_test.o文件下载到开发板上

5、具体操作步骤

本人的OK6410开发板之前已装好linux-2.6.18内核的Linux系统,然后输shell命令

insmod led_driver.ko                                                  //加载led_driver.ko驱动到内核

mknod /dev/led c 240 0                                              //把led设备文件挂载到/dev/led上,c 代表字符设备 ,240 是主设备号 , 0 是次设备号

./led_test.o                                                                   //启动测试程序,点亮LED灯

 

注意:

在PC机上写ARM开发板的驱动程序,需要在PC(俗称上位机)上配置交叉编译工具链  arm-linux-

开始想不通过驱动程序,通过iopl(3);提升权限,直接操作硬件的,发现在ARM开发板上不能这么做。

原来以为只能写驱动程序的方式控制寄存器的,后来发现,mmap()那个“/dev/mem”文件系统也可以的。

开始在开发板上调试,cat /var/log/messages 查看printk的输出,发现什么也没有,原来需要输入shell命令 klogd 来开启日志功能。

祝大家在开发板上玩的愉快。