zoukankan      html  css  js  c++  java
  • 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 ");  
    76.     rc=register_chrdev(LED_MAJOR,"led",&led_fops);  
    77.     if(rc<0)  
    78.     {  
    79.         printk("register %s char dev error ","led");  
    80.         return -1;  
    81.     }  
    82.     printk("OK! ");  
    83.     return 0;  
    84. }  
    85.   
    86. void __exit led_exit(void)  
    87. {  
    88.     unregister_chrdev(LED_MAJOR,"led");  
    89.     printk("module exit ");  
    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 来开启日志功能。

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

  • 相关阅读:
    MXCMS List标签说明
    c# 测量运行时间的方法
    简单的定时任务
    jQuery实现的简单文字提示效果模拟title
    ECSHOP设置默认配送方式和默认支付方式
    asp 里sql防止注入的方法
    asp.net上传图片并生成水印与缩略图的代码
    定时备份并清除系统日志的shell代码
    sql server 2005 万能分页存储过程
    01.部署NopCommerce时遇到的问题
  • 原文地址:https://www.cnblogs.com/zhaoshuireshui/p/3706109.html
Copyright © 2011-2022 走看看