【Linux驱动】TQ2440 LED驱动程序

★总体介绍

LED驱动程序主要实现了TQ2440开发板上的4个LED灯的硬件驱动,实现了对引脚GPIOB5、GPIOB6、GPIOB7、GPIOB8的高低电平设置(common-smdk.c中已经实现了对引脚的配置),利用测试程序调用该驱动程序,通过命令控制LED灯的亮灭。

★详细介绍

1、驱动程序代码:My_led.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/device.h>

#define DEVICE_NAME  "My_led" /**加载模块后执行cat/proc/devices中看到的设备名称**/
#define Led_MAJOR         103         /**主设备号**/
#define LED_ON        1
#define LED_OFF       0 

/**Led的控制引脚**/
static unsigned long led_table[ ] =
{
    S3C2410_GPB5,
    S3C2410_GPB6,
	S3C2410_GPB7,
	S3C2410_GPB8,
};

static int My_led_open(struct inode *inode,struct file *file)
{
    printk("My_led  open\n");
    return 0;
}

static int My_led_ioctl(struct inode * inode, struct file * file,unsigned int cmd,unsigned long arg)
{
	if(arg > 4)
	{
		return -1;
       }
	switch(cmd)
	{
     		case LED_ON:
				s3c2410_gpio_setpin(led_table[arg], 0);//设置指定引脚为输出电平为0
  				return 0;
	        case LED_OFF:
	            s3c2410_gpio_setpin(led_table[arg], 1);//设置指定引脚为输出电平为1
	            return 0;
   		default:
				return  -1;
	}
}

static struct file_operations My_led_fops =
{
	.owner = THIS_MODULE,
	.open = My_led_open,
	.ioctl = My_led_ioctl,
};

static struct class *led_class;

static int __init My_led_init(void)
{
	int ret;
	printk("My_led start\n");

	 /**注册字符设备驱动程序**/
	 /**参数为主设备号、设备名字、file_operations结构**/
	 /**这样主设备号就与file_operations联系起来**/
	 ret = register_chrdev(Led_MAJOR, DEVICE_NAME, &My_led_fops);
	 if(ret < 0)
	 {
		printk("can't register major number\n");
		return ret;
	 }

	//注册一个类,使mdev可以在"/dev/目录下建立设备节点"
	led_class = class_create(THIS_MODULE, DEVICE_NAME);
	if(IS_ERR(led_class))
	{
		printk("failed in My_led class.\n");
		return -1;
	}
	device_create(led_class, NULL, MKDEV(Led_MAJOR,0), NULL, DEVICE_NAME);
	printk(DEVICE_NAME "initialized\n");
	return 0;

}

static void __exit My_led_exit(void)
{
    unregister_chrdev(Led_MAJOR, DEVICE_NAME);
    device_destroy(led_class, MKDEV(Led_MAJOR,0));//注销设备节点
   class_destroy(led_class);//注销类
}

module_init(My_led_init);
module_exit(My_led_exit);

MODULE_LICENSE("GPL");

2、宏定义

#define DEVICE_NAME  "My_led" //加载模块后执行cat/proc/devices中看到的设备名称

#define Led_MAJOR         103         //主设备号

#define LED_ON        1

#define LED_OFF       0 My_led_ioctl函数中要输入的参数命令,LED_ON会执行打开灯的命令、LED_OFF执行关闭灯的命令

3、Led灯的引脚控制

定义一个led_table[ ] 数组,在后面调用时要方便些。

详细说明一下S3C2410_GPB5是什么意思:

如上图所示,是关于S3C2410_GPB5相关的所有代码。通过上面的代码可以得出S3C2410_GPB5为37。实际上S3C2410_GPB5就是端口的编号,bank是分组的基号码,offset是组内的偏移量。TQ2440开发板的GPIOB的第五个引脚为37。

4、My_led_ioctl()函数

此函数主要负责响应应用程序的相关命令,然后根据命令执行相关的代码。cmd命令包括宏定义的LED_ON、LED_OFF。

s3c2410_gpio_setpin()函数

自认为这是本驱动程序最重要的一个函数,它的作用是:将指定的引脚设置为低电平或者高电平。本驱动程序中只是用了内核提供的这一个接口来实现对引脚的控制,但是肯定会研究一下这个函数。

