【原创】Tiny6410简单驱动 --- LED控制


【原创】Tiny6410简单驱动 --- LED灯控制


编写驱动之前记住一个原则:驱动程序提供机制而不提供策略,即驱动只管做什么,怎么做的问题交给应用程序。

依据上述原则,此文的简单驱动只实现四个LED的开和关,而要怎样用这开和关就交给应用程序。

LED硬件结构和相关寄存器

如下图,应设置输出模式(即cpu向LED管脚输出信号),低电平点亮,高电平熄灭。

my_led_module.c源代码(驱动程序)

驱动程序的构建方式和其Makefile文件参考链接http://blog.csdn.net/geng823/article/details/37355109#t4

<span style="font-size:18px;"><span style="font-size:18px;">#include <linux/miscdevice.h>

#include <linux/delay.h>

#include <asm/irq.h>

#include <mach/hardware.h>

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/init.h>

#include <linux/mm.h>

#include <linux/fs.h>

#include <linux/types.h>

#include <linux/delay.h>

#include <linux/moduleparam.h>

#include <linux/slab.h>

#include <linux/errno.h>

#include <linux/ioctl.h>

#include <linux/cdev.h>

#include <linux/string.h>

#include <linux/list.h>

#include <linux/pci.h>

#include <asm/uaccess.h>

#include <asm/atomic.h>

#include <asm/unistd.h>


#include <mach/map.h>

#include <mach/regs-clock.h>

#include <mach/regs-gpio.h>

#include <plat/gpio-cfg.h>

#include <mach/gpio-bank-e.h>

#include <mach/gpio-bank-k.h>


#define DEVICE_NAME	"my_led" //设备名称设为 my_led
#define ALL_LED_ON	0<span style="white-space:pre">	</span>//四个灯全点亮
#define ALL_LED_OFF	1<span style="white-space:pre">	</span>//四个灯全熄灭

static long s3c6410_leds_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)

{

	switch(cmd) {

		unsigned tmp;

		case ALL_LED_ON:	//四个灯全亮

			tmp = readl(S3C64XX_GPKDAT);

			tmp &= ~(0xF << 4);

			writel(tmp, S3C64XX_GPKDAT);

			break;

		case ALL_LED_OFF:	//四个灯全灭

			tmp = readl(S3C64XX_GPKDAT);

			tmp |= (0xF << 4);

			writel(tmp, S3C64XX_GPKDAT);

			break;

		default:

			return -EINVAL;

	}

}

static struct file_operations dev_fops = {

	.owner			= THIS_MODULE,

	.unlocked_ioctl	= s3c6410_leds_ioctl,

};

static struct miscdevice misc = {

	.minor = MISC_DYNAMIC_MINOR,

	.name = DEVICE_NAME,

	.fops = &dev_fops,

};

static int __init dev_init(void)

{
	int ret;

	{
		unsigned tmp;
	
		//将S3C64XX_GPKCON配制成输出,0xffffU<<16表示控制四个LED灯

		tmp = readl(S3C64XX_GPKCON);

		tmp = (tmp & ~(0xffffU<<16))|(0x1111U<<16);

		writel(tmp, S3C64XX_GPKCON);

		//低电平有效,初始时将四个灯都关掉

		tmp = readl(S3C64XX_GPKDAT);

		tmp |= (0xF << 4);

		writel(tmp, S3C64XX_GPKDAT);

	}

	ret = misc_register(&misc);//注册杂项设备

	printk (DEVICE_NAME"\tinitialized\n");

	return ret;
}



static void __exit dev_exit(void)

{

	misc_deregister(&misc);//注销杂项设备

	printk (DEVICE_NAME"\tuninstalled\n");

}

module_init(dev_init);

module_exit(dev_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("GENG");</span></span>


my_led.c源代码(应用程序)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdlib.h>


#define ALL_LED_SPLASH	'r'	//四个灯间隔1s同时闪烁
#define ALL_LED_STOP	's'	//四个灯停止闪烁
#define DEVICE_QUIT	'q'	//设备退出
#define ALL_LED_ON	0	//四个灯全点亮
#define ALL_LED_OFF	1	//四个灯全熄灭



/*
 * 此函数用来获得从键盘输入的一个字符,也可以直接在主函数中用getchar()获得
 */
static int getch(void)
{
	struct termios oldt,newt;
	int ch;

	if (!isatty(STDIN_FILENO)) {
		fprintf(stderr, "this problem should be run at a terminal\n");
		exit(1);
	}
	// save terminal setting
	if(tcgetattr(STDIN_FILENO, &oldt) < 0) {
		perror("save the terminal setting");
		exit(1);
	}

	// set terminal as need
	newt = oldt;
	newt.c_lflag &= ~( ICANON | ECHO );
	if(tcsetattr(STDIN_FILENO,TCSANOW, &newt) < 0) {
		perror("set terminal");
		exit(1);
	}

	ch = getchar();

	// restore termial setting
	if(tcsetattr(STDIN_FILENO,TCSANOW,&oldt) < 0) {
		perror("restore the termial setting");
		exit(1);
	}
	return ch;
}


int main(int argc, char **argv)
{
	int fd;
	//打开设备
	fd = open("/dev/my_led", 0);
	if (fd < 0) {
		fd = open("/dev/my_led", 0);
	}
	if (fd < 0) {
		perror("open device my_led");
		exit(1);
	}

	printf( "\nmy_led TEST ( led Control )\n" );
	
	while(1)
	{
		int c;
		int i;
		c = getch();

		//通过输入的字符选择功能
		//注意:输入字符后,需要再按回车键
		switch(c) {
		case ALL_LED_SPLASH: //四个led灯同时以1s的间隔闪烁
			for (i = 0; i < 10; i++){
				ioctl(fd, ALL_LED_ON);//同时亮
				sleep(1);//睡一秒
				ioctl(fd, ALL_LED_OFF);//同时灭
				sleep(1);//睡一秒
			}
			break;
		case ALL_LED_STOP: //四个灯全灭
			ioctl(fd, ALL_LED_OFF);// 
			break;
		case DEVICE_QUIT://关闭设备,退出
			close(fd);
			exit(0);
		default://其他字符,继续等待输入
			break;
		}
	}
	return 0;
}

应用程序的Makefile

<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"># ----------------------------------------------------------------------------
# Makefile for building tapp
#
# Copyright 2010 FriendlyARM (http://www.arm9.net/)
#

ifndef DESTDIR
DESTDIR			   ?= /tmp/FriendlyARM/mini6410/rootfs
endif

CFLAGS				= -Wall -O2
CC					= arm-linux-gcc
INSTALL				= install

TARGET				= my_led


all: $(TARGET)

led: my_led.c
	$(CC) $(CFLAGS) $< -o $@


install: $(TARGET)
	$(INSTALL) $^ $(DESTDIR)/usr/bin

clean distclean:
	rm -rf *.o $(TARGET)


# ----------------------------------------------------------------------------

.PHONY: $(PHONY) install clean distclean

# End of file
# vim: syntax=make
</span></span></span>

原文链接http://blog.csdn.net/geng823/article/details/37531187

posted @ 2014-07-07 20:29  GengLUT  阅读(464)  评论(0编辑  收藏  举报