linux内核驱动:TQ2440的LED驱动

刚搭建完针对TQ2440开发板2.6.30.4内核的驱动模块交叉编译的环境,接下来就迫不及待地想弄个实实在在的驱动程序移植到目标板上看看效果,这不网上TQ2440的LED驱动的参考资料比较多,所以就做TQ2440 LED驱动程序吧。

本文参考:http://wenku.baidu.com/link?url=vdAY5Ynk3EWSIdXGQ9ySu22F8vfRc2yCC2TPGQZmylryUawvfZCOtqHDOSyftlMp3gyMHYM3KWGZIdr9I_fsxfYaZt4BaD3ArUgcFRbLi9S

1.硬件分析:

在天嵌科技提供的开发板中4个LED灯(TQ2440)分别使用了S3C2440芯片的:GPB5、GPB6、GPB7和GPB8。下面列出来对应的原理图:

       

TQ2440底板原理图  


TQ2440_V2核心板原理图

根据上图可以知道,当CPU的GPB5到GPB8是低电平时,LED灯亮;当为高电平时LED灯灭。

2.LED灯驱动程序的编写,将文件的名字命名为myled.c:

#include <linux/module.h> //支持动态添加和卸载模块的头文件
#include <linux/init.h> //内核初始化头文件       
#include <linux/fs.h>  //文件系统头文件
#include <linux/cdev.h>  //定义了表示字符设备的cdev结构和与之相关的一些辅助函数         
#include <linux/kdev_t.h> //定义用来操作设备编号的宏
#include <linux/kernel.h>
#include <asm/io.h> //定义I/O mapping等函数

#define GPBOUT (1<<(5*2)) |(1<<(6*2)) | (1<<(7*2)) | (1<<(8*2));//设置GPB5/6/7/8为输出
int major = 0;  //主设备号
struct cdev* leds_cdev;
volatile unsigned long *GPBCON = NULL;//GPB(0~10)  [21:0]位
volatile unsigned long *GPBDAT = NULL;//GPB[10:0]   [10:0]位
#define DEVICE_NAME "myleds" //设备名称      
static char __initdata banner[] = "lizs's TQ2440 Leds, (R) 2010.07\n";  

static int myleds_open(struct inode *inode, struct file *filp)
{
    *GPBCON = 0;//控制端口清零
    *GPBCON = GPBOUT;
    return 0;
}

static int myleds_ioctl(struct inode* inode, struct file* filp, unsigned int cmd, unsigned long arg)
{
    if (arg > 4)
    {
        printk("deyond the led no\n");
    }
    printk("3---arg = %d\n", arg);
    printk("4---cmd = %d\n", cmd);
    switch (cmd)
    {
        case 1:
            *GPBDAT |= (1<<(arg + 4));//灭灯
            break;
        case 0:
            *GPBDAT &= ~(1<<(arg + 4));//亮灯
            break;
        default:
            printk("cmd error\n");
            break;
    }
    return 0;
}

struct file_operations myleds_fops =
{
    .owner = THIS_MODULE,
    .open = myleds_open,
    .ioctl = myleds_ioctl,
};

static int __init myleds_init(void)
{
    dev_t dev;
printk(banner);
    leds_cdev = cdev_alloc();
    alloc_chrdev_region(&dev, 0, 1, "myleds");
    major = MAJOR(dev);
    leds_cdev->ops = &myleds_fops;
    cdev_init(&leds_cdev, &myleds_fops);
    cdev_add(&leds_cdev, dev, 1);
    GPBCON = (volatile unsigned int *)ioremap(0x56000010, 16);//将物理地址映射到虚拟地址,GPBCON物理地址为0x56000010
    GPBDAT = GPBCON + 1;//GPBDAT物理地址为0x56000014
    printk("1---GPBCON = 0x%x\n", GPBCON);
printk("2---GPBDAT = 0x%x\n", GPBDAT);
    return 0;
}

static void __exit myleds_exit(void)
{
    dev_t dev;
    dev = MKDEV(major, 0);
    printk("3---GPBCON = 0x%x\n", GPBCON);
printk("4---GPBDAT = 0x%x\n", GPBDAT);
    cdev_del(&leds_cdev);
    unregister_chrdev_region(dev, 1);
}

