GBA探索日记(7)(Interrupt)

这一节是简单地讲讲关于中断的使用.声音的播放就必修使用有关时间的中断.GBA里面有14个硬件中断可以使用,但其实我们一般都只使用其中的一个就够了.我在这里将介绍两种使用中断的方法,希望对你能有所帮助.

 

首先我介绍一个十分简单的使用中断的方法.

先看看这张图片

图中看到Work RAM的顶头03007ffc的地址就是保存中断处理函数地址的地方.

GBA程序里,你只需要简单地把你的中断处理函数的地址传输到这个32位内存块中就行了.

 

然后我们再看看有关中断控制的寄存器

1.REG_IME 硬件中断总开关

When this flag is 0, all interrupts are disabled.

REG_IME设置成0,所有中断都禁止

When 1, the setting for interrupt enable register IE is enabled

REG_IME设置成1,允许使用中断.

 

2.REG_IE 具体中断开关

With the interrupt enable register, each hardware interrupt can be individually masked

我想图中已经很清楚地显示出来它的设置方法了.

当对应位设置成1,表示开起该中断,当对应位设置成0,表示关闭改中断.

除了Timer和V -Blank中断,其它中断我们一般不用,所以也不必太在意具体的设置.

Timer中断就是简单的时间中断.前一篇日记中具体讲解了Timer的使用.当一个Timer计数器自增到溢出时,系统就会产生个Timer中断.

 

V-Blank中断是个关于显示扫描的中断.具体时间是频率是59.727 Hz,每16.743 ms一次.由于它的频率跟60Hz很接近,而且很稳定,所以AgbLib官方开发包里面也把它当成了控制声音播放的时间中断来使用. 再后面关于声音的播放部分,我也将使用它作为声音播放的时间控制. 当然,你也可以使用标准的Timer来控制时间,不过对于声音播放这种精度要求不高的控制来所,V-Blank中断完全足够了.

 

3.REG_IF

When an interrupt request signal is generated from each hardware device, the corresponding interrupt request flag is set in the IF Register

当一个中断信号由硬件产生,相应的中断标志就会出现在REG_IF寄存器里面.这样你就知道该中断是从那里产生的.

 

首先要说明的是,REG_IF是个只读寄存器.通过它你可以知道你的中断服务函数是由什么中断引起的.

 

好了,理论部分就讲完了.下面我们看看实例代码.

#include <agb.h>

void Interrupts(void);

int main()

{

                REG_IME = 0x00; // Disable interrupts

                REG_INTERUPT = (u32)Interrupts;// Set interrupt proc address (IRQHandler)

                REG_IE |= 1;                                          // Enable V-Blank IRQ.

                REG_DISPSTAT |= 1<<3;    // Enable Display V-Blank IRQ also.

                REG_IME = 1;                                       // Enable interrupts

                while(1)

                {

                }

}

 

void Interrupts(void)

{

                REG_IME = 0x00; // Disable interrupts

                if((REG_IF & 1) == 1) // 如果是V-Blank中断

                {

                                // 处理V-Blank中断的代码......

                }

                REG_IME = 1;       // Re-Enable interrups

}

 

上面中interrupts()函数首先必须将REG_IME=0x00中断总开关关掉,然后是处理中断响应的代码,最后再重新开起中断开关.当重新开起中断开关后,REG_IF就自动回复到0,也就是说,你对REG_IF的访问必须是在重新开起中断总开关REG_IME前.

 

在处理V-Blank中断的时候设计到另一个寄存器REG_DISPSTAT.通常我们如果要使用V-BLANK中断,需要把它设置成REG_DISPSTAT |= 1<<3;  // Enable Display V-Blank IRQ also.

 

下面我将简单地讲一下官方开发包里面使用中断的方法:

 AgbLib的demo,sample的代码里面都有个crt0.s的汇编程序.里面的代码除了设置GBA ROM的版本信息等,主要的就是设置中断向量表.具体的设置方法其实我不清楚,我没有学过Arm汇编,对于这个crt0.s也是无能为力.但正是这个crt0.s给我们的编译器带来了很多麻烦.比如AgbLib的crt0.s覆盖了常规C语言的入口函数.一般C语言都是从main函数入口,而AgbLib的demo,sample都是从AgbMain函数入口.而且AgbLib的代码在编译的时候去掉了一些常规C语言库函数,弄得我们不得不自己再去配置我们的gcc.所以我的建议是不要使用这种设置中断的方法,而使用前面讲解的简单使用中断的方法,那样你就可以避开使用crt0.s.编译器最好是DevKitAdv.它是个为开发GBA而已经配置好了的gcc.拿来就可以用.

 

本来我想把官方开发包里面使用中断的方法详细在这里讲解出来的,但是很不好意思地告诉大家,其实我本人对于官方开发包里crt0.s处理中断的代码都看不懂,所以无法详细说明了.

 

AgbLib里面的crt0.s加入了处理中断向量表的代码.C程序里面就只需定义一个中断向量表,每个中断的产生就会自动地启动处理该种中断的函数,而不是通过对REG_IF寄存器的访问.应该说速度更快些.如果你有兴趣,我可以告诉你具体的使用方法.我的QQ是8664220,Email是[email protected].

 

!就到这里,下一部分我们就开始声音播放的讲解了.有了这3篇日记的基础后,声音播放应该就是很简单了.等声音播放的讲解完后,我们对GBA的基础介绍大致就告一段落了.不过我们对于GBA的探索还没有完,后面我将介绍一些开发中常遇到的问题和解决方法,还包括对前面日记没有讲解到的补充以及扩充.

金点 tangl_99

2003/2/19