最近的时间了,本人都在从事软硬件间的程序设计,虽然我懂得不多,但是经过一段时间的摸索之后也找到了一些解决问题的方法。虽然从前的我,只会写软体程序,也从来没有想到我会接触到这个领域的东西,但是经过这几个月的努力终于有了一些小小的收获。
我所使用的实验平台是S3C2440A开发板,外观如下图:
这篇文章主要针对如何在Linux环境下驱动LED灯号做一个简单的说明,内容包含如何撰写一个Linux的module、如何使用module、如何测试module。在嵌入式系统中最常碰到的事情就是要控制周边的装置,例如灯号、蜂鸣器等等,这些装置可以通过GPIO来做控制,GPIO到底是什麽东西呢?你可以把GPIO当作是一堆可以控制周边装置的暂存器,每个暂存器都会有他对应的实体位置,对这些暂存器设定一些数值就可以控制周边的装置。我们先从最简单的LED控制开始研究,其他的装置都是大同小异,我也会在后面的文章中陆陆续续的说明这些装置如何来实作。我们假设已经可以正常的从S3C2440实验版上通过boot loader正常开机,并且载入Linux作业系统。如果我们能在Linux作业系统下控制LED灯号的亮或暗,就完成本文章的目的。
目前开发板上所使用的作业系统为Linux 2.4.18,所以该模组是针对2.4.18所撰写的,所以必须在编辑环境(我们所使用的开发环境是Dev-C++,请参考之前的文章)中include到2.4.18的kernel,设定的方法:「专桉(p)」->「专桉选项」,会弹出如下图的视窗,请设定「档桉/目录」->「引入标头档目录」,加入Linux 2.4.18中的include的目录。
接下来我们必须先了解一下灯号的接线,了解灯号到底使用到哪些GPIO,你可以去翻阅你手边所拥有的线路图,应该能找到一份有关Led的讯号接线方式,如下图所示:
从图中你可以了解到控制第一个Led是由EINT4/GPF4来做控制的,有些线路图可能不会直些写出是哪个GPIO,你可能要去找找这个符号对应到2440A处理器的哪一个接脚以得知是由哪个GPIO控制。这张图显示第一个灯号是由GPF4所控制,当你知道是由GPF4所控制你可以从S3C2440A的规格书中得知对应的Address,如下图所示:
当你已经得知这些基本的资料后可以开始撰写Linux的驱动程序。
如何撰写一个Linux的module在这裡我们打算以module的方式将led driver放进Linux中,这种方式能让你日后容易维护,有需要修改时只要将该module修改好之后就可以使用,不必重新编译整个Linux Kernel。
一个module必须包含的三个东西:
1. 提供哪些控制的方法:
struct file_operations QuickMarkLed_ctl_fops= { 方法: 函数名称, 方法: 函数名称…};
方法:如ioctl
函数名称:如QuickMarkLed_ctl_ioctl,该函数后面要自己实作,撰写其动作方法
2. 初始化函数:
int init_module(void)
{
//想要初始化的资料,我们会在这裡注册一个装置
//register_chrdev(装置编号, 装置名称, 提供哪些控制的方法);
//装置编号:0~255 随便选一个号码,建议选择127以后的号码,
// 不要与系统其他装置的号码冲到
//装置名称:一个字串,自己随便取,让使用者知道这是什麽装置
//提供哪些控制的方法:是一个结构指标,裡面纪录可以对该装置做哪些动作,如read, write, ioctl…
}
3. 模组关闭函数:
void cleanup_module(void)
{
//反注册该装置
//其它记忆体的使用归还
}
所以一个模组是由这三部份组成,只要掌握好这三部份就快要成功了。再来我们要做的事就是存取装置暂存器,我们存规格书中知道GPFCON的位置是0x56000050,GPFDATA的位置是0x56000054,GPFUP的位置是0x56000058,因此我们在程序码定义了这些位置,我们以base=0x56000000加上0x50就是GPFCON,宣告如下:
#define GPIO_CTL_BASE 0x56000000
#define bGPIO(p) __REG(GPIO_CTL_BASE + (p))
#define rGPFCON bGPIO(0x50)
#define rGPFDAT bGPIO(0x54)
#define rGPFUP bGPIO(0x58)
针对这些位置最控制,该bit是0就会亮灯,如果是1就会暗灯,如此控制灯号闪烁。void QuickMarkLed_ctl_ioctl(struct inode*inode,struct file *flip,U32 ledNumber, U32 ledStatus)函数提供外界控制灯号的方法,ledNumber表示要控制哪个灯号,目前开发板上有四个led灯号,ledStatus表示要使该灯号亮或不亮,可参考后面范例以了解其控制的方法。
程序码下载:让使用者能够控制实验版上的LED灯号,编译完成之后会产生main.o的档案
如何使用module
将main.o改名为QuickMarkLed.o download到实验版上
在Linux下执行:
insmod QuickMarkLed.o
mknod /dev/QuickMarkLed c 221 0
如何测试module
测试程序如下:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/kd.h>
#include <signal.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int testdev;
//led test…
testdev = open(“/dev/QuickMarkLed”,O_RDWR);
ioctl(testdev, 2, 1); //ioctl(device, led number, open/close) open=1
ioctl(testdev, argv[1][0]-‘0’, argv[2][0]-‘0’); //ioctl(device, led number, open/close) open=1
close(testdev);
return 0;
}
编译完该程序,如果成功出始化会先将第二个灯号设成亮,之后通过使用者输入了两个参数设定Led的明暗,假设编译完成产生执行档的档名叫leds
leds 1 1 ->表示第一个led亮
leds 1 0 -> 表示第一个led暗
leds 2 1 -> 表示第二个led亮…..以此类推