这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » 分析ARMCortex-M内核复位启动过程

共7条 1/1 1 跳转至

分析ARMCortex-M内核复位启动过程

高工
2023-03-21 12:52:16     打赏

    ARM Cortex-M内核的复位启动过程也被称为复位序列(Reset sequence),下面就来简要总结分析下这一过程。

    ARM Cortex-M内核的复位启动过程与其他大部分CPU不同,也与之前的ARM架构(ARM920T、ARM7TDMI等)不相同。大部分CPU复位后都是从0x0000_0000处取得第一条指令开始运行的,然而在ARM Cortex-M内核中并不是这样的。其复位序列为:1. 从地址0x0000_0000处取出MSP的初始值;2. 从地址0x0000_0004处取出PC的初始值,然后从这个值对应的地址处取指。    即下图所示过程:

image.png


    事实上,地址0x0000_0004开始存放的就是默认中断向量表(有些资料中将地址0x0000_0000处的MSP指针初始值也算作中断向量表的一部分,这个说法似乎不太妥当),ARM Cortex-M内核的中断向量表布局情况如下图所示:
image.png    注意:中断向量表的位置可以改变,此处是默认情况下的设置。
    值得注意的是,在ARM Cortex-M内核中,发生异常后,并不是去执行中断向量表中对应位置处的代码,而是将对应位置处的数据存入PC中,然后去此地址处进行取指。简而言之,在ARM Cortex-M的中断向量表中不应该放置跳转指令,而是该放置ISR程序的入口地址。    有了上面的分析就很好理解复位序列了,复位其实就相当于发生了一次Reset异常,而从图中可以看到,地址0x0000_0004处存放的正是Reset异常对应的中断处理函数入口地址。    另外还有两个细节问题需要注意:1. 0x0000_0000处存放的MSP初始值最低三位需要是0;2. 0x0000_0004处存放的地址最低位必须是1。    第一个问题是因为ARM AAPCS中对栈使用的约定是这样的:5.2.1.1
Universal stack constraints
At all times the following basic constraints must hold:
Stack-limit < SP <= stack-base. The stack pointer must lie within the extent of the stack.
SP mod 4 = 0. The stack must at all times be aligned to a word boundary.
5.2.1.2
Stack constraints at a public interface
The stack must also conform to the following constraint at a public interface:
SP mod 8 = 0. The stack must be double-word aligned.    简而言之,规约规定,栈任何时候都必须4字节对齐,在调用入口需8字节对齐,而且SP的最低两位在硬件上就被置为0了。    第二个问题与ARM模式与Thumb模式有关。ARM中PC中的地址必须是32位对齐的,其最低两位也被硬件上置0了,故写入PC中的数据最低两位并不代表真实的取址地址。ARM中使用最低一位来判断这条指令是ARM指令还是Thumb指令,若最低位为0,代表ARM指令;若最低位为1,代表Thumb指令。在Cortex-M内核中,并不支持ARM模式,若强行切换到ARM模式会引发一个Hard Fault。    最后写一段小程序来验证下以上分析。这段程序基于STM32F4系列单片机,作用是让PA0管脚输出高电平。这应该也是实现这一目的最精简的写法了。

rAHB1ENR        EQU     0x40023830AHB1ENRValue    EQU     0x00000001 rMODER          EQU     0x40020000MODERValue      EQU     0xA8000001 rODR            EQU     0x40020014ODRVaule        EQU     0x00000001
    AREA RESET, DATA, READONLY    DCD 0x00000400    DCD Start
    AREA |.text|, CODE, READONLY    ENTRY
Start    LDR R0, =rAHB1ENR    LDR R1, =AHB1ENRValue    STR R1, [R0]     LDR R0, =rMODER    LDR R1, =MODERValue    STR R1, [R0]     LDR R0, =rODR    LDR R1, =ODRVaule    STR R1, [R0]
    B .      END

    第11行使用DCD伪指令分配了4个字节的存储空间,并将其值设置为0x0000_0400;第12行同理,将Start标号处的地址放置在偏移量为4字节的位置处;第17行Start标号之后的部分就是程序主体,依次完成了GPIOA端口RCC时钟使能、PA0设置为输出模式、PA0置高这三个步骤。    程序在链接时会将RESET段放置在目标文件开头,故相当于在地址0x0000_0000处的数据为0x0000_0400,在地址0x0000_0004处的数据为Start部分的入口地址。    不过需要指出的是,实际上在STM32F4芯片中,内部Flash的地址是从0x0800_0000处开始的,在BOOT管脚设置为Flash启动的时候,芯片内部会自动将0x0000_00000 0x000F_FFFF区域映射至0x0800_0000 0x080F_FFFF处,此时可以视为二者是等价的。    使用Debug模式进行调试,复位后CPU寄存器的值如下所示:image.png    Flash中的数据如图:image.png    可以看到,编译器很智能的将0x0800_0004处的数据设置为了0x0800_0009,而不是Start标号真实的地址值,这说明了这是一条Thumb-2指令。复位后PC中的值是0x0800_0008,SP中的值是0x0000_0400,与预期结果完全相同。    最后顺便提一下,上面那段简单的程序有个问题,实际上Start部分的程序是占用了中断向量表的空间,这在没有异常发生的时候是没有问题的,不过一旦有异常发生,显然程序执行是会出错的。





关键词: Cortex-M     ARM     复位     启动    

专家
2023-03-21 13:03:00     打赏
2楼

感谢分享


高工
2023-03-21 13:15:54     打赏
3楼

感谢楼主的分享,很实用了。


高工
2023-03-21 13:42:18     打赏
4楼
分析ARMCortex-M内核复位启动过程



高工
2023-03-21 13:42:23     打赏
5楼

高工
2023-03-21 13:42:33     打赏
6楼

感谢楼主的分享,很实用了。


专家
2023-03-24 16:14:30     打赏
7楼

感谢分享


共7条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]