最终效果是使用杂项设备完成一个蜂鸣器驱动,然后在应用程序中传入参数1为打开蜂鸣器,0为关闭蜂鸣器
步骤
- 新建一个beep.c和Makefile和app.c,放在一个文件夹中
- 查找蜂鸣器原理图对应的管脚名称,然后在参考手册中找到对应的引脚为gpio几,然后再找gpio几的数据寄存器的地址
- 编写beep.c蜂鸣器驱动代码,我这里拿第六章中的misc代码来修改,只需要加一个io.h库,然后定义对应GPIO几的地址,并定义一个虚拟地址全局变量,在init函数添加申请虚拟地址,exit函数释放虚拟地址,write函数读取应用传进来的数据并作出判断来修改虚拟地址
#include <linux/init.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/io.h> #define GPIO5_DR 0x020AC00 unsigned int *vir_gpio5_dr; int misc_open(struct inode * inode,struct file * file) { printk("hello misc_open\n"); return 0; } int misc_read(struct file *file,char _user *ubuf,size_t size,loff_t *loff_t) { char kbuf[64] = "heheh"; if( copy_to_user(ubuf,kbuf,strlen(kbuf))!=0) { printk("copy_to_user error\n"); return -1; } return 0; } int misc_write(struct file *file,const char _user *ubuf,size_t size,loff_t *loff_t) { char kbuf[64] = {0}; if( copy_from_user(kbuf,ubuf,size)!=0) { printk("copy_from_user error\n"); return -1; } printk("kbuf is %s\n",kbuf); if(kbuf[0]==1) { *vir_gpio5_dr |= (1<<1); } else if { *vir_gpio5_dr &= ~(1<<1); } return 0; } struct const file_operation misc_fops = { .owner = THIS_MODULE, .open = misc_open, .write= misc_write, .read = misc_read }; struct miscdevice misc_dev = { .minor = MISC_DYNAMIC_MINOR,//动态分配 .name ="hellomisc",//设备节点名字 .fops =&misc_fops }; static int misc_init(void) { int ret; ret = misc_register(&misc_dev); if(ret<0) { printk("misc registe is error\n"); return -1; } vir_gpio5_dr = ioremap(GPIO5_DR,4); if(vir_gpio5_dr ==NULL) { printk("GPIO5_DR ioremap error\n"); return -EBUSY; } printk("GPIO5_DR ioremap ok\n"); return 0; } static void misc_exit(void) { misc_deregister(&misc_dev); iounmap(vir_gpio5_dr ); printk("misc goodbye"); } module_init(misc_init); module_exit(misc_exit); MODULE_LICENSE("GPL");
- 编写Makefile编译蜂鸣器驱动模块代码,也是第六章的代码,只是将参数写入buf然后写入驱动
obj-m +=beep.o KDIR:=自己的linux内核源码根目录路径 PWD?=$(shell pwd) all: make -C $(KDIR) M=$(PWD) modules
- 编写app.c应用程序代码
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main(int argc, char * argv) { int fd; char buf[64] = {0}; fd = open("/dev/hellomisc",O_RDWR); if (fd<0) { perror("open error\n"); return fd; } buf[0] = atoi(argv[1]); write(fd,buf,sizeof(buf)); printf("buf is %s\n",buf); close(fd); return 0; }
- 配置arm环境和交叉编译环境
- 将驱动编译成模块,和将应用程序编译成可执行文件,两者放入开发板中
- 加载驱动,查看是否加载成功,insmod beep.ko
- 运行可执行文件测试驱动,打开蜂鸣器为./app 1,关闭蜂鸣器为./app 0