手把手教你学linux驱动开发 OK6410系列之03---LED字符设备驱动


   上一篇文章我们介绍了字符设备驱动程序的框架,本篇文章我们将操作真实的硬件---LED。

作者:沧海猎人   出处:http://blog.csdn.net/embedded_hunter转载请注明出处   嵌入式技术交流QQ群:179012822

一、实验环境 

开发机环境

操作系统:ubuntu 9.10

交叉编译环境:arm-linux-gcc 4.2.2 ,安装位置 /usr/local/arm/4.3.2/

6410板子内核源码路径:/work/linux-2.6.36.2-v1.05/      

目标板环境:OK6410-A     linux2.6.36

二、实验原理

控制LED是最简单的一件事情,我们学习LED驱动程序,就相当于学习其他编程语言是的“hello  world”程序一样,是一个入门的程序。

学习驱动程序,必须要对硬件有所了解,接下来看几个与硬件相关的材料。

OK6410  LED原理图

OK6410  LED原理图 

从上面的原理图可以得知,LED与CPU引脚的连接方法如下,低电平点亮。

LED1 -GPM0

LED2 -GPM1

LED3 -GPM2

LED4 -GPM3

从数据手册可以找到相应的控制方法。这里我们以LED1为例,介绍一下LED1的操作方法,其他的类似,请大家自行分析。

通过上面可以得知,需要先将GPM0设置为输出方式。将相应的寄存器进行配置。

然后将GPMDAT寄存器的第0位置0灯亮,置1灯灭。

三、实验步骤

1、编写驱动程序

driver_led.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <linux/module.h>  
  
#include <linux/kernel.h>  
#include <linux/fs.h>  
#include <asm/uaccess.h> /* copy_to_user,copy_from_user */  
#include <linux/miscdevice.h>    
#include <linux/pci.h>    
#include <mach/map.h>    
#include <mach/regs-gpio.h>    
#include <mach/gpio-bank-m.h>    
#include <plat/gpio-cfg.h>  
  
#define LED_MAJOR 240  
  
int  led_open ( struct  inode *inode, struct  file *filp)  
  
{  
unsigned tmp;     
tmp = readl(S3C64XX_GPMCON);     
tmp = (tmp & ~(0x7U<<1))|(0x1U);     
writel(tmp, S3C64XX_GPMCON);   
printk( "#########open######\n" );  
return  0;  
}  
  
ssize_t led_read ( struct  file *filp,  char  __user *buf,  size_t  count,loff_t *f_pos)  
{  
printk( "#########read######\n" );  
return  count;  
}  
  
  
ssize_t led_write ( struct  file *filp,  const  char  __user *buf,  size_t  count,loff_t *f_pos)  
{  
char  wbuf[10];  
unsigned tmp;     
printk( "#########write######\n" );  
copy_from_user(wbuf,buf,count);  
switch (wbuf[0])  
{  
case  0:   //off  
tmp = readl(S3C64XX_GPMDAT);     
tmp |= (0x1U);     
writel(tmp, S3C64XX_GPMDAT);  
break ;  
case  1:   //on  
tmp = readl(S3C64XX_GPMDAT);     
tmp &= ~(0x1U);     
writel(tmp, S3C64XX_GPMDAT);  
break ;  
default  :  
break ;  
}  
return  count;  
}  
  
int  led_release ( struct  inode *inode,  struct  file *filp)  
{  
printk( "#########release######\n" );  
return  0;  
}  
  
struct  file_operations led_fops ={  
.owner = THIS_MODULE,  
.open = led_open,  
.read = led_read,  
.write = led_write,  
.release = led_release,  
};  
  
int  __init led_init ( void )  
{    int  rc;  
printk ( "Test led dev\n" );  
rc = register_chrdev(LED_MAJOR, "led" ,&led_fops);  
if  (rc <0)  
{  
printk ( "register %s char dev error\n" , "led" );  
return  -1;  
}  
printk ( "ok!\n" );  
return  0;  
}  
  
void  __exit led_exit ( void )  
{  
unregister_chrdev(LED_MAJOR, "led" );  
printk ( "module exit\n" );  
return  ;  
}  
  
module_init(led_init);  
module_exit(led_exit);  


Makefile文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
obj-m := driver_led.o  
KDIR :=/work/linux-2.6.36.2-v1.05/  
all:  
make -C $(KDIR) M=$(shell pwd) modules  
install:  
cp driver_led.ko /tftpboot/  
clean:  
make -C $(KDIR) M=$(shell pwd) clean  
obj-m := driver_led.o
KDIR :=/work/linux-2.6.36.2-v1.05/
all:
     make -C $(KDIR) M=$(shell pwd) modules
install:
     cp driver_led.ko /tftpboot/
clean:
     make -C $(KDIR) M=$(shell pwd) clean


2、编写测试程序

test.c


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
int  main ( void )  
{  
int  fd;  
char  buf[10]={0,1};  
fd = open( "/dev/my_led" ,O_RDWR);  
if  (fd < 0)  
{  
printf  ( "Open /dev/my_led file error\n" );  
return  -1;  
}     
while (1)  
{  
write(fd,&buf[0],1);  
sleep(1);  
write(fd,&buf[1],1);  
sleep(1);  
}  
close (fd);  
return  0;  
  
}


 
 

3、编译驱动程序与测试程序

编译驱动程序

#make

将驱动程序放到tftp的工作目录 /tftpboot

#make install

编译测试程序

#arm-linux-gcc  test.c  -o  test

将测试程序放到tftp的工作目录 /tftpboot

#cp  test  /tftpboot

4、将程序下载到开发板

将开发板的IP地址修改,与主机在同一个网段。确保PC的tftp服务开启。

下载程序到开发板

SMDK6410#   tftp -l /lib/modules/2.6.36.2/driver_led.ko -r  driver_led.ko  -g  192.168.1.111        192.168.1.111为服务器IP

SMDK6410#   tftp -l test  -r test  -g  192.168.1.111         

5、测试

加载驱动   #insmod  /lib/modules/2.6.36.2/driver_led.ko

创建设备文件   #mknod  /dev/my_led  c   240  0

测试  ./test

[root@FORLINX6410]# ./test
此时可以看到OK6410板子上的LED0在闪烁。

卸载驱动  #rmmod   driver_led

从上面的结果我们可以看到,当用户调用相应的文件操作函数时,驱动程序中的相应的函数也会被调用。

大家可以修改相应程序,测试一下其他的情况。

作者:沧海猎人   出处:http://blog.csdn.net/embedded_hunter转载请注明出处   嵌入式技术交流QQ群:179012822

备注: 本驱动使用了最基本的内核函数,可能操作方法与你看过的其他驱动程序不太一样,尤其注册字符设备的函数。   没关系,我们会一步一步介绍相关的其他函数。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值