ARM9由于频率高(400M),内存大(64MSDRAM),可以用来在OS进行大量计算或者实现复杂的算法。但ARM处理器还有很重要的作用——控制。平时可能需要IO口和三极管开关电路来控制一些设备的开启关闭,在M3或者低端的ARM处理器上比较好实现。但是ARM9移植了linux操作系统,我们为数个能完成这项工作的一群GPIO口专门写一个驱动程序,这样只需要在上层API中调用(高级字符启动设备操作 iotcl [1])就可以实现这个常用功能。
在调试的过程中,出现了有下面的一些问题:
arm-linux-gcc
arm-linux-gcc是交叉编译工具,为什么要使用这个工具呢?因为受ARM开发板的资源性能限制,我们不可能在它里面定制的linux内核下装vim,装emacs。而编译整个内核或者编译程序需要大量计算、资源消耗。这样为了提高效率,我们优雅地转换到PC上来做这件事情。但是PC是基于X86的平台,而ARM9是ARM架构。它们能执行的二进制代码的排列组织方式(也包括大端小端模式)肯定不一样,这就需要一个转换工具,把能在X86下运行的字节码转换为能在ARM架构下运行的字节码。
安装完了这个编译工具,假设安装目录在/usr/local/arm/4.4.3/bin下。我们在终端调用时必须要使用/usr/local/arm/4.4.3/bin/arm-linux-gcc这一长串来编译代码。同样为了方便优雅地使用这个工具,我们选择在系统的环境变量里添加这个路径,这样只需要用arm-linux-gcc就可以编译了。我是这样添加:
我们先看一下.bashrc的作用:该文件包含专用于你的bash shell的bash信息,当登录时以及每次打开新的shell时,该 文件被读取。就是当前用户的环境变量。
然后编写内核驱动的Makefile文件:
这样运行make命令就应该开始编译GPIO内核驱动了。但是出现了错误:
S3C2410PF(0)未声明。
S3C2410_gpio_setpin未声明。
出现这样错误的第一反应是头文件未包含或者路径不对,但是检查了发现没有问题。其实文件未包含只是表面的原因,真正的原因是位于/opt/linux-2.6.32.2的内核源码树未形成,换言之,是位于PC上匹配开发板的内核源码没有经过编译[2]。
编译内核源码树
设备驱动程序是内核的一部分,所以它采用的是内核的头文件和库,而在linux发行版里可能并没有这些东西。 这就需要下载内核版本然后编译生成源码树,以准备好驱动编译所需要的头文件和库。
linux设备驱动程序说:
要想为2.6.x内核构造模块,还必须在自己的系统中配置并构造好内核树。这一要求和先前版本的内核不同 ,先前的版本只需要一头内核头文件就够了,但因为2.6内核的模块要和内核源代码中的目标文件连接
按照步骤执行下列命令:
1.进入linux-2.6.32.2这个目录,从终端输入命令:
cd /opt/linux-2.6.32.2
2.执行以下命令来使用缺省配置文件 config_w35(不同的屏幕尺寸对应的配置文件不同)
sudo cp config_mini2440_w35 .config
3.然后执行“sudo make menuconfig“,出现配置内核界面,并且这时不用做任何更改,在主菜单里选择
4.输入make 命令,开始编译内核。
这时出现了arm-linux-gcc找不到的错误[3]。这是因为执行make命令是以超级用户执行的,而超级用户的的PATH里,并没有/usr/local/arm/4.4.3/bin。
解决方法是:
1.先打开一个超级用户权限的shell:
命令:sudo –s
2.在当前shell下,设置环境变量:
命令:gedit /etc/profile
在文件末端加上 export PATH=$PATH:/usr/local/arm/4.4.3/bin,并保存。
3.执行source /etc/profile 这是避免重新启动ubuntu而又使刚刚修改的环境变量生效的方法。
/etc/profile的作用是:此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行. 并从/etc/profile.d目录的配置文件中搜集shell的设置.
加载内核驱动
将编译好的GPIOs.ko文件通过ftp传给ARM开发板,用insmod GPIOs.ko命令将驱动动态加载入内核。可以通过lsmod命令查看所有动态加载的module.
cat /proc/devices查看主设备号,cat /proc/misc查看所有misc设备的次设备号。
因为GPIOs被定义为一个misc设备,而misc设备无需mknod就可以自己创建设备节点(即设备文件)
用户层App
用户层的调用主要使用了高级驱动设备ioctl控制的功能,它和read,write等调用不一样。它不进行文件读写,虽然也是打开文件进行操作。它实现的是通过设备驱动程序执行各种类型的硬件控制,比如,用户空间请求设备锁门,弹出介质,报告错误信息,改变波特率。或者像这个例子一样,改变GPIO的高低电平。
在终端中调用
./GPIOApp 0 0 即可置GPIOF0口为3.3V电平 ./GPIOApp 0 1 即可置GPIOF0口为0V电平
Reference
[1].LDD3 P137
[2].http://www.360doc.com/content/12/0106/16/1317564_177703831.shtml
[3].http://blog.sina.com.cn/s/blog_7d3976fc01012c2d.html
[4].http://tieba.baidu.com/p/2055472114