ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进
入多任务系统工作,并且大大提高了工作效率。采用中断比以往的查询方式占用更少的CPU时间,让
系统提供更好性能。那么中断在S3C44B0中是怎么样的呢?在开发ARM程序中是怎么样进行响应的呢
?这就是我需要学习的东西。
查询S3C44B0的手册,发现它有7种工作模式,每种工作模式是不一样的。其中最常用的,就是SVC和
IRQ模式。在使用中断之前,一定要初始化每种模式的栈指针SP,如果不初始化,肯定会出错。在CP
U进行初始化时,就需要依次进入IRQ模式,初始化SP,接着再进入SVC模式初始化SP。这样这两种模
式,就可以使用了。然后再在S3C44B0的中断向表里,初始化IRQ的中断处理程序,这段代码就是用
来根据不同中断位来调用不同的中断子程序。
对于使用C语言写的中断子程序,一定要加一些特定的修饰定义,否则C编译器不会生成适合中断模
式下运行的程序。由于我对GCC不是很了解,就调试了好几天,才发现我写的中断处理程序没有返回
去,原因就是没有加这些中断修饰定义,GCC编译器就没有生成合适返回指令。当我加了如下:
void Eint4567Isr(void) __attribute__ ((interrupt ("IRQ")));
的修改之后,就会生成合适的中断处理程序了。GCC就会编译成这样的代码:
sub lr, lr, #4 ;
stmdb sp!, {r0, r1, r2, r3, r4, ip, lr}
......
......
ldmia sp!, {r0, r1, r2, r3, r4, ip, pc}^
由于从IRQ模式返回到SVC模式,就需要把LR减4,才是PC的指令。如果不加上面的中断修饰定义,就
不会生成这样的代码,这样的函数就不能作来中断处理使用。
当然,我也是通过编译出这些的代码之后,再反汇编之后,然后发现不一样的。然后通过嵌入式汇
编也是可以实现的。比如:
void foo(void)
{
asm volatile ( "sub lr, lr, #4" );
asm volatile ( "stmdb sp!, {r0, r1, r2, r3, r4, ip, lr}" );
......
......
asm volatile ( "ldmia sp!, {r0, r1, r2, r3, r4, ip, pc}" );
return;
}
原先,在我没有找到这个定义之前,就是通过自己手动地添加上面的代码实现的。这段中断代码,
让我学会了怎么样处理中断,从SVC到IRQ模式,然后再从IRQ模式转回到SVC模式。只要从LR移动到P
C,就自己转回到SVC的模式了。
通过查找GCC的帮助文档,下面的连接:
http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html,就可看到中断函数在GCC的里声明。
5.24 Declaring Attributes of Functions
In GNU C, you declare certain things about functions called in your program which help the compiler optimize function calls and check your code more carefully.
The keyword __attribute__
allows you to specify special attributes when making a declaration. This keyword is followed by an attribute specification inside double parentheses. The following attributes are currently defined for functions on all targets: noreturn
, noinline
, always_inline
, pure
, const
, nothrow
, sentinel
, format
, format_arg
, no_instrument_function
, section
, constructor
, destructor
, used
, unused
, deprecated
, weak
, malloc
, alias
, warn_unused_result
and nonnull
. Several other attributes are defined for functions on particular target systems. Other attributes, including section
are supported for variables declarations (see Variable Attributes) and for types (see Type Attributes).
You may also specify attributes with `__' preceding and following each keyword. This allows you to use them in header files without being concerned about a possible macro of the same name. For example, you may use __noreturn__
instead of noreturn
.
See Attribute Syntax, for details of the exact syntax for using attributes.
然后再看看它的中断函数声明:
interrupt
Use this attribute on the ARM, AVR, C4x, M32R/D and Xstormy16 ports to indicate that the specified function is an interrupt handler. The compiler will generate function entry and exit sequences suitable for use in an interrupt handler when this attribute is present.
Note, interrupt handlers for the m68k, H8/300, H8/300H, H8S, and SH processors can be specified via the interrupt_handler
attribute.
Note, on the AVR, interrupts will be enabled inside the function.
Note, for the ARM, you can specify the kind of interrupt to be handled by adding an optional parameter to the interrupt attribute like this:
void f () __attribute__ ((interrupt ("IRQ")));
Permissible values for this parameter are: IRQ, FIQ, SWI, ABORT and UNDEF.
除了可以使用IRQ中断方式之外,还可以写FIQ,SWI,ABORT,UNDEF的中断处理函数。