和LED这类简单的设备驱动开发一样,依旧是比较简单的步骤,如下:
· 搭框架
· 硬件操作
阅读原理图 -- 确定哪些引脚接到按键上
阅读收据手册 -- 确定操作哪些寄存器
· 写测试程序
1. 搭框架
a. 建立file_operations
b. 创建驱动open、read等驱动函数的框架(根据需要,名字随便定义,但要与定义file_operations赋予open、read的值保持一致)
当然还有init、exit函数
这里定义的button_init、button_exit函数只是普通函数,若想让它们成为特别的入口函数和退出函数,就得加上一些修饰,如下:
简单的框架至此便搭好了,然后便是丰富函数的内容了,这会涉及硬件操作!
2. 硬件操作
a. 首先阅读原理图,看看按键对应哪些IO口,如下:
由此可以知道对应GPF0、GPF1、GPF2、GPF4这四个IO口。
然后便是获取对应IO口的相关寄存器的信息了,对于本文,所要操作的是两个寄存器GPFCON和GPFDAT。在操作之前得知道相关寄存器的地址。
b. 然后阅读芯片手册,获取需要操作的寄存器的地址
可以知道地址是GFPCON对应地址是0x56000050,GPFDAT对应地址是0x56000054
c. 填充驱动函数
对于GPIO的操作,无论是读还是写,首先得进行IO口配置(譬如配置为可读或可写)。这个步骤在open函数里完成(当然可以有其他安排,只是笔者认为这样安排更有逻辑)。
先定义两个全局变量,分别对应GPFCON、GPFDAT寄存器,如下:
然后对这两个地址完成地址映射,即把这两个变量映射到GPFCON、GPFDAT所在的地址上。但需要注意到的是,datasheet中所提供的0x56000050是物理地址,而Linux内核在完成初始化后对所有内存、外设操作的是虚拟地址,所以要转换一下,这个过程在驱动初始化过程(即button_init函数)里完成比较好,代码如下:
而button_open函数最终如下:
然后便是读写操作了,本文的目的是读取按键状态,所以只需要read函数,button_read函数填充如下:
对于button_init函数,它除了要完成gpfcon、gpfdat地址映射之外,还得完成设备节点创建,具体如下:
此处不过多讲述了,比较简单,对于button_exit函数,它所做的事情差不多是button_init函数的逆过程,如下:
烧到根文件系统中!
烧入开发板,执行“cat /dev/devices”命令可以看到:
执行“ls /dev/buttons”命令可以看到:
至此,硬件操作完成了。
3. 写测试程序
即写应用程序,主要内容如下:
编译,烧写到根文件系统中。
用“./zwbutton”命令调用zwbutton应用程序如下:
ps:上述按键没有按下,没有任何显示,然后按下一个按键,截取部分显示信息如下:
让这个应用程序在后台运行,执行“./zwbutton &”命令,然后执行“top”命令,top命令有点类似于Windows下的任务管理器,截取部分显示信息如下:
可见,button应用程序占用了几乎所有(97%)内存。为什么是这样的呢?因为在应用程序中使用了一个死循环,程序一直运行,然后没有很多其他应用程序与它争抢CPU资源,所以它看起来比较霸道了!我们常常在实际应用中需要时时刻刻(宏观上的时时刻刻)监控按键状态,类似本文设计通过查询方式获取按键状态的行为当然可以,但若在多功能系统中,这样设计未免太霸道,效率奇低无比,占用CPU资源过多,需要有更好的解决方式...