当前位置:   article > 正文

玩转STM32(16)理解复位函数_stm32复位向量

stm32复位向量

前面搞定了栈顶的问题,接着下来,可以从复位矢量表里,看到如下:

__Vectors       DCD     __initial_sp               ; Top of Stack

                DCD     Reset_Handler              ; Reset Handler

                DCD     NMI_Handler                ; NMI Handler

从向量表里看到第二项,就是复位函数的入口地址,Reset_Handler是复位向量的过程函数,它被编译之后,可以看到它表示的值是:

Reset_Handler                            0x0800019d   Thumb Code     8  startup_stm32f40_41xxx.o(.text)

前面说过CPU会在复位之后,就加载Reset_Handler到PC寄存器,也就是加载地址0x0800019d,然后就会执行复位过程函数Reset_Handler,这时就开始运行复位过程函数的代码了。复位过程函数到底做了些什么工作,才可以进入C语言的入口函数main执行呢?要回答这个问题,我们先来看复位过程函数的代码,如下:

Reset_Handler    PROC

                 EXPORT  Reset_Handler             [WEAK]

        IMPORT  SystemInit

        IMPORT  __main

 

                 LDR     R0, =SystemInit

                 BLX     R0

                 LDR     R0, =__main

                 BX      R0

                 ENDP

在上面这段代码里,使用PROC/ENDP宏指令来声明一个子过程,然后使用EXPORT指令来声明本过程Reset_Handler为弱声明,也就是后面的[WEAK]。为什么要使用WEAK指令?其实是为了方便用户来自定义自己的函数。比如用户使用默认的Reset_Handler过程函数不能满足自己的要求,需要自己定义一个过程函数来替换Reset_Handler。如果使用旧的方法,就是使用宏定义来判断,但这里使用WEAK指令之后,就可以不使用宏来实现了。编译器会直接判断编译所有文件时,是否会发现用户自定义的Reset_Handler函数,如果有就会使用用户定义的Reset_Handler函数,而不是调用这里声明为WEAK的Reset_Handler函数。如果用户没有定义,就调用默认的Reset_Handler函数。这跟C++里虚函数有点像,当派生类有相同函数名称时,就会调用派生类的函数,如果没有就调用基类的函数。因此在向量表里的中断函数,很多都是使用WEAK指令声明的,所以都会有这个作用,如果用户自己没有定义相应中断函数,就会调用默认的中断函数,这样就方便大家写中断函数的代码,不必要把所有的中断函数都写一遍,只需要写自己关心的中断函数即可,这样大大减轻了开发人员的工作量,同时代码更加标准化,更方便移植和复用。

接着下来可以看到下面这行代码:

IMPORT  SystemInit

这里使用IMPORT指令,说明后面的函数SystemInit在别的地方声明的,在这里它是在system_stm32f4xx.c文件里定义的,通过IMPORT指令才可以在startup_stm32f40_41xxx.s文件里调用它,否则它在连接时找不到这个函数,就会编译出错。

同理,IMPORT  __main代码,也是声明_main函数是在别的模块里声明和定义的,所以采用IMPORT指令。

接着会运行这行代码:

LDR     R0, =SystemInit

LDR指令是将存储器地址所指地址处连续的4个字节(1个字)的数据传送到目的寄存器中。在这里是把SystemInit的地址加载到R0寄存器。

BLX     R0

BLX reg是跳转到由寄存器reg给出的地址,并根据REG的LSB切换处理器;状态还要把转移前的下条指令地址保存到LR。这行代码就是实现调用SystemInit函数运行,运行之后跳到下一条指令执行。

LDR     R0, =__main

BX      R0

这两行语句,与前面运行SystemInit函数是一样的,在这里调用_main函数运行,这个函数里会更进一步地初始化C语言运行环境,然后调用C语言的入口函数main来运行,这样就调用C语言编写的代码了。

到这里,就完成复位函数的代码分析,理解整个复位函数为什么要这么写,以及怎么样执行每一步。

https://blog.csdn.net/caimouse/article/details/51749579

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/713289
推荐阅读
相关标签
  

闽ICP备14008679号