module_init(myleds_init);
module_exit(myleds_exit);
MODULE_AUTHOR("lizs");
MODULE_DESCRIPTION("lizs's TQ2440 leds Driver");
MODULE_LICENSE("GPL");

3.编写Makefile文件,文件的名字命名为Makefile:

obj-m:=myled.o
CC=arm-linux-gcc
KERNELDIR=/usr/local/opt/EmbedSky/linux-2.6.30.4
PWD:=$(shell pwd)
default:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

4.交叉编译可在TQ2440开发板上内核2.6.30.4加载的驱动模块:

将上面的myled.c和Makefile文件放在同一文件夹下,我的是放在Led文件夹下,特别注意这个文件夹的名字里面不能有中文,否则不能编译! 进入Led文件夹下,打开终端登录root,输入指令:make 即可。

5.编写测试程序测试myled驱动模块,文件的名字命名为test_led.c:

#include <stdio.h>
#include <linux/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#define ON 0
#define OFF 1
int main(int argc, char* argv[])
{
    int led_no;
    if (argc != 3)
    {
        printf("Usage: %s <led_no> <ON/OFF>\n", argv[0]);
        exit(0);
    }
    int fd;
    fd = open("/dev/myleds", O_RDWR);
    if (fd < 0)
    {
        printf("open error\n");
        exit(0);
    }
    led_no = strtoul(argv[1], 0, 0); //将字符串转换成无符号长整型数
  
    if (!strcmp(argv[2], "ON"))
        ioctl(fd, ON, led_no);
    else if (!strcmp(argv[2], "OFF"))
        ioctl(fd, OFF, led_no);
    else
        exit(0);
    return 0;
}

6.使用交叉编译工具arm-linux-gcc交叉编译test_led.c:

输入指令:arm-linux-gcc -o test_led.o test_led.c ,编译后的test_led.o文件便是我们需要的驱动测试程序。

7.将myled.ko和test_led.o文件拷贝到开发板进行测试:

注意:TQ2440开发板根文件系统直接使用了天嵌官方做好的根文件系统,开发板启动便已经加载了EmbedSky-gpio驱动,为了使用我们自己编译的驱动,需要将开发板上/etc/init.d/rcS文件中/etc/rc.d/init.d/leds start这一行注释掉。方法如下:

输入指令:cd /etc/init.d 进入init.d目录,然后输入指令 vi rcS 打开rcS这个文件,输入i进入编辑模式,找到/etc/rc.d/init.d/leds start这个一行,在前面输入#将其注释掉,最后按Esc键退出编辑模式进入命令模式,输入  :wq!强制保存退出就OK了!重启开发板,这之后系统自带的led驱动程序就不会运行了,我们就可以使用我们自己的led驱动程序了。

7.1 将文件拷贝到开发板的方法:

    7.1.1 首先将u盘插到你的电脑上把myled.ko和test_led.o拷贝到u盘里面

    7.1.2 将u盘插到开发板上,在你的主机的linux系统中的终端输入指令:sudo kermit  - c 连接开发板

    7.1.3 输入指令 :ls可查看到一个叫udisk的目录,然后输入指令:cd udisk/ 进入到这     个目录下,然后将myled.ko和test_led.o文件使用cp指令复制到开发板的opt文件夹下     就OK了。

7.2 进入opt文件夹下,输入指令:insmod myled.ko 把驱动模块加载进系统内核,这个时候我们接着输入指令:cat /proc/devices 可以看到多了252 myleds这么一行,这说明驱动模块确实是已经加载到了我们系统的内核之中了。

7.3 建立设备文件:

输入指令:mknod /dev/myleds c 252 0 建立设备文件,第一个参数是设备文件的目录,第二个参数c表示我们的设备是字符设备,第三个参数和第四个参数分别是主设备号和次设备号。

7.4 运行测试程序test_led.o进行测试:

输入指令:./test_led.o 1 OFF,这时候led灯1灭了

输入指令:./test_led.o 2 OFF,这时候led灯2灭了

输入指令:./test_led.o 1 ON ,这时候led灯1亮了

其他灯的测试指令依此类推!

完!




倒萨


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值