嵌入式Linux驱动学习之LED控制:基于AT91SAM9261EK
来源:互联网 发布:计算机二级vb选择题 编辑:程序博客网 时间:2024/06/04 18:54
最近移植成功了基于AT91SAM9261EK的UBI根文件系统,移植了ftp服务器功能,因此,打算开始驱动的学习,首先写个最简单的基于Linux 的LED驱动,根据网上的例子,修改一下。然后成功运行!方法很重要,开发环境很重要。我这里使用的是Linux 2.6.32的内核。
(1)编写嵌入式Linux LED驱动,控制开发板上的两个LED灯。低电平亮,高电平灭。Atmel AT91SAM9261 PA13 PA14两个GPIO控制。
(2)编写驱动程序(生成模块)与用户程序(执行文件)。
(3)文件系统是可写的,也就是可以建目录与文件,移植了简单的ftp服务器(我这里使用stupidftp)。这样的话,生成的模块与用户程序,直接通过ftp复制到开发板上,由串口超级终端(我使用CRT)来加载模块,执行用户程序,操作运行。
LED驱动程序:修改网上成功的例子:
*******************
二:驱动程序Makefile编写
驱动程序的Makefile文件:我这里不放在Linux 文件里(一般简单的直接放在Linux下面Drivers/char/目录下,然后修改Kconfig)
由于编译成模块,可以加载(insmod)与卸载(rmmod),没有必要再改动内核或是编译选项为:模块M。当然,内核要支持insmod 与rmmod命令。这好像应该是文件系统制作时:busybox的命令!!
因此,内核与根文件系统制作好了就不要去改了,只要把模块与用户程序通过ftp放到开发板的目录下:我这里为:/mnt/nandflash 自己建的一个目录,设置一下权限,为可以读写。
LED_TEST.c的Makefile文件如下:
注意:虽然不放在Linux 如:linux-2.6.32.2的目录下,但编译驱动还是需要使用这个目录的,即开发板烧写的内核的目录。因为驱动与Linux内核文件有关,使用它的相关头文件与开发板硬件相关的底层文件。我这里驱动文件放在一个单独的目录里,然后引用内核的目录。
三:编译驱动的命令为:
在驱动文件目录(有LED_TEST.c Makefile),
执行shell:
# make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
生成LED_Test.ko模块(加载就可以直接使用)
用户程序LED_APP.c的编写:
(在Makefile里,已经指定了arm-none-linux-gnueabi-gcc 的交叉编译,因此直接make就执行了交叉编译)
就可以生成LED_APP可执行的文件,可以chmod 777 LED_APP设置一下执行权限。
然后把LED_APP LED_TEST.ko 通过ftp复制到开发板。如果你的开发板不支持ftp,则需要跟文件系统一起烧到开发板。
如放在/mnt/nandflash里面,
则进入/mnt/nandflash。
在shell里执行:
#insmod LED_TEST.ko
//会提示是否加载模块成功!!
# ./LED_APP 0 1 //(第一个LED 亮)
# ./LED_APP 0 0 //(第一个LED灭)
#./LED_APP 1 1 //(第二个LED亮)
#./LED_APP 1 0 //( 第二个LED灭)
(输入时不要输入#,那是shell提示符!./表示当前目录,如果放在bin下面,可以直接执行LED_APP,因为bin这种目录,就像windows下面设置好了环境变量,可以直接执行,不用输入全路径。如果是其他的目录,需要输入全路径,当前目录下,直接使用./即可。)
卸载的命令:
# rmmod LED_TEST.ko
好了,执行成功!
(1)编写嵌入式Linux LED驱动,控制开发板上的两个LED灯。低电平亮,高电平灭。Atmel AT91SAM9261 PA13 PA14两个GPIO控制。
(2)编写驱动程序(生成模块)与用户程序(执行文件)。
(3)文件系统是可写的,也就是可以建目录与文件,移植了简单的ftp服务器(我这里使用stupidftp)。这样的话,生成的模块与用户程序,直接通过ftp复制到开发板上,由串口超级终端(我使用CRT)来加载模块,执行用户程序,操作运行。
LED驱动程序:修改网上成功的例子:
#include <linux/string.h>#include <linux/cdev.h>#include <linux/fs.h>#include <mach/gpio.h> //包含管脚操作的相关函数#include <linux/device.h> //包含创建设备文件的相关函数#define DEVICE_NAME "SAM9261-LED_TEST" static int LED_Major = 0;struct cdev cdev;/** 应用程序执行 ioctl(fd, cmd, arg)时的第 2 个参数 **/ #define LED_OFF 0#define LED_ON 1static unsigned long led_table [] ={ AT91_PIN_PA13, /**led_1**/ AT91_PIN_PA14, /**led_2**/};/*应用程序对设备文件/dev/leds 执行 open()时, *就会调用SAM9261_ledtest_open */ static int SAM9261_ledtest_open(struct inode *inode, struct file *file){ printk("SAM9261-ledtest Driver Open Called!\n"); return 0;}static long SAM9261_ledtest_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){ if((cmd != 1 && cmd != 0) || (arg != 1 && arg != 0)) return -1; switch(cmd) { case LED_ON: if(arg){at91_set_gpio_value(led_table[arg], 0);}else{at91_set_gpio_value(led_table[arg], 0);}break; case LED_OFF: if(arg){at91_set_gpio_value(led_table[arg], 1);}else{at91_set_gpio_value(led_table[arg], 1);}break; default:return -EINVAL; } return 0;}static int SAM9261_ledtest_release(struct inode *inode, struct file *file){ printk("SAM9261_LED Driver Release Called!\n"); return 0;}/*这个结构是字符设备驱动程序的核心 *当应用程序操作设备文件时调用的 open、read等函数, *最终会调用这个结构中指定的对应函数 */static struct file_operations SAM9261_ledtest_fops ={ .owner = THIS_MODULE, .open = SAM9261_ledtest_open, .release = SAM9261_ledtest_release, .unlocked_ioctl = SAM9261_ledtest_ioctl,};static struct class *SAM9261_ledtest_class = NULL;/**模块的初始化函数**/ static int __init SAM9261_ledtest_init(void){int result,err; dev_t devno = MKDEV(LED_Major, 0); /**采用自动分配主设备号**/ if (LED_Major) { result = register_chrdev_region(devno, 1, DEVICE_NAME);printk("Got the Major number by register_chrdev_region !\n ");} else {result = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME); LED_Major=MAJOR(devno);printk("Got the Major number by alloc_chrdev_region !\n"); } if (result < 0) { printk(DEVICE_NAME " can't register major number\n"); return result; } printk("register SAM9261_ledtest Driver OK! Major = %d\n", LED_Major); /**初始化cdev结构**/ cdev_init(&cdev,&SAM9261_ledtest_fops); cdev.owner=THIS_MODULE; cdev.ops=&SAM9261_ledtest_fops; /**注册字符设备**/ err=cdev_add(&cdev, MKDEV(LED_Major, 0), 1); if (err) {printk("error %d adding led \n ", err);goto fail_cdev_add;} /**自动创建设备文件**/SAM9261_ledtest_class = class_create(THIS_MODULE, DEVICE_NAME);if(IS_ERR(SAM9261_ledtest_class)){printk("Err: failed in SAM9261_ledtest class. \n");goto fail_create_class;}device_create(SAM9261_ledtest_class, NULL, MKDEV(LED_Major, 0), NULL, DEVICE_NAME);/**初始化PA13,PA14 PA23引脚**/at91_set_gpio_output(AT91_PIN_PA13, 1);at91_set_gpio_output(AT91_PIN_PA14, 1);at91_set_gpio_output(AT91_PIN_PA23, 1);at91_set_deglitch(AT91_PIN_PA13, 1);at91_set_deglitch(AT91_PIN_PA14, 1);at91_set_deglitch(AT91_PIN_PA23, 1);printk(DEVICE_NAME " initialized\n");return 0; fail_create_class:cdev_del(&cdev);fail_cdev_add: unregister_chrdev_region(devno, 1);return -1;}/**模块的撤销函数**/ static void __exit SAM9261_ledtest_exit(void){printk("SAM9261 LED DRIVER MODULE EXIT\n");device_destroy(SAM9261_ledtest_class, MKDEV(LED_Major, 0));class_destroy(SAM9261_ledtest_class);cdev_del(&cdev);unregister_chrdev(LED_Major, DEVICE_NAME); }/**指定驱动程序的初始化函数和卸载函数**/ module_init(SAM9261_ledtest_init);module_exit(SAM9261_ledtest_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("none");MODULE_DESCRIPTION("SAM9261_LEDTEST drivers");MODULE_ALIAS("LED Driver module.");
*******************
二:驱动程序Makefile编写
驱动程序的Makefile文件:我这里不放在Linux 文件里(一般简单的直接放在Linux下面Drivers/char/目录下,然后修改Kconfig)
由于编译成模块,可以加载(insmod)与卸载(rmmod),没有必要再改动内核或是编译选项为:模块M。当然,内核要支持insmod 与rmmod命令。这好像应该是文件系统制作时:busybox的命令!!
因此,内核与根文件系统制作好了就不要去改了,只要把模块与用户程序通过ftp放到开发板的目录下:我这里为:/mnt/nandflash 自己建的一个目录,设置一下权限,为可以读写。
LED_TEST.c的Makefile文件如下:
obj-m:=LED_TEST.oCURRENT_PATH:=$(shell pwd)ARM_LINUX_KERNEL:=/home/AT91/Kernel/linux-2.6.32.2all:$(MAKE) -C $(ARM_LINUX_KERNEL) SUBDIRS=$(CURRENT_PATH) modulesclean:rm -rf *.cmd *.o *.ko *.mod.c *.symvers *.order
注意:虽然不放在Linux 如:linux-2.6.32.2的目录下,但编译驱动还是需要使用这个目录的,即开发板烧写的内核的目录。因为驱动与Linux内核文件有关,使用它的相关头文件与开发板硬件相关的底层文件。我这里驱动文件放在一个单独的目录里,然后引用内核的目录。
三:编译驱动的命令为:
在驱动文件目录(有LED_TEST.c Makefile),
执行shell:
# make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
生成LED_Test.ko模块(加载就可以直接使用)
用户程序LED_APP.c的编写:
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/ioctl.h>#define LED_DEV "/dev/SAM9261-LED_TEST"int main(int argc, char **argv){ int fd, ret, led_num, led_status; if (argc!=3 || sscanf(argv[1],"%d", &led_num)!=1 || sscanf(argv[2],"%d", &led_status)!=1) { printf("\r\nPlease input correct parameters !\r\n\n"); printf("usage:\r\n%s <led_num> <led_status>\r\n", argv[0]);printf("\r\nOptions:\r\n"); printf(" led_num\t- 1 for red led, 0 for blue led.\r\n led_status\t- 1 for ON, 0 for OFF.\r\n\n"); exit(1); } if((led_status!=1 && led_status!=0) || (led_num!=0 && led_num!=1)) { printf("\r\nError: The parameter value must be '0' or '1' !\r\n"); printf("\r\nPlease try again !!! !\r\n\n"); exit(1); } fd = open(LED_DEV, 0); if (fd < 0) { printf("\r\nFail to open device '%s'!\r\n\n", LED_DEV); exit(1); } ret = ioctl(fd, led_status, led_num); if(ret < 0) { printf("\r\nFail calling ioctl !\r\n\n"); } close(fd); return 0;}
all:arm-none-linux-gnueabi-gcc LED_TEST_APP.c -o LED_APPclean:rm -rf *.o LED_APP
执行编译:# make
(在Makefile里,已经指定了arm-none-linux-gnueabi-gcc 的交叉编译,因此直接make就执行了交叉编译)
就可以生成LED_APP可执行的文件,可以chmod 777 LED_APP设置一下执行权限。
然后把LED_APP LED_TEST.ko 通过ftp复制到开发板。如果你的开发板不支持ftp,则需要跟文件系统一起烧到开发板。
如放在/mnt/nandflash里面,
则进入/mnt/nandflash。
在shell里执行:
#insmod LED_TEST.ko
//会提示是否加载模块成功!!
# ./LED_APP 0 1 //(第一个LED 亮)
# ./LED_APP 0 0 //(第一个LED灭)
#./LED_APP 1 1 //(第二个LED亮)
#./LED_APP 1 0 //( 第二个LED灭)
(输入时不要输入#,那是shell提示符!./表示当前目录,如果放在bin下面,可以直接执行LED_APP,因为bin这种目录,就像windows下面设置好了环境变量,可以直接执行,不用输入全路径。如果是其他的目录,需要输入全路径,当前目录下,直接使用./即可。)
卸载的命令:
# rmmod LED_TEST.ko
好了,执行成功!
0 0
- 嵌入式Linux驱动学习之LED控制:基于AT91SAM9261EK
- 嵌入式Linux驱动学习之USART串口控制:基于AT91SAM9261EK
- 树莓派linux驱动学习之LED控制
- 树莓派linux驱动学习之LED控制
- 树莓派linux驱动学习之LED控制
- 嵌入式驱动之PWM控制LED灯
- 嵌入式系统学习——S3C2451之linux驱动led
- 嵌入式Linux驱动开发(二)——字符设备驱动之控制LED
- 基于AT91SAM9261EK的嵌入式Linux+Cramfs根文件系统移植成功
- 基于AT91SAM9261EK的嵌入式Linux+UBI根文件系统移植成功
- 嵌入式Linux字符设备LED驱动-基于树莓派
- 嵌入式学习之LED
- 嵌入式Linux驱动学习笔记(一)------第一个LED驱动程序
- 嵌入式Linux字符设备入门之--LED驱动详解
- Linux嵌入式系统开发之Led开发---驱动篇
- 嵌入式Linux应用学习(一)------QT控制LED设备硬件
- Linux字符驱动学习之LED
- 我的第一个嵌入式linux驱动(基于韦东山led驱动)
- unity3D 下雨效果实现
- Singly Linked List & Destructor - C++ for C Programmers 3.4
- UNIX环境高级编程第十一章 线程 总结
- 最新版IntelliJ IDEA 15开发Java Maven项目
- 用gparted给ubuntu调整分区
- 嵌入式Linux驱动学习之LED控制:基于AT91SAM9261EK
- Spring MVC过滤器-委派过滤器代理(DelegatingFilterProxy)
- LeetCode 268 Missing Number(丢失的数字)
- 每个人都该懂点网络安全
- 第二天
- web前端面试题集锦
- Session机制详解
- URL详解
- JavaScript王者归来02