开发环境
主机开发环境:ubuntu12.04
BootLoader:u-boot-1.1.6
kernel:linux-2.6.30.4
CPU:s3c2440
开发板:TQ2440
开发步骤
1、硬件分析
在天嵌科技提供的开发板中 4 个 LED 灯(TQ2440)分别使用了 S3C2440芯片的:GPB5、GPB6、GPB7 和 GPB8,下面列出来对应的原理图:
根据上图可以知道,当 CPU 的 GPB5 到 8 是低电平时,LED 灯亮;当为高电平时 LED 灯灭。只需要在驱动中实现对 GPB 口电平的控制就可以实现对灯进行开关操作。
2、编写LED驱动
以下为驱动源码:
#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEVICE_NAME "le2440-leds" /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */ #define LED_MAJOR 231 /* 主设备号 */ /* 应用程序执行 ioctl(fd, cmd, arg)时的第 2 个参数 */ #define IOCTL_LED_ON 1 #define IOCTL_LED_OFF 0 /* 用来指定 LED 所用的 GPIO 引脚 */ static unsigned long led_table[] = { S3C2410_GPB5, S3C2410_GPB6, S3C2410_GPB7, S3C2410_GPB8, }; /* 用来指定 GPIO 引脚的功能:输出 */ static unsigned int led_cfg_table[] = { S3C2410_GPB5_OUTP, S3C2410_GPB6_OUTP, S3C2410_GPB7_OUTP, S3C2410_GPB8_OUTP, }; /* 应用程序对设备文件/dev/le2440-leds 执行 open(...)时, * 就会调用 le2440_leds_open 函数 */ static int le2440_leds_open(struct inode *inode, struct file *file) { int i; for (i = 0; i < 4; i++) { // 设置 GPIO 引脚的功能:本驱动中 LED 所涉及的 GPIO 引脚设为输出功能 s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]); } return 0; } /* 应用程序对设备文件/dev/le2440-leds 执行 ioclt(...)时, * 就会调用 le2440_leds_ioctl 函数 */ static int le2440_leds_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { if (arg > 4) { return -EINVAL; } switch (cmd) { case IOCTL_LED_ON: // 设置指定引脚的输出电平为 0 s3c2410_gpio_setpin(led_table[arg], 0); return 0; case IOCTL_LED_OFF: // 设置指定引脚的输出电平为 1 s3c2410_gpio_setpin(led_table[arg], 1); return 0; default: return -EINVAL; } } /* 这个结构是字符设备驱动程序的核心 * 当应用程序操作设备文件时所调用的 open、read、write 等函数, * 最终会调用这个结构中指定的对应函数 */ static struct file_operations le2440_leds_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module 变量 */ .open = le2440_leds_open, .ioctl = le2440_leds_ioctl, }; static char __initdata banner[] ="TQ2440 le2240-ledsn"; static struct class *led_class; /* * 执行“insmod le2440_leds.ko”命令时就会调用这个函数 */ static int __init le2440_leds_init(void) { int ret; printk(banner); /* 注册字符设备驱动程序 * 参数为主设备号、设备名字、file_operations 结构; * 这样,主设备号就和具体的 file_operations 结构联系起来了, * 操作主设备为 LED_MAJOR 的设备文件时,就会调用 le2440_leds_fops 中的相关成员函数 * LED_MAJOR 可以设为 0,表示由内核自动分配主设备号 */ ret = register_chrdev(LED_MAJOR, DEVICE_NAME, &le2440_leds_fops); if (ret < 0) { printk(DEVICE_NAME " can't register major numbern"); return ret; } //注册一个类,使 mdev 可以在"/dev/"目录下面建立设备节点 led_class = class_create(THIS_MODULE, DEVICE_NAME); if (IS_ERR(led_class)) { printk("Err: failed in le2440-leds class. n"); return -1; } //创建一个设备节点,节点名为 DEVICE_NAME device_create(led_class, NULL, MKDEV(LED_MAJOR, 0), NULL, DEVICE_NAME); printk(DEVICE_NAME " initializedn"); return 0; } /* * 执行”rmmod le2440_leds.ko”命令时就会调用这个函数 */ static void __exit le2440_leds_exit(void) { /* 卸载驱动程序 */ unregister_chrdev(LED_MAJOR, DEVICE_NAME); device_destroy(led_class, MKDEV(LED_MAJOR, 0)); //删掉设备节点 class_destroy(led_class); //注销类 } /* 这两行指定驱动程序的初始化函数和卸载函数 */ module_init(le2440_leds_init); module_exit(le2440_leds_exit); /* 描述驱动程序的一些信息,不是必须的 */ MODULE_DESCRIPTION("TQ2440 LED Driver"); // 一些描述信息 MODULE_LICENSE("GPL"); // 遵循的协议 Makefile如下: #Makefile ifeq ($(KERNELRELEASE),) KERNELDIR ?= /home/linux/sky/ker/linux-2.6.30.4/ #KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules* .PHONY: modules modules_install clean else obj-m := leds.o endif 将其编译成.ko文件拷贝到NFS文件系统即可。 3、编写app控制LED灯 #include #include #include #include int main(int argc, char **argv) { int on; int led_no; int fd; if (argc != 3 || sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2],"%d", &on) != 1 || on < 0 || on > 1 || led_no < 1 || led_no > 4) { fprintf(stderr, "Usage: leds which-led 0|1n"); exit(1); } fd = open("/dev/le2440-leds", 0); if (fd < 0) { perror("open device leds"); exit(1); } ioctl(fd, on, (led_no-1)); close(fd); return 0; } Makefile如下: CROSS=arm-linux- all: leds leds:leds.c $(CROSS)gcc -o leds leds.c $(CROSS)strip leds clean: @rm -vf leds *.o *~ 编译成可执行文件拷贝到NFS文件系统即可 4、实验现象 加载.ko文件,执行app,便可以在开发板上控制任意一个LED灯的亮灭
编译过程中遇到一些问题,经过查找资料,解决方法如下:
上一篇:嵌入式驱动学习之按键驱动
下一篇:嵌入式驱动移植之IIC总线驱动移植
推荐阅读最新更新时间:2024-11-13 09:13