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的探索还没有完,后面我将介绍一些开发中常遇到的问题和解决方法,还包括对前面日记没有讲解到的补充以及扩充.