5、注册一个类

如果不注册这个类,那么当在开发板上挂载驱动之后,还要做的一件事是手动“生成设备节点”,就是利用mknod命令。但是驱动程序都是随操作系统的运行而开始工作的,因此生成设备节点要让它自动生成,而并非手动。所以才会注册这样一个类,在挂载驱动之后,自动将设备节点生成。注册类的核心代码:

led_class = class_create(THIS_MODULE, DEVICE_NAME);
	if(IS_ERR(led_class))
	{
		printk("failed in My_led class.\n");
		return -1;
	}
	device_create(led_class, NULL, MKDEV(Led_MAJOR,0), NULL, DEVICE_NAME);

6、测试程序

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

int main()
{
    int fd,i,cmd;
    fd=open("/dev/My_led",0);
    if (fd<0)
    {
        printf("open led_driver error");
        exit(1);
    }
    while(1)
    {
	    scanf("%d",&cmd);
	    switch(cmd)
	    {
		case 0:
		    printf("All off\n");
		    for(i = 0;i < 4;i ++)
		    ioctl(fd,0,i);
		    break;
		case 1:
		    printf("light first led\n");
		    ioctl(fd,1,0);
		    break;
		case 2:
		    printf("light second led\n");
                    ioctl(fd,0,0);
		    ioctl(fd,1,1);
		    break;
		case 3:
		    printf("light third led\n");
                    ioctl(fd,0,1);
		    ioctl(fd,1,2);
		    break;
		case 4:
		    printf("light fourth led\n");
                    ioctl(fd,0,2);
		    ioctl(fd,1,3);
		    break;
		case 5:
		    printf("All light \n");
		    for(i = 0;i < 4;i ++)
		    ioctl(fd,1,i);
		    break;
		default:
                    i = 10;
		    break;

	    }
            if (i == 10)
                break;
    }

    return 0;
 }

★遇到的错误

1、找不到文件

这个错误的主要原因很可能是内核的版本不同,不同内核的头文件存放的路径不相同。因此,当编译驱动程序报错“找不到文件”时,检查头文件的路径是否正确

2、Makefile文件指定交叉编译器

下面是驱动程序的Makefile文件

#LED_makefile

KERNELDIR := /home/xg/linux_arm/linux-2.6.30.4/
PWD :=$(shell pwd)

