目 录
目 录... 1
实验一 ARM的中断实验... 2
实验二 Linux驱动程序的编写... 7
实验三 Linux的应用程序的编写... 13
实验一 ARM的中断实验
一、实验目的
(1) 掌握ARM9 的中断原理,能够对S3C2410 的中断资源及其相关中断寄存器的进行合
理配置;
(2) 掌握对S3C2410 中断的编程的方法
二、实验内容
1、学习响应外部中断请求的配置方法,并通过定时器中断,执行中断服务子程序,使CPU板上的LED指示灯LED1、LED2闪烁发光。
三、实验设备
1、EL-ARM-830 教学实验箱,PentiumII 以上的PC 机,仿真调试电缆。
2、PC操作系统、ADS1.2集成开发环境。
四、实验原理
(一)ARM的中断原理
在ARM 中,有两类中断,一类是IRQ,一类是FIQ。IRQ 是普通中断,FIQ 是快速中断,在进行大批量的复制、数据转移等工作时,常使用此类中断。FIQ 的优先级高于IRQ。同时,它们都属于ARM 的异常模式,当一旦有中断发生,不管是外部中断,还是内部中断,正在执行的程序都会停下,PC 指针进而跳入异常向量的地址处,若是IRQ 中断,则PC 指针跳到0x18 处,若是FIQ 中断,则跳到0x1C 处。异常向量地址处,一般存有中断服务子程序的地址,所以,接下来PC 指针跳入中断服务子程序中。当完成中断服务子程序后,PC 指针会返回到被打断的程序的下一条地址处,继续执行程序。这就是ARM 中断操作的基本原理。但是,通常由于生产ARM 处理器的各厂家都集成了很多中断请求源,比如,串口中断、AD 中断、外部中断、定时器中断、DMA 中断等等,所以,很多中断可能同时请求中断,因此,为区分它们,更准确的完成任务,这些中断都有相应的优先级别,以及当发生中断时,它们都有相应的中断标志位,通过在发生中断是判断中断优先级,和访问中断标志位的状态来识别到底哪一个中断发生了。
(二)S3C2410中断的使用
首先,ARM920T CPU 的PSR 寄存器中的F 位为1,则CPU 不会响应中断控制器的FIQ 中断,同样,ARM920T CPU 的PSR 寄存器中的I 位为1,则CPU 也不会响应中断控制器的IRQ 中断,为使CPU 响应中断,须在启动代码中将其设为0,以及使INTMSK 寄存器中的相应位置0。
S3C2410 共有56个中断源,有26个中断控制器,外部中断EXTIN8~23 共用一个中断控制器,外部中断EXTIN4~7 共用一个中断控制器,9个UART 中断分成3 组,共用3 个中断控制器,ADC和触摸屏共用一个中断控制器。
中断的优先级是由主组号和从ID号的级别控制的。中断系统有6个分仲裁器和1个总仲裁器,每一个仲裁器可以处理6路中断。
中断优先级产生模块如图1-1所示。
图1-1 中断控制器原理图
从图1-1可以看出,中断优先级产生模块共有7个判优器,每个判优器是否使能由寄存器PRIORITY[6:0]决定,每个判优器下面有4~6个中断源,这些中断源对应着REQ0~REQ5 这6个优先级,这些优先级由寄存器PRIORITY[20:7]的相应位决定。
要正确使用这些中断,必须对以下中断寄存器做设置:
各个寄存器具体位定义与使用说明,可参考课堂讲义。
(三)S3C2410定时器的特点
S3C2410有5个16bit定时器。定时器0-3有脉宽调制功能(Pulse Width Modulation,PWM),定时器4是内部定时器,没有输出引脚。定时器0-1共用一个8bit prescaler,定时器2-4共用另外一个。每个定时器有一个时钟分频器,可以选择5种分频方法。每个定时器从各自的时钟分频器获取时钟信号。prescaler是可编程的,并依据TCFG0-1寄存器数值对PCLK进行分频。当定时器被使能之后,定时器计数缓冲寄存器(TCNTBn)中初始的数值就被加载到递减计数器中。定时器比较缓冲寄存器(TCMPBn)中的初始数值被加载到比较寄存器中,以备与递减计数器数值进行比较。这种双缓冲特点可以让定时器在频率和占空比变化时输出的信号更加稳定。每个定时器都有一个各自时钟驱动的16bit递减计数器,当计数器数值为0时,产生一个定时中断,同时TCNTBn中的数值被再次载入递减计数器中再次开始计数。只有关闭定时器才不会重载。TCMPBn的数值用于PWM,当递减计数器的数值和比较寄存器数值一样时,定时器改变输出电平,因此,比较寄存器决定了PWM输出的开启和关闭。自动加载功能被打开后,当TCNTn数值递减到0时,芯片自动将TCNTBn的数值拷贝到TCNTn,从而开始下一次循环,若TCNTBn数值为0,则不会有递减操作,定时器停止。
如图1-2,给出了本试验的程序流程图。
图1-2 中断处理程序实验原理图
(四)实验电路
图1-3给出了本试验的参考电路连接图。
图1-3 硬件原理图
如图1-3所示,在G端口第8位和第9位的外部各连接了一个发光二极管。
五、实验内容与步骤
(一)实验内容
1.试验例子
如图1所示,在定时器0的1秒钟中断服务程序中,根据FLAG的标志,设置端口G的第8和第9位的数值,从而改变发光二极管的显示状态。即每个发光二极管交替点亮和熄灭,但在任一时刻,两个灯一个点亮,一个熄灭。
2.设计要求
要求每个发光二极管交替点亮和熄灭,但在任一时刻,两个灯同时点亮,或同时熄灭。
(二)实验步骤及参考程序
1.实验步骤
1) 本实验仅使用实验教学系统的核心CPU 板。在进行本实验时,LCD 电源开关,音频的左右声道开关、AD 通道选择开关、触摸屏中断选择开关等均应处在关闭状态。
2) 在PC 机并口和实验箱的CPU 板上的JTAG 接口之间,连接仿真调试电缆。
3) 检查连接是否可靠,可靠后,接入电源线,系统上电。
4) 打开ADS1.2 开发环境, 从里面打开\ 实验程序\HARDWARE\ADS\ 实验六\Interrupt.mcp 项目文件,进行编译。
5) 编译通过后,进入ADS1.2 调试界面,加载\实验程序\HARDWARE\ADS\实验六\Interrupt_Data\Debug 中的映象文件程序映像Interrupt.axf。
6) 在ADS 调试环境下全速运行映象文件。观察LED1 和LED2 的变化!LED1 和LED2 灯会由于定时中断的1 秒钟发生一次,而一秒钟闪烁一次!也可以改变闪烁的频率,即改变Startup2410\target.c 文件内的void Timer1_init(void)函数里的rTCNTB1 = 48828;的赋值,数字量越小,闪烁频率越快。编译全速运行,观看结果,看闪烁频率是否发生了改变!这是对GPIO 口操作的结果。具体实现见程序。
2.参考程序
//文件名称 : Main.c
//文件功能 : 该文件为S3C2410硬件平台主程序。
#include <string.h>
#include "..\INC\config.h"
void Main(void){
Target_Init();
while(1);
}
//函数名称 : TargetInit(void)
//函数说明 : 目标板初始化程序,主函数中只需调用此函数,即可完成目标板的初始化
void Target_Init(void)
{
MMU_Init();
ChangeClockDivider(1,1); // 1:2:4
ChangeMPllValue(0xa1,0x3,0x1); // FCLK=202.8MHz
Isr_Init();
Port_Init();
Timer1_init();
Timer1INT_Init();
Uart_Init(0,115200);
Uart_Select(0);
}
//函数名称 : void __irq Timer1_ISR( void )
//定时器中断服务子程序
int flag;
void __irq Timer1_ISR( void )
{
if (flag == 0)
{
rGPGDAT = rGPGDAT & 0xeff | 0x200;
flag = 1;
}
else
{
rGPGDAT = rGPGDAT & 0xdff | 0x100;
flag = 0;
}
rSRCPND |= BIT_TIMER1;
rINTPND |= BIT_TIMER1;
}
六、思考题
LOOP的循环条件是什么?
1.请给出代码,设置端口G的第4位和第5位为输出口,并输出11,但保持端口G其余位的功能和状态保持不变。
2.ARM的异常向量表和中断向量表是什么关系?
七、实验报告要求
具体内容包含以下几项:实验题目、实验目的、实验环境、实验内容与完成情况(要求附上自主设计的源程序)、实验中出现的问题、对问题的解决方案、完成思考题、实验总结等。
实验二 Linux驱动程序的编写
一、实验目的与内容
学习linux 下键盘驱动程序的编写方法。
二、实验仪器
PentiumII 以上的PC 机,Linux 操作系统。EL-ARM830 实验箱
三、预习要求
了解Linux下驱动程序的编写方法,了解键盘控制器HD7279的控制方法。
四、实验原理
嵌入式应用对成本和实时性比较敏感,而对linux的应用主要体现在对硬件的驱动程序的编写和上层应用程序的开发上。
嵌入式linux驱动程序的基本结构和标准Linux的结构基本一致,也支持模块化模式,所以,大部分驱动程序编成模块化形式,而且,要求可以在不同的体系结构上安装。linux是可以支持模块化模式的,但由于嵌入式应用是针对具体的应用,所以,一般不采用该模式,而是把驱动程序直接编译进内核之中。但是这种模式是调试驱动模块的极佳方法。设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。同时,设备驱动程序是内核的一部分,它完成以下的功能:对设备初始化和释放;把数据从内核传送到硬件和从硬件读取数据;读取应用程序传送给设备文件的数据和回送应用程序请求的数据;检测和处理设备出现的错误。在linux操作系统下有字符设备和块设备两类主要的设备文件类型。字符设备和块设备的主要区别是:在对字符设备发出读写请求时,实际的硬件I/O一般就紧接着发生了;块设备利用一块系统内存作为缓冲区,当用户进程对设备请求满足用户要求时,就返回请求的数据。块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待。
(一)设备驱动程序的 file_operations 结构
通常,一个设备驱动程序包括两个基本的任务:驱动设备的某些函数作为系统调用执行;而某些函数则负责处理中断(即中断处理函数)。而file_operations 结构的每一个成员的名称都对应着一个系统调用。用户程序利用系统调用,比如在对一个设备文件进行诸如read操作时,这时对应于该设备文件的驱动程序就会执行相关的ssize_t (*read)(struct file *, char *, size_t, loff_t *);函数。在操作系统内部,外部设备的存取是通过一组固定入口点进行的,这些入口点由每个外设的驱动程序提供,由file_operations结构向系统进行说明,因此,编写设备驱动程序的主要工作就是编写子函数,并填充file_operations的各个域。file_operations结构在kernel/include/linux/fs.h中可以找到。
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*readv) (struct file *, const struct iovec *, unsigned long,loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long,loff_t *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
#ifdef MAGIC_ROM_PTR
int (*romptr) (struct file *, struct vm_area_struct *);
#endif /* MAGIC_ROM_PTR */
};
其中主要的函数说明如下:
1) open 是驱动程序用来完成设备初始化操作的, open还会增加设备计数,以防止文件在关闭前模块被卸载出内核。open主要完成以下操作:检查设备错误(诸如设备未就绪或相似的硬件问题);如果是首次打开,初始化设备;标别次设备号;分配和填写要放在file→private_data内的数据结构;增加使用计数。
2) read 用来从外部设备中读取数据。当其为NULL指针时,将引起read系统调用返回-EINVAL(“非法参数”)。函数返回一个非负值表示成功地读取了多少字节。
3) write 向外部设备发送数据。如果没有这个函数,write 系统调用向调用程序返回一个-EINVAL。如果返回值非负,就表示成功地写入的字节数。
4) release是当设备被关闭时调用这个操作。release的作用正好与open相反。这个设备方法有时也称为close。它应该完成以下操作:使用计数减1;释放open分配在file→private_data中的内存,在最后一次关闭操作时关闭设备。
5) llseek 是改变当前的读写指针。
6) readdir 一般用于文件系统的操作。
7) poll 一般用于查询设备是否可读可写或处于特殊的状态。
8) ioctl 执行设备专有的命令。
9) mmap 将设备内存映射到应用程序的进程地址空间。
(二)设备驱动程序的 file_operations 结构
通过了解驱动程序的file_operations 结构,用户就可以编写出相关外部设备的驱动程序。首先,用户在自己的驱动程序源文件中定义file_operations结构,并编写出设备需要的各操作函数,对于设备不需要的操作函数用NULL初始化,这些操作函数将被注册到内核,当应用程序对设备相应的设备文件进行文件操作时,内核会找到相应的操作函数,并进行调用。如果操作函数使用NULL,操作系统就进行默认的处理。
定义并编写完file_operations结构的操作函数后,要定义一个初始化函数,比如函数名可device_init(),在linux初始化的时候要调用该函数,因此,该函数应包含以下几项工作:
1) 对该驱动所使用到的硬件寄存器进行初始化。包括中断寄存器。
2) 初始化设备相关的参数。一般来说每个设备要定义一个设备变量,用来保存设备相关的参数。
3) 注册设备。Linux内核通过主设备号将设备驱动程序同设备文件相连。每个设备有且仅有一个主设备号。通过查看linux系统中/proc下的devices文件,该文件记录已经使用的主设备号和设备名,选择一个没有使用的主设备号,调用下面的函数来注册设备。
int register_chrdev(unsigned int,const char*,struct file_operations*),
其中的三个参数代表主设备号,设备名,file_operations的结构地址。
4) 注册设备使用的中断。注册中断使用的函数。
int request_irq(unsigned irq,void(*handler)(int,void*,struct
pt_regs*),unsigned long flags, const char* device, void* dev_id);其中,
irq是中断向量。硬件系统将IRQn映射成中断向量。
handler-----中断处理函数。
flags-----中断处理中的一些选项的掩码。
device-----设备的名称
dev_id------在中断共享时使用的id。
e. 其他的一些初始化工作,比如给设备分配I/O,申请DMA通道等。
当设备的驱动程序使用了如下的函数方式,则设备驱动可以动态的加载和卸载
int __init device_init (void)
void __exit device_exit(void)
module_init(device _init);
module_exit(device _exit);
当然,也可以编译进内核中。
(三)将设备驱动加到linux内核中
设备驱动程序写完后,就可以加到linux的内核中了,这需要修改linux的源码,然后重新编译linux内核。
1) 将设备驱动文件(比如device_driver.c)复制到kernel/drivers/char目录下,该目录保存了linux的字符型设备的设备驱动程序。该驱动程序中,使用 int __int device_init(void)方式编写。
2) 在 kernel/drivers/char目录下的Makefile文件中填加如下代码:
ifeq($(CONFIG_DEVICE_DRIVER),y)
L_OBJS+= DEVICE_DRIVER.o
endif
或obj-$(CONFIG_DEVICE_DRIVER) += DEVICE_DRIVER.o
如果在配置linux内核的时候,选择了支持我们定义的设备,则在编译内核的时候,会编译DEVICE_DRIVER.c,生成DEVICE_DRIVER.o文件。
3) 在kernel/drivers/char目录下修改config.in文件。在comment 'Character devices'下面填加:bool ‘support for DEVICE_DRIVER’ CONFIG_DEVICE_DRIVER。 这样在编译内核时,运行make menuconfig时,在配置字符设备时就会出现support for DEVICE_DRIVER的字样。当选中它时,编译通过,则驱动程序就加到内核中去了。
在文件系统cramfs中加上设备驱动程序对应的设备文件。挂在操作系统中的设备都使用了设备驱动程序,要使一个设备成为应用程序可以访问的设备,必须在文件系统中有一个代表此设备的设备文件,通过使用设备文件,就可以对外部设备进行具体操作。设备文件都包含在/dev目录下,linux使用的根文件系统是cramfs文件系统。这个系统是一个只读压缩文件系统,要在制作cramfs文件系统之前,在root_tech目录结构中的/usr/etc/rc.local文件下,添加相应的设备文件。用mknod命令来创建一个设备文件:mknod device_driver c 120 0,device_driver为设备文件名,c指的是字符设备,120是主设备号,0为次设备号。
device_driver这个名字与注册函数中使用的字符串要一致!
(四)将设备驱动编译成驱动模块
使用同一个驱动程序的源代码,当然一定要如下定义某些函数 int __init device_init (void);void __exit device_exit(void);module_init(device _init);module_exit(device_exit);利用相应的交叉编译器,以及编译命令,就能把device_driver.c编译成device_driver.o这样的动态驱动模块。
当编译通过后,利用NFS网络文件系统,mount到根文件系统下,在存有驱动模块的文件系统下,在linux系统的终端中,键入加载驱动模块命令 insmod device_driver.o,则系统安装上驱动模块,如果在/dev目录下没有相应的设备文件,就可以使用mknod device_name c 主设备号 从设备号 来创建一个设备文件。从而正确使用驱动模块。当卸载驱动模块时,使用 rmmod device_driver即可。删除设备文件,则使用 rm device_name。
(五)实验电路
五、实验内容与步骤
(一)预备知识
1、linux预备知识:
(1)常用指令
a、ls命令,---文件及子目录名列表
如:ls –a 显示所有文件,包括隐藏文件。
l s –l 以默认方式显示文件属性,包括大小、日期、所有者、权限及名称。
b、cd命令,---改变工作目录(目录切换)
如:cd dir 切换到当前目录下的dir 目录。
cd / 切换到根目录。
cd .. 切换到上一级目录。
c、cp命令,---复制文件和目录
语句格式:cp [源文件及路径] [目标文件及路径]
cp -r 源目录 目标目录
如:cp file1 file2 将文件file1复制成file2。
cp /root/file . 将/root目录下的文件file 复制到当前目录下,名字仍为file 。
cp file /usr 将当前目录下的文件file 复制到/usr目录下,名字仍为file 。
cp –r dir1 dir2 将dir1下的文件和目录,全部复制到dir2目录下。
d、rm,删除文件命令
如:rm file1 删除当前目录下的file1文件
rm *.c 删除当前目录下的所有c文件
rm abc.* 删除当前目录下主文件名为abc的所有文件。
rm * 删除当前目录下的所有文件
e、mkdir,建立目录
f、rmdir,删除目录,如果有-r选项,则删除目录及目录下的文件。
2、minicom介绍
minicom是Linux下一个很类似Windows超级终端的程序。很适合用于使用串口调试设备(多是网络设备)。
安装
# aptitude install minicom
配置
#minicom -s
如果是用于调试设备;只需要修改Serial port setup部分。值得注意的是Serial Device部分,默认值是/dev/ttyS1。而Debian(绝大多数Linux)中ttyS0对应的是com1;而ttyS1对应的是com2。这个是比较容易忽略的一点。
设置完成后,如果这个配制是常用的配制。建议Save setup as dfl,保存为默认。以后直接打
#minicom即可使用。
(二)实验内容
编写键盘实验程序,实现键盘驱动程序的编写方法。
(三)实验步骤及参考程序
1.实验步骤
(1)在PC机与试验箱CPU之间,连接串口交叉电缆,在PC机网卡端与试验箱的网口之间连接交叉网线。
(2)启动计算机,选择启用linux系统;系统启动后,以root用户登陆。
(3)在linux下,在tty1下把arm7279_driver.o文件放到共享文件夹内,如/home/nfs,nfs为一新建文件夹,需要更改此文件夹的权限:
chmod 777 /home/nfs
改变此文件夹权限为所有人都可以读、写与执行。
(4)在tty2下,配置minicom
minicom -s
配置要求:波特率为115200,无奇偶校验、8bit。
然后给系统上电,系统正常启动后,配置系统的ip地址。
ifconfig –eth0 192.168.1.5
192.168.1.5是试验箱网卡的ip地址,一般设置为192.168网段(私有网段),网关取默认值。
配置完毕,保存退出。
再次键入minicom,启动超级终端,键盘驱动正常后,在此可看到键值。
(5)PC机ip地址设置
ifconfig –eth0 192.168.1.1
注意:PC机ip地址与试验系统ip地址前三段应相同,保证在同一个子网内,否则无法访问。
配置完毕,可以测试是否连通:
ping 192.168.1.5
看屏幕的提示,了解网络是否正常。连上后,可进行下一步工作
(6)在tty2,把键盘驱动程序加载上,具体命令:
mount –o nolock 192.168.1.1:/home/nfs /mnt/yaffs
那么将主机上的/home/nfs下的文件挂载到试验系统的/mnt/yaffs目录下。如果挂载不成功,需要关闭linux的防火墙。
(7)挂载成功后,在tty2终端下,使用挂载驱动模块命令
insmod arm7279_driver.o
当终端上输出:
Registering Kbdboard Device -à[OK]
Initializing HD7279 Device -à[OK]
Kbd7279 Driver Installed
则说明驱动模块正常加载。
(8)正常加载后,可按下键盘,在led与终端上有相应键值显示。需要执行键盘应用程序才可以连续看到键值。
2.参考程序
struct file_operations Kbd7279_fops = {
open: Kbd7279_Open, //打开设备文件
ioctl: Kbd7279_Ioctl, //设备文件其他操作
release: kbd7279_Close, //关闭设备文件
};//其他选项省略
static int Kbd7279_Ioctl(struct inode *inode,struct file *file,unsigned int cmd, unsigned long arg)
{
int i;
switch(cmd)
{
case Kbd7279_GETKEY:
return kbd7279_getkey();
default:
printk(“Unkown Keyboard Command ID.\n”);
}
return 0;
}
static int Kbd7279_Close(struct inode * inode, struct file * file)
{
return 0;
}
static int Kbd7279_Open(struct inode * inode, struct file * file)
{
return 0;
}
static int kbd7279_getkey(void)
{
int i,j;
enable_irq(33);
key_number= 0xff;
for (i=0;i<3000;i++)
for (j=0;j<900;j++);
//如果有按键按下,返回键值
return key_number;
}
static void kbd_ISR(int irq,void* dev_id,struct pt_regs * regs)
{
disable_irq(33);
key_number = read7279(cmd_read);
switch(key_number)
{
case 0x04 :
KeyValue = 0x08;
break;
case 0x05 :
KeyValue = 0x09;
break;
case 0x06 :
KeyValue = 0x0A;
break;
case 0x07 :
KeyValue = 0x0B;
break;
case 0x08 :
KeyValue = 0x04;
break;
case 0x09 :
KeyValue = 0x05;
break;
case 0x0A :
KeyValue = 0x06;
break;
case 0x0b :
KeyValue = 0x07;
break;
default:
break;
}
printk("key_number=%d\n",KeyValue);
}
void Setup_Kbd7279(void)
{
int i;
BWSCON &= ~(3<<16); //设定数据总线宽度
set_gpio_ctrl(clk); //设定模拟clk
set_gpio_ctrl(dat); //设定模拟dat
set_gpio_ctrl(GPIO_F5|GPIO_MODE_EINT); //设定外部中断模式
set_external_irq(33,2,0); //设定下降沿触发
for(i=0;i<100;i++);
}
int __init Kbd7279_Init(void)
{
int result;
printk("\n Registering Kbdboard Device\t--- >\t");
result = register_chrdev(KEYBOARD_MAJOR, "Kbd7279", &Kbd7279_fops);
if (result<0)
{
printk(KERN_INFO"[FALLED: Cannot register Kbd7279_driver!]\n");
return result;
}
else
printk("[OK]\n");
printk("Initializing HD7279 Device\t--- >\t");
Setup_Kbd7279();
if (request_irq(33,Kbd7279_ISR,0,"Kbd7279","88"))
{
printk(KERN_INFO"[FALLED: Cannot register Kbd7279_Interrupt!]\n");
return -EBUSY;
}
else
printk("[OK]\n");
printk("Kbd7279 Driver Installed.\n");
return 0;
}
void __exit Kbd7279_Exit(void)
{
unregister_chrdev(KEYBOARD_MAJOR, "Kbd7279");
free_irq(33,"88");
printk("You have uninstall The Kbd7279 Driver succesfully,\n if you
want to install again,please use the insmod command \n");
}
module_init(Kbd7279_Init); //作为动态模块时调用
module_exit(Kbd7279_Exit); //作为动态模块时调用
六、思考题
1.驱动程序如何动态加载?
七、实验报告要求
具体内容包含以下几项:实验题目、实验目的、实验环境、实验内容与完成情况(要求附上自主设计的源程序)、实验中出现的问题、对问题的解决方案、完成思考题、实验总结等。
实验三 Linux的应用程序的编写
一、实验目的
学习linux 下键盘的应用程序编写方法
二、实验仪器
PentiumII 以上的PC 机,Linux 操作系统。EL-ARM830 实验箱
三、预习要求
了解Linux下驱动程序的编写方法,了解键盘控制器HD7279的控制方法。
四、实验原理
一般的步骤是,当应用程序的动态调试通过后,就把应用程序的可执行文件,放到root_tech 目录结构中的/usr/sbin 或/usr/bin 目录下,然后,使用mkcramfs制作工具,利用命令 MKCRAMFS root_tech rootfs.cramfs 来生成新的文件系统。当系统启动后,就可在相应的目录下,执行可执行程序。
(一)应用程序动态调试
键盘的应用程序,应该在加入键盘驱动之后使用,否则,无法正常运行!当动态加载好驱动或把驱动编进内核中去后,也可以使用两种方法运行应用程序。本方法使用动态调试法。
在使用光盘资料/实验程序/linux/Key7279/app_key/目录下的Makefile文件编译好应用程序后,将可执行文件kbd,放到主机下的共享目录/home/nfs下,利用ifconfig eth0 命令改变实验系统的IP地址,并且和主机的前三段保持一致,最后一段不同,如:主机为192.168.1.1,则实验系统可为192.168.1.5(除1外的小于255的任意数)。利用mount –o nolock 192.168.1.1:/home/nfs /mnt/yaffs 命令把主机上存放应用程序的共享的文件目录安装到实验系统的根文件系统下,之后,查看一下,/mnt/yaffs目录下是否加入了主机上的共享目录下的文件。成功后,键入执行命令 ./kbd, 则主机终端有 Open successful 输出。之后,按实验系统的键盘,通过串口线在minicom中则会输出键值。
(二)应用程序加入文件系统
编译成功后,把可执行文件,放到存放文件系统root_tech 的usr/sbin 目录或者usr/bin 目录下.之后,使用mkcramfs 制作工具,利用命令 MKCRAMFS root_techrootfs.cramfs 来生成新的文件系统。之后把它通过网口烧下载到flash 中,当系统启动后,就可在usr/sbin 目录或者usr/bin 目录下,执行可执行程序。注意该例在于说明应用程序的编写步骤,一些头文件等均没有说明,所以,完全的应用程序请参看/实验程序/linux/Key7279/app_key/Kbd.c。
(三)实验电路
五、实验内容与步骤
(一)实验内容
1.试验例子
(二)实验步骤及参考程序
1. 实验步骤
2.参考程序
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>
main(int argc, char **argv)
{
int fd;
if ((fd = open("/dev/Kbd7279", 0)) < 0)
{
printf("cannot open /dev/Kbd7279\n");
exit(0);
};
for (;;)
ioctl(fd, 0, 0);
close(fd);
}
六、思考题
1.应用程序如何动态加载?
七、实验报告要求
具体内容包含以下几项:实验题目、实验目的、实验环境、实验内容与完成情况(要求附上自主设计的源程序)、实验中出现的问题、对问题的解决方案、完成思考题、实验总结等。