嵌入式内核开发:led灯驱动
2016-08-20 19:51
375 查看
接触单片机或者其他嵌入式芯片的编程中,最简单的就是GPIO的High/Low控制。
比如学校里面最基本的单片机实验:led控制,流水灯,数码管。其实都是最基本的GPIO操作。
那么同样,对应到linux嵌入式开发,GPIO的High/Low控制也是最简单的操作。算的上是c语言的 hello world 例程一样。
linux的设备有分几个类别,这里led一般认作是字符形设备。在linux中访问设备就是访问设备文件,所以linux也作基于文件的操作系统
将此编译进内核。
2.编写led测试程序。
如此,将led驱动直接编译进内核后,然后在busybox构建的文件系统中,调用led测试程序。结果发现可以按照预先的想法顺利控制led的亮暗。
int gpio_request(unsigned gpio, const char *label) ,成功返回0,否则负数
gpio则为你要申请的哪一个管脚,label则是为其取一个名字
自动创建节点的字符杂项设备misc_register
注册
int misc_register(struct miscdevice * misc);
释放
int misc_deregister(struct miscdevice *misc);
杂项设备的
struct miscdevice {
int minor;
const char *name;
const struct file_operations *fops;
struct list_head list;
struct device *parent;
struct device *this_device;
const char *nodename;
umode_t mode;
};
网上关于杂项字符设备与普通字符设备的区别描述如下:
杂项字符设备和一般字符设备的区别:
1.一般字符设备首先申请设备号。 但是杂项字符设备的主设备号为10次设备号通过结构体struct miscdevice中的minor来设置。
2.一般字符设备要创建设备文件。 但是杂项字符设备在注册时会自动创建。
3.一般字符设备要分配一个cdev(字符设备)。 但是杂项字符设备只要创建struct miscdevice结构即可。
4.一般字符设备需要初始化cdev(即给字符设备设置对应的操作函数集struct file_operation). 但是杂项字符设备在结构体truct miscdevice中定义。
5.一般字符设备使用注册函数 int cdev_add struct (cdev *p,devt_t dev, unsigned)(第一个参数为之前初始化的字符设备,第二个参数为设备号,第三个参数为要添加设备的个数) 而杂项字符设备使用int misc_register(struct miscdevice *misc)来注册
驱动调用的实质:
就是通过 设备文件找到与之对应设备号的设备,再通过设备初始化时绑定的操作函数对硬件进行控制的
上面例子中是将led看作一个杂项设备来实现的
比如学校里面最基本的单片机实验:led控制,流水灯,数码管。其实都是最基本的GPIO操作。
那么同样,对应到linux嵌入式开发,GPIO的High/Low控制也是最简单的操作。算的上是c语言的 hello world 例程一样。
linux的设备有分几个类别,这里led一般认作是字符形设备。在linux中访问设备就是访问设备文件,所以linux也作基于文件的操作系统
#include <linux/kernel.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/moduleparam.h> #include <linux/slab.h> #include <linux/ioctl.h> #include <linux/cdev.h> #include <linux/delay.h> #include <linux/gpio.h> #include <mach/gpio.h> #include <mach/regs-gpio.h> #include <plat/gpio-cfg.h> #define DEVICE_NAME "leds" static int led_gpios[] = { S5PV210_GPJ2(0), S5PV210_GPJ2(1), S5PV210_GPJ2(2), S5PV210_GPJ2(3), }; #define LED_NUM ARRAY_SIZE(led_gpios) static long smart210_leds_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { switch(cmd) { case 0: case 1: if (arg > LED_NUM) { return -EINVAL; } gpio_set_value(led_gpios[arg], !cmd); printk(DEVICE_NAME": %ld %d\n", arg, cmd); break; default: return -EINVAL; } return 0; } static struct file_operations smart210_led_dev_fops = { .owner = THIS_MODULE, .unlocked_ioctl = smart210_leds_ioctl, }; static struct miscdevice smart210_led_dev = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &smart210_led_dev_fops, }; static int __init smart210_led_dev_init(void) { int ret; int i; for (i = 0; i < LED_NUM; i++) { ret = gpio_request(led_gpios[i], "LED"); if (ret) { printk("%s: request GPIO %d for LED failed, ret = %d\n", DEVICE_NAME, led_gpios[i], ret); return ret; } s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT); gpio_set_value(led_gpios[i], 1); } ret = misc_register(&smart210_led_dev); printk(DEVICE_NAME"\tinitialized\n"); return ret; } static void __exit smart210_led_dev_exit(void) { int i; for (i = 0; i < LED_NUM; i++) { gpio_free(led_gpios[i]); } misc_deregister(&smart210_led_dev); } module_init(smart210_led_dev_init); module_exit(smart210_led_dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("FriendlyARM Inc.");
将此编译进内核。
2.编写led测试程序。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> 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 < 0 || led_no > 3) { fprintf(stderr, "Usage: leds led_no 0|1\n"); exit(1); } fd = open("/dev/leds0", 0); if (fd < 0) { fd = open("/dev/leds", 0); } if (fd < 0) { perror("open device leds"); exit(1); } ioctl(fd, on, led_no); close(fd); return 0; }
如此,将led驱动直接编译进内核后,然后在busybox构建的文件系统中,调用led测试程序。结果发现可以按照预先的想法顺利控制led的亮暗。
int gpio_request(unsigned gpio, const char *label) ,成功返回0,否则负数
gpio则为你要申请的哪一个管脚,label则是为其取一个名字
自动创建节点的字符杂项设备misc_register
注册
int misc_register(struct miscdevice * misc);
释放
int misc_deregister(struct miscdevice *misc);
杂项设备的
struct miscdevice {
int minor;
const char *name;
const struct file_operations *fops;
struct list_head list;
struct device *parent;
struct device *this_device;
const char *nodename;
umode_t mode;
};
网上关于杂项字符设备与普通字符设备的区别描述如下:
杂项字符设备和一般字符设备的区别:
1.一般字符设备首先申请设备号。 但是杂项字符设备的主设备号为10次设备号通过结构体struct miscdevice中的minor来设置。
2.一般字符设备要创建设备文件。 但是杂项字符设备在注册时会自动创建。
3.一般字符设备要分配一个cdev(字符设备)。 但是杂项字符设备只要创建struct miscdevice结构即可。
4.一般字符设备需要初始化cdev(即给字符设备设置对应的操作函数集struct file_operation). 但是杂项字符设备在结构体truct miscdevice中定义。
5.一般字符设备使用注册函数 int cdev_add struct (cdev *p,devt_t dev, unsigned)(第一个参数为之前初始化的字符设备,第二个参数为设备号,第三个参数为要添加设备的个数) 而杂项字符设备使用int misc_register(struct miscdevice *misc)来注册
驱动调用的实质:
就是通过 设备文件找到与之对应设备号的设备,再通过设备初始化时绑定的操作函数对硬件进行控制的
上面例子中是将led看作一个杂项设备来实现的
相关文章推荐
- 【嵌入式linux】(第六步):使用eclipse集成开发环境开发第一个嵌入式Linux程序,并测试LED驱动
- android平台led开发之内核硬件驱动层(一)
- 嵌入式驱动开发笔记(裸机程序篇)---点亮LED灯
- 嵌入式驱动开发之内核态spi ---module_spi_driver
- 嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)
- 嵌入式linux平台设备驱动(设备驱动模型)开发之linux内核中bus总线
- 嵌入式学习-驱动开发前奏-lesson1-内核模块相关知识
- 【内核编程】【Makefile】:嵌入式驱动开发时驱动模块于内核版本不匹配的解决
- Linux内核与驱动开发学习总结:嵌入式中南北桥(三)
- 嵌入式开发第62日(linux内核模块之设备驱动:修改内核的默认输出级别)
- 嵌入式驱动开发之内核源码树(内核升级)的引用
- 嵌入式驱动开发-内核、文件系统的挂载基于(exynos4412)
- 嵌入式学习-驱动开发-lesson2-LED字符设备驱动
- android平台led开发之内核硬件驱动层
- 第十章--中断处理 (专注于嵌入式Linux内核和驱动开发)
- 嵌入式Linux内核驱动实战开发班
- 【转】嵌入式Linux之我行——LED驱动在2440上的实例开发
- 嵌入式linux平台设备驱动(设备驱动模型)开发之linux内核中的设备驱动
- 和菜鸟一起学linux:第六篇:将LED驱动编译到内核
- 构建嵌入式驱动开发编译环境