嵌入式Linux驱动 GPIO操作 包括驱动和应用层程序对驱动进行测试

2019-07-12 18:49发布

class="markdown_views prism-github-gist">

嵌入式Linux驱动 GPIO操作

这里记录的是嵌入式linux驱动对gpio的基本操作。但是并不是规范的驱动编写方式,在后面的学习中还要进行改进。
改进过后点击这里
实现的内容是:gpio驱动编写>>>>应用编写(闪烁灯)。
目标板是iTOP4412。CPU为 Exynos4412。

代码

代码部分包括 驱动层代码对GPIO寄存器的直接操作。然后是应用层对驱动的测试代码以验证驱动的正确性。再是Makefile文件规定文件的编译规则。
代码有详细注释。

驱动代码

#include #include #include #include #include #include #include #define GPIOL2_CON 0x11000000+0x0100 //这里是从芯片数据手册中查得的GPIOL2的基地址 #define LEN 8 //要进行虚拟地址映射的地址长度 单位:字节 volatile unsigned long *gpiol20_cof;//用于指向经过虚拟地址映射的gpio控制寄存器地址 volatile unsigned long *gpiol20_dat;//用于指向经过虚拟地址映射的gpio数据寄存器地址 static int DEV_MAJOR=300; //设备主设备号(高12bit) static int DEV_MINIOR=0;//设备次设备号(底20bit) dev_t dev_num ; static struct class *devcls; //设备类 static struct device * dev; //设备 //由于没有用到读功能所以没进行read函数的具体实现。也可以不写。 ssize_t chr_drv_read (struct file *filp, char __user *buffer, size_t count, loff_t *fpos) { printk("-------%s------- ",__FUNCTION__); return 0 ; } ssize_t chr_drv_write (struct file *flip, const char __user *buffer, size_t count, loff_t *fpos) { int ret; int value; static int num=0; printk("write:%d ",num++); ret = copy_from_user(&value, buffer, count); //从应用空间拷贝数据到内核空间 if(value == 1) { printk("vaule:%d ",value); *gpiol20_dat |=1<<0; //设置gpiol2[0]为高电平 } else { printk("vaule:%d ",value); *gpiol20_dat &=~(1<<0);//设置gpiol2[0]为底电平 } return 0; } //没用到不进行具体实现 int chr_drv_open (struct inode *inode, struct file *filp) { printk("-------%s------- ",__FUNCTION__); return 0; } int chr_drv_release (struct inode *inode, struct file *filp) { printk("-------%s------- ",__FUNCTION__); return 0; } //文件操作的操作集 函数指针指向上面定义的实现函数 static struct file_operations file_ops={ .owner = THIS_MODULE, .open = chr_drv_open, .read = chr_drv_read, .write = chr_drv_write, .release = chr_drv_release, }; //设备装载初始化代码 static int __init chr_io_init(void) { int ret; printk("-----------%s-------- ",__FUNCTION__); dev_num= MKDEV(DEV_MAJOR, DEV_MINIOR); //得到设备号 ret = register_chrdev(DEV_MAJOR , "io",&file_ops);//注册设备 if(ret) goto reg_err; //创建设备节点 devcls = class_create(THIS_MODULE, "io_cls"); dev = device_create(devcls, NULL, dev_num, NULL, "io"); //进行虚拟地址映射 gpiol20_cof= ioremap(GPIOL2_CON, LEN); gpiol20_dat = gpiol20_cof+1; /*配置为输出模式*/ *gpiol20_cof &=~(1<<0); *gpiol20_cof |=1<<0; return 0; reg_err: return ret; } static void __exit chr_io_exit(void) { unregister_chrdev(DEV_MAJOR, "io"); device_destroy(devcls, dev_num); //销毁设备节点 和创建设备节点时相反 class_destroy(devcls); printk("-----------%s-------- ",__FUNCTION__); } MODULE_LICENSE("GPL"); module_init(chr_io_init); module_exit(chr_io_exit);

应用层代码 测试驱动

#include #include #include #include #include #include #include int main(int argc,char *argv[]) { int fd; int buf=0; fd = open("/dev/io",O_RDWR); if(fd<0) { printf("open /dev/io failed! fd:%d ",fd); return fd; } while(1) //循环向文件写1和0 也就是控制led亮灭 { buf =0; write(fd,&buf,4); sleep(1); buf =1; write(fd,&buf,4); sleep(1); } close(fd); return 0; }

Makefile

#!/bin/bash obj-m +=io.o KDIR :=/home/topeet/linux_dirver_learning/iTop4412_Kernel_3.0 #KDIR :=/lib/modules/3.5.0-23-generic/build PWD ?=$(shell pwd) #获取当前路径 all: make -C $(KDIR) M=$(PWD) modules #编译驱动模块 arm-none-linux-gnueabi-gcc -o chr_test chr_test.c #编译测试文件 clean: #清理文件 rm -rf *.o *.order *.mod.c *.mod.o *.symvers install: #将生成的文件拷贝到对应的目录 cp *.ko chr_test /home/topeet/tftpboot