all:
	make -C $(KERNELDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=/opt/opt/EmbedSky/4.3.3/bin/arm-linux-
test:
	/opt/opt/EmbedSky/4.3.3/bin/arm-linux-gcc -o test test.c
clean:
	rm -rf *.o *ko

obj-m :=My_led.o

当时出的错误就是编译器的路径没有搞清楚。

【Linux驱动】TQ2440 LED驱动程序,布布扣,bubuko.com

时间: 2024-10-12 21:49:17

【Linux驱动】TQ2440 LED驱动程序的相关文章

【Linux 驱动】设备驱动程序再理解

学习设备驱动编程也有一段时间了,也写过了几个驱动程序,因此有对设备驱动程序有了一些新的理解和认识,总结一下.学习设备驱动编程也有一段时间了,也写过了几个驱动程序,因此有对设备驱动程序有了一些新的理解和认识,总结一下. ★什么是驱动程序 刚开始学习设备驱动程序的时候,产生了许多的问题.什么是驱动程序?驱动程序是干嘛的?它是如何工作的?它又是如何跟操作系统联系起来的?一系列的问题,现在有些地方还是不一定清楚,但是相比起刚开始的那个阶段,感觉自己还是清楚了很多. 设备驱动程序说白了(实质)就是为应用程

《驱动学习 - LED驱动程序

1.编写LED驱动程序步骤 1.1 框架 1.2 完善硬件操作 1.2.1 查看原理图 1.2.2 看2440手册 1.2.3 写代码 其中需要注意的是:单片机通常直接用物理地址去操作寄存器.而这里要将物理地址映射为虚拟地址,用ioremap函数. 2.查看原理图 从mini2440的原理图可以看到,2440是低电平点亮LED.然后继续查看nLED引脚 所以对应的是: 查看上s3c2440芯片手册: 可以看到GPBCON和GPBDAT的物理地址,这个是后面点亮LED的需要操作的两个寄存器. 需要

Linux下的led驱动程序,ok6410

本程序采用动态映射的方法控制led,硬件平台为飞凌的ok6410 led.h:定义控制命令 #ifndef _LED_H #define _LED_H #define LED_MAGIC 'M' #define LED_ON _IO(LED_MAGIC, 0) #define LED_OFF _IO(LED_MAGIC, 1) #endif 驱动程序led.c #include <linux/module.h> #include <linux/init.h> #include &l

linux驱动之USB驱动程序

1. USB是主从结构的 所有的USB传输,都是从USB主机这方发起:USB设备没有"主动"通知USB主机的能力. 例子:USB鼠标滑动一下立刻产生数据,但是它没有能力通知PC机来读数据,只能被动地等得PC机来读. 2. USB的传输类型:a. 控制传输:可靠,时间有保证,比如:USB设备的识别过程b. 批量传输: 可靠, 时间没有保证, 比如:U盘c. 中断传输:可靠,实时,比如:USB鼠标d. 实时传输:不可靠,实时,比如:USB摄像头 3. USB传输的对象:端点(endpoin

linux驱动之触摸屏驱动程序

触摸屏归纳为输入子系统,这里主要是针对电阻屏,其使用过程如下 :当用触摸笔按下时,产生中断.在中断处理函数处理函数中启动ADC转换x,y坐标.ADC结束,产生ADC中断,在ADC中断处理函数里上报(input_event)启动定时器,再次启动定时器(可以处理滑动.长按),松开按键.其驱动程序的写法和之前写输入子系统的写法基本上一致.写出入口函数,出口函数并加以修饰,加入相关头文件,然后开始完善各函数,在入口函数中分配input_dev结构体,设置(能产生哪类事件,能产生这类事件中的哪些事件),注

TQ2440按键点亮LED驱动程序

一,硬件分析: 1.打开TQ2440的底板原理图找到按键测试的模块,如下图所示: 从图我们知道,控制按键k1 k2 k3 k4 的管脚为EINT1 EINT4 EINT2 EINT0 ,当按键按下时,管脚输出低电平,当按键没有被按下时,管脚输出高电平. 2.打开TQ2440核心板原理图找到EINT1  EINT4 EINT2 EINT0所对应的cpu控制引脚,如下图所示: 从图我们可以知道,EINT1  EINT4 EINT2 EINT0 对应的cpu控制引脚为GPF1 GPF4 GPF2 GP

驱动编程思想之初体验 --------------- 嵌入式linux驱动开发之点亮LED

这节我们就开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的住,不然真像一些人说的,学了一年嵌入式感觉还没找到门. 不能再扯了,涉及到linux的驱动开发知识面灰常广,再扯文章就会变得灰常长.首先还是回到led驱动的本身上,自从linux被移植到arm上后,做驱动开发的硬件知识要求有所降低,很多都回归到了软件上,这是系统编程的一大特点,当然 ,也不排除有很多

嵌入式linux驱动开发之点亮led未遂(驱动编程思想之初体验)

有了上两篇文章的基础,我们就可以开始开始进行实战啦!这里顺便说一下啊,出来做开发的基础很重要啊,基础不好,迟早是要恶补的.个人深刻觉得像这种嵌入式的开发对C语言和微机接口与原理是非常依赖的,必须要有深厚的基础才能hold的住,不然真像一些人说的,学了一年嵌入式感觉还没找到门. 另外实践很重要,一年多以前就知道了arm,那时整天用单片机的思维去yy着arm,直到前段时间弄来一块arm板,烧上linux系统后才知道,坑呀!根本不是那回事,所以实践是学习计算机类最重要的基本素质,如果整天看书,那基本上

Linux驱动——LED闪烁

连接开发板和PC,然后打开S3C开发板的电源开关,成功启动后,执行build.sh脚本文件编译和安装LED驱动.build脚本文件会自动将驱动的.ko文件上传到S3C开发板并安装. LED驱动会建立一个/dev/s3c5410_leds设备文件,该Linux驱动可以控制4个LED.通过向/dev/s3c6410_leds发送长度为1到4的字符串可以控制这4个LED的开关.也可以执行test_leds.sh脚本文件测试LED. 创建LED驱动的设备文件:1.使用cdev_init函数初始化cdev