实验内容介绍见《GEC210嵌入式系统开发教材20131120(更新)》第84页--“5.2 嵌入式 Linux 的 LED 实验”
misc设备驱动模型分析:http://blog.csdn.net/alan445947767/article/details/38849413
5.2 嵌入式 Linux 的 LED 实验
实验目的:
1、 掌握基本的字符设备的驱动程序设计。
2、 掌握基本的文件操作。
3、 掌握在操作系统下对普通 IO 端口的使用方法
实验内容:
1、 阅读 S5PV210 的数据手册,熟悉 GPIO 端口的原理。
2、 编写 LED 应用程序。
3、 编写 Makefile 文件。
4、 下载并调试 LED 跑马灯应用程序。
预备知识:
1、 C 语言基础知识。
2、 Linux 下常用命令的使用及 vim 编辑器的使用
3、 程序调试的基础知识和方法。
4、 ARM 应用程序的基本架构。
实验设备及工具:
1、 硬件:GEC210 开发板
2、 PC 操作系统 ubuntu10.04 、minicom、arm-linux-交叉开发环境。
基础知识:
1、 硬件原理:
a) 原理图:
b) 寄存器简介:
GPJ2CON 为 GPIO 端口引脚功能控制寄存器,每个引脚占 4 位,如:GPJ2CON0[3:0]设置为输出功能时,
GPJ2CON0[3:0]=0001
GPJ2PUD 寄存器用于设置 GPJ2 引脚的上拉电阻或者下拉电阻的使能。
实验原理:
1、 该驱动设计为一个字符设备,主要通过驱动提供的 ioctl 函数来实现对相应 IO 引脚
的置高与置低,以此来实现对 LED 灯的关闭和打开。
驱动程序代码:
< driver / led.c >
/*
*
*This is a led driver test.(2014/8/26)
*The author is Alan
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME "leds"
static int led_gpios[]={
S5PV210_GPJ2(0),
S5PV210_GPJ2(1),
S5PV210_GPJ2(2),
S5PV210_GPJ2(3),
};
#define LED_NUM ARRAY_SIZE(led_gpios)
//实现系统的IO控制命令
static long gec210_leds_ioctl(struct file *flip,unsigned int cmd,
unsigned long arg)
{
switch(cmd)
{
case 0:
case 1:
if(arg>LED_NUM)
return -EINVAL;
gpio_set_value(led_gpios[arg],cmd);//(原代码有错)
break;
default:
return -EINVAL;
}
return 0;
}
//初始化file_operations结构体,实现系统调用
static struct file_operations gec210_led_dev_fops={
.owner = THIS_MODULE,
.unlocked_ioctl = gec210_leds_ioctl,
};
//初始化杂项设备结构体
static struct miscdevice gec210_led_dev={
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &gec210_led_dev_fops,
};
//驱动装载函数
static int __init gec210_led_dev_init(void)
{
int ret;
int i;
for(i=0;i
ifneq ($(KERNELRELEASE),)
obj-m :=led.o
else
module-objs :=led.o
KERNELDIR :=/home/gec/linux_kernel/linux2.6.35.7/
PWD :=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
clean:
$(RM) *.ko *.mod.c *.mod.o *.o *.order *.symvers *.cmd
< app / led_test.c >
#include
#include
#include
#include
#include
#include
#define IOCTL_LED_ON 0
#define IOCTL_LED_OFF 1
void usage(char *exename)//使用说明
{
printf("Usage:\n");
printf(" %s \n",exename);
printf(" led_no=1,2\n");
}
int main(int argc, char **argv)
{
unsigned int led_no;
int fd = -1;
if(argc != 3)
{
goto err;
}
fd = open("/dev/leds",O_RDWR);//打开文件
if(fd < 0)
{
printf("Can't open /dev/leds\n");
return -1;
}
led_no = strtoul(argv[1],0,0) - 1;//获取LED号
if (led_no > 3)
goto err;
if(!strcmp(argv[2],"on"))
{
ioctl(fd,IOCTL_LED_ON,led_no); //点亮LED灯
}
else if(!strcmp(argv[2],"off"))
{
ioctl(fd,IOCTL_LED_OFF,led_no);//熄灭LED灯
}
else
{
goto err;
}
close(fd);
return 0;
err:
if(fd > 0)
close(fd);
usage(argv[0]);
return -1;
}
< app / Makefile >
#
# General Makefile
Exec := led_test
Obj := led_test.c
CC := arm-linux-gcc #此编译器需根据自己的内核编译器来更改
$(Exec) : $(Obj)
$(CC) -o $@ $(Obj) $(LDLIBS$(LDLIBS-$(@)))
clean:
rm -vf $(Exec) *.elf *.o