第一步就是进行中断向量表的设置。在ARM11中,中断向量表叫做异常向量表。 ARM11共有10种异常,这个在ARM11的datasheet中有。file:///root/%E6%A1%8C%E9%9D%A2/interupt.png
这里说明一下:
异常 |
说明 |
详细说明 |
Reset |
复位异常 |
当系统刚上电,或者按下复位键时候,触发这个异常,这个时候,程序跳转到这个地址处执行程序 |
undefined_instruction |
未定义指令异常 |
当程序执行发现有一条指令是未定义的指令,会触发这个异常,这个时候,程序跳转到这个地址处执行程序 |
software_interrupt |
软中断异常 |
当软件设置软中断时,会触发这个异常,这个时候,程序跳转到这个地址处执行程序 |
prefetch_abort |
取指异常 |
当CPU取指令发生问题时,会触发这个异常,这个时候,程序跳转到这个地址处执行程序 |
data_abort |
数据异常 |
这个就包括内部取数据和外部取数据,当取数据发生问题时,会触发这个异常,这个时候,程序跳转到这个地址处执行程序 |
irq |
中断异常 |
当有中断触发后,会触发这个异常,这个时候,程序会跳转到这个地址出执行程序 |
fiq |
快中断异常 |
当快中断触发后,会触发这个异常,这个时候,程序会跳转到这个地址出执行程序 |
最后一个目前不知道是什么意思。现在也用不上,先就不管了。
异常,也都写得比较清楚,都知道这些异常大致是干什么的。这里,要注意,异常发生的时候,是跳转到异常地址去执行程序的,但是每个异常地址的大小是4个字节,4个字节大小肯定是放不下程序的。所以,肯定会有第二级跳转。所以这个异常地址的指令,就是一个跳转指令,跳转到对应的程序去执行。
这些异常,现在不用清楚这些异常怎么用,用的时候再来学习就可以了。只要知道有这么些异常就可以了。
这些异常的地址是固定的,这个和STM32是不一样的。所以,我们设置中断向量表的时候,要将这些异常写在固定的地址上。这样,程序才能正常访问这些异常。
异常 |
地址 |
Reset |
0x0000_0000 |
undefined_instruction |
0x0000_0004 |
software_interrupt |
0x0000_0008 |
prefetch_abort |
0x0000_000c |
data_abort |
0x0000_0010 |
irq |
0x0000_0018 |
fiq |
0x0000_001c |
下面就是我们的程序:
.text .global _start _start: b reset ldr pc, _undefined_instructions ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _no_use ldr pc, _irq ldr pc, _fiq _undefined_instructions: .word undefined_instructions _software_interrupt: .word software_interrupt _prefetch_abort: .word prefetch_abort _data_abort: .word data_abort _no_use: .word no_use _irq: .word irq _fiq: .word fiq undefined_instructions: nop software_interrupt: nop prefetch_abort: nop data_abort: nop no_use: nop irq: nop fiq: nop reset:
简单说明下
.text : 表示是代码段,说明下面的程序是代码
.global _start : 定义全局标号_start
_start的代码,就是设置中断向量表了。可以看出,其实都是跳转指令。不同的异常,跳转到不同的地方去执行程序,这样就实现了异常的处理。
这里
ldr pc, _undefined_instructions 1
_undefined_instructions:
.word undefined_instructions
undefined_instructions:
nop
1的指令,就是将标号_undefined_instructions地址处的值赋值给pc,这样pc的值就是undefined_instructions的值,所以就跳转到undefined_instructions程序地方去执行。这里,undefined_instructions程序就只有一个nop指令。因为目前没有用到这些异常,所以这里,除了Reset异常我们是编写代码外,其他的异常我们都是写的nop。
其他异常的分析,和以上的分析是一样的。只是要注意,我们中间定义了一个_no_use异常。可是这个异常是ARM异常里面没有的。这里定义这个异常,就是为了占一个字节大小,这样的话,irq的地址才会是0x0000_0018,否则的话就是0x0000_0014,这样就不对了。
这里有个问题,只有Reset的跳转指令是b指令,其他的指令都是ldr指令。这个是为什么了?
b指令是相对跳转指令,ldr是绝对跳转指令。在上电或者复位的时候,程序在内部的stepping stone中执行,地址从0x0000_0000开始。但是我们在编译代码的时候,用的链接脚本的链接地址是0x5000_0000,如果使用ldr决定跳转指令的话,就会跳到内存去执行程序了,这个时候,我们还没有把程序拷贝到内存中,所以执行就会出错了,所以这里使用b指令。复位结束后,我们已经把代码拷贝到内存中去了,所以这个时候,就要用ldr绝对跳转指令了。
以上,就将我们的异常向量表就设置好了,接下来,我们就对Reset函数编写代码就好了。因为这里写的代码,就是上电执行的代码。
原文来自:http://comm.chinaaet.com/adi/blogdetail/39909.html