linux驱动开发之路(一)--LED驱动(misc设备)

实验内容介绍见《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 <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/delay.h>

#include <mach/gpio.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>

#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<LED_NUM;i++)//轮询请求IO资源
	{
		ret=gpio_request(led_gpios[i],"LED");
		if(ret)//请求不成功
		{
			printk("%s: request GPIO %d for LED failed,ret = %d\n",
				DEVICE_NAME,led_gpios[i],ret);
			return ret;
		}
		s3c_gpio_cfgpin(led_gpios[i],S3C_GPIO_OUTPUT);//配置GPIO为输出
		gpio_set_value(led_gpios[i],1);//设置GPIO输出1,即LED灭
	}
	ret = misc_register(&gec210_led_dev);  //注册杂项设备
	printk("\t%s initalized\n",DEVICE_NAME);//(原代码有错)
	return ret;
}

//驱动卸载函数
static void __exit gec210_led_dev_exit(void)
{
	int i;
	
	for(i=0; i<LED_NUM;i++)//轮询释放IO资源
		gpio_free(led_gpios[i]);
	misc_deregister(&gec210_led_dev);//注销杂项设备
}

module_init(gec210_led_dev_init);
module_exit(gec210_led_dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ALAN");


< driver / Makefile >

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 <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>

#define IOCTL_LED_ON 0
#define IOCTL_LED_OFF 1

void usage(char *exename)//使用说明
{
	printf("Usage:\n");
	printf("   %s <led_no> <on/off>\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


测试效果:








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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值