ARM Cortex-M3中断跳转过程

来源:互联网 发布:保鲜膜pe和pvdc 知乎 编辑:程序博客网 时间:2024/06/06 07:13

在学习CM3的时候,仔细学习了CM3的中断跳转过程,发现嵌入式的MCU在这一块基本上是一样的,当然不同架构的MCU也有自己的特性。

我来介绍下CM3的中断跳转过程,首先假设中断发生,CM3内核开始响应中断,由于不同厂家的CM3可能略有区别,但CM3的内核肯定是一样的,所以我们在这个前提下开始讨论,暂时把中断屏蔽位,标志位之类的东西放在一边。

现在介绍中断响应的过程:

1、压栈。从这一点来讲几乎所有的处理器都是一样的,用压栈保护现场。压入哪些寄存器呢,又是怎样一个顺序?如果就大多数的C语音编程来讲,这个不是很关心的内容。但是CM3的压栈寄存器特点,让我们来见识下ARM设计的特点。其压栈顺序如下图所示,请注意压栈的地址顺序和时间顺序不是相同的。

地址(SP)

寄存器

被保护顺序(时间顺序)

N-0

之前已压栈内容

 

N-4

xPSR

2

N-8

PC

1

N-12

LR

8

N-16

R12

7

N-20

R3

6

N-24

R2

5

N-28

R1

4

N-32

R0

3

这一点就我们普通coding来讲,是非常奇特的,堆栈的空间顺利和进栈时间没有必然联系,跟我们“后进先出”的观点有很大出入,那么显然这里的“堆栈”,并不是我们传统意义的上的堆栈,具体怎样实现ARM没有详述,只是说他们可以做到这点。

我们可以看到PC,xPSR,R0,R1,R2,R3是率先入栈的(时间上),这样做的目的,是为了编译器优先使用入栈了的寄存器来保存中间结果(如果程序过大也可能要用到R4-R11,此时编译器负责生成代码来push它们)。这也是要求ISR尽量短小的原因,用更少的寄存器,以加快响应。

2、查找中断向量表。其实这一步跟第一步是并行的,只是为了分别介绍我,列了序号。ARM是有D-Code(数据总线)和I-Code(指令总线),两条总线。可以看到PC是第一个压栈的,此时数据总线正忙于压栈操作,与此同时指令总线就可以查找中断向量表,查询中断服务程序的入口地址。在CM3中中断向量表位于地址从0x00000000开始的一段存储空间,每个表项占一个字(4byte)。这是中断向量表没有重定位的情况,当然中断向量表也可以重定位,即存储在其他地方。这个需要设置相应的寄存器,我个人认为还是让其固定在这个默认的位置比较好,以免出现以外情况。在看中断向量表的时候我遇到了一个很有意思的问题:

中断服务函数的入口地址为0x67C(图1所示),但是中断向量表中存储的地址确是0x67D(图2所示),竟然加了1。

    这让我纠结了很久,后来一位整ARM7的大牛解答了我的问题。ARM的PC最低位是0的时候ARM会进入ARM模式,但是最低位是1的时候会进入thumb模式。而我们的CM只支持thumb模式,所以PC最低位必须为1。而且thumb指令集是16位的,所以0x67D就是指向0x67C所存储的指令,但是减一就不行了,就变成了指令空间内上一个地址存储的指令。

         把CM3中断跳转过程写出来跟大家分享,若有不妥之处,望大家斧正。

图1 方框内为所对应中断服务函数入口地



图2 方框内为中断向量表中中断服务函数入口地址

***************************************************************************

记得在DSP TMS32F2812中,中断向量的初始化是由一段地址拷贝代码完成的,在STM32(Cortex-M3)中没有显示的代码拷贝,只有启动代码进行了向量的初始化,一直以为是编译器在程序影像中自己完成了相关向量的拷贝,即,拷贝到固定的NVIC区,事实上并不是这样,cortex-m3并没有一块专门用于存放NVIC向量表的地方,这张表实际是存放在代码(程序映像)的开始,下面引用cortex-M3权威指南进行解释:

    当发生了异常并且要响应它时,CM3需要定位其服务例程的入口地址。这些入口地址存储在所谓的“(异常)向量表”中。缺省情况下,CM3认为该表位于零地址处,且各向量占用4字节。因此每个表项占用4字节,如表7.6所示。

      

  因为地址0处应该存储引导代码,所以它通常映射到Flash或者是ROM器件,并且它们的值不得在运行时改变。然而,为了支持动态重分发中断,CM3允许向量表重定位——从其它地址处开始定位各异常向量。这些地址对应的区域可以是代码区,但更多是在RAM区。在RAM区就可以修改向量的入口地址了。为了实现这个功能,NVIC中有一个寄存器,称为“向量表偏移量寄存器”(在地址0xE000_ED08处),通过修改它的值就能重定位向量表。但必须注意的是:向量表的起始地址是有要求的:必须先求出系统中共有多少个向量,再把这个数字向上“圆整”到2的整次幂,而起始地址必须对齐到后者的边界上。例如,如果一共有32个中断,则共有32+16(系统异常)=48个向量,向上圆整到2的整次幂后值为64,因此向量表重定位的地址必须能被64*4=256整除,从而合法的起始地址可以是:0x0, 0x100, 0x200等。向量表偏移量寄存器的定义如表7.7所示。

如果需要动态地更改向量表,则对于任何器件来说,向量表的起始处都必须包含以下向量:
 主堆栈指针(MSP)的初始值
 复位向量
 NMI
 硬fault服务例程
后两者也是必需的,因为有可能在引导过程中发生这两种异常。
可以在SRAM中开出一块空间用于存储向量表。在引导期间先填写好各向量,然后在引导完成后,就可以启用内存中的新向量表,从而实现向量可动态调整的能力。


0 0
原创粉丝点击