★整体介绍

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就是port的编号。bank是分组的基号码,offset是组内的偏移量。

这样算出来的S3c2410_GPB5 的值为37,他的作用是代表S3c2440中B组port的第五个引脚。

4、My_led_ioctl()函数

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

s3c2410_gpio_setpin()函数

自觉得这是本驱动程序最重要的一个函数,它的作用是:将指定的引脚设置为低电平或者高电平。

本驱动程序中仅仅是用了内核提供的这一个接口来实现对引脚的控制。如今来分析一下这个函数。

◇函数的作用

这个函数是设置s3c2440中引脚的高低电平的。

它的第一个參数是linux系统中关于引脚定义的一些宏。比如s3c2410_GPB5、s3c2410_GPB6等代表芯片的port引脚;还有一个參数就是一个值to。这个值代表0或者1。

◇此函数是怎样设置高低电平的

首先贴出此函数的定义在内核版本号Linux2.6.30.4/arch/arm/plat-s3c24xx/gpio.c中

void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
unsigned long flags;
unsigned long dat; local_irq_save(flags); dat = __raw_readl(base + 0x04);
dat &= ~(1 << offs);
dat |= to << offs;
__raw_writel(dat, base + 0x04); local_irq_restore(flags);
}

先来分析第一个函数S3C24XX_GPIO_BASE(pin)

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驱动程序的更多相关文章

  1. linux驱动之LED驱动

    通过之前的学习,了解到linux驱动编写的流程是:先通过注册函数注册我们编写的入口函数,然后在入口函数中获取设备号->注册字符设备->自动创建设备节点->获取设备树信息,最后通过销毁 ...

  2. 1.7见识一下什么叫Linux驱动:LED

    1.任何的Linux驱动都有一个装载函数(装载驱动时调用)和一个卸载函数(卸载驱动时调用): 2.装载函数和卸载函数分别通过module_init和module_exit宏指定.

  3. Linux驱动之LED驱动编写

    从上到下,一个软件系统可以分为:应用程序.操作系统(内核).驱动程序.结构图如下:我们需要做的就是写出open.read.write等驱动层的函数.一个LED驱动的步骤如下: 1.查看原理图,确定需要 ...

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

    学习设备驱动编程也有一段时间了,也写过了几个驱动程序,因此有对设备驱动程序有了一些新的理解和认识,总结一下.学习设备驱动编程也有一段时间了,也写过了几个驱动程序.因此有对设备驱动程序有了一些新的理解和 ...

  5. Linux下的led驱动程序,ok6410

    本程序採用动态映射的方法控制led.硬件平台为飞凌的ok6410 led.h:定义控制命令 #ifndef _LED_H #define _LED_H #define LED_MAGIC 'M' #d ...

  6. linux驱动之USB驱动程序

    1. USB是主从结构的 所有的USB传输,都是从USB主机这方发起:USB设备没有"主动"通知USB主机的能力. 例子:USB鼠标滑动一下立刻产生数据,但是它没有能力通知PC机来 ...

  7. linux驱动之触摸屏驱动程序

    触摸屏归纳为输入子系统,这里主要是针对电阻屏,其使用过程如下 :当用触摸笔按下时,产生中断.在中断处理函数处理函数中启动ADC转换x,y坐标.ADC结束,产生ADC中断,在ADC中断处理函数里上报(i ...

  8. linux驱动之LED驱动_1

    步骤: 1.框架 2.完好硬件的操作: a.看原理图.引脚 b.看2440手冊 c.写代码: IO口须要用ioremap映射 我的板子电路例如以下所看到的 1.配置GPBCON 寄存器,配置输出   ...

  9. Linux驱动之按键驱动编写(中断方式)

    在Linux驱动之按键驱动编写(查询方式)已经写了一个查询方式的按键驱动,但是查询方式太占用CPU,接下来利用中断方式编写一个驱动程序,使得CPU占有率降低,在按键空闲时调用read系统调用的进程可以 ...

随机推荐

  1. 带着项目学PHP第九讲 - 如何给ecshop的wap版本首页和商品页添加商品图片

    ecshop的wap版本自身不带图片, 所以看起来光秃秃的,非常不讨人喜欢, 网络上关于wap的模板就不像pc版那么多,容易找到, 而且能找到的都是要花钱买的, 虽然这个小小的改动不能替代找个合适的模 ...

  2. Matlab实现Hough变换检測图像中的直线

    Hough变换的原理: 将图像从图像空间变换至參数空间.变换公式例如以下: 变换以后,图像空间与參数空间存在下面关系: 图像空间中的一点在參数空间是一条曲线,而图像空间共线的各点相应于參数空间交于一点 ...

  3. ThinkPHP3.2 常量参考

    原文:ThinkPHP3.2 常量参考 预定义常量 预定义常量是指系统内置定义好的常量,不会随着环境的变化而变化,包括: URL_COMMON 普通模式 URL (0) URL_PATHINFO PA ...

  4. NetBeans工具学习之道:NetBeans的(默认)快捷键

    没什么好介绍的,是netbeans的快捷键,比較全面.看到好多坛子里还在问eclipse下的这个快捷键怎么netbeans下没有呢.曾经收集的,如今列在以下: 事实上,在当前安装的netbeans的 ...

  5. ogre sample分析(一)

    ogre自带了一些例子,逐个过一遍并自己动手做一些调整 1 Sample_BezierPatch:这个例子直接用数值来构造顶点缓存并创建entity,这种方法一般只能创建简单对象,本人以为复杂对象顶点 ...

  6. [Cocos2d-x]CCSpriteBatchNode的使用

    文档: http://cocos2d.cocoachina.com/document/index/class?url=dd/d95/classcocos2d_1_1_c_c_sprite_batch_ ...

  7. A Game of Thrones(16) - Edard

    “They’ve found her, my lord.” Ned rose quickly. “Our men or Lannister’s?” “It was Jory,” his steward ...

  8. HDOJ/HDU 2717 Catch That Cow 一维广度优先搜索 so easy..............

    看题:http://acm.hdu.edu.cn/showproblem.php?pid=2717 思路:相当于每次有三个方向,加1,减1,乘2,要注意边界条件,减1不能小于0,乘2不能超过最大值. ...

  9. Codeforces Round #272 (Div. 1)C(字符串DP)

    C. Dreamoon and Strings time limit per test 1 second memory limit per test 256 megabytes input stand ...

  10. UVa 213 Message Decoding(World Finals1991,串)

     Message Decoding  Some message encoding schemes require that an encoded message be sent in two part ...