admin管理员组

文章数量:1608851

PC:Program Counter,是通用寄存器,但是有特殊用途,用来指向当前运行指令的下一条指令。
SP:Stack Pointer,堆栈指针,也是通用寄存器,用于入栈和出栈操作。
对于ARM7而言,是三级流水线结构,一条指令为4个字节大小,一条指令包含三个过程:Fetch(取指)、Decode(译指)、Execute(执行)。
CPU运行地址 = 当前PC值 = 当前程序执行位置 + 8;
对于ARM7而言,PC为R15,SP为R13。
PC不是指向正在执行的指令,而是始终指向下一个取指的指令。对于ARM7三级流水先结构和指令的三个过程,所以PC = 当前程序执行位置 + 8。

再造STM32—第十二部分:启动文件详解
https://blog.csdn/qq_38351824/article/details/89791784?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164319801916780265483984%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=164319801916780265483984&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-3-89791784.first_rank_v2_pc_rank_v29&utm_term=AREA++++STACK%2C+NOINIT%2C+READWRITE%2C+ALIGN%3D3&spm=1018.2226.3001.4187
STM32的中断向量表规定每一行必须是SP地址,第二行是复位中断入口地址,上电后,CPU首先就会读这两个值,分别存为SP和PC寄存器。上述流程第一行_initial_sp就是SP地址。 那么_initial_sp的值是怎么得到的呢?这是根据STM32的SRAM分配规则计算的,SRAM从规定的地址开始分别存付已初始全局和静态变量、未初化全局和静态变量、堆、栈,其中变量的长度是你写程序后就固定了,堆和栈的长度则是在启动代码中定义的,那么把它们加起来就会得于_initial_sp的值,编译后,_initial_sp就被替代为上述计算好的地址。
第二个问题,上电已经初始了SP,为什么后边又初始化堆栈?因为上电只是将_initial_sp值存入了SP寄存器,这只是一个栈顶指针,但堆的大小和栈的大小并没有初始化,所以在_main中要把在启动文件中定义好的值传给C库进行堆栈大小的初始化。无论是带系统的,还是裸机程序,都要管理堆栈的大小,这就是会产生堆栈溢出的原因。

另外,对于有MMU的系统,在进入保护模式后,地址切换到虚拟地址,还要对SP重新赋值,因为上电时的地址是实模式下真实的物理地址,而MMU是虚拟线性地址
文链接:https://blog.csdn/qq_23899395/article/details/90344731

STM32上电复位与手动复位介绍----执行复位中断处理函数

上电复位:STM32的复位引脚低电平有效,但是低电平、高电平在电气特性中有一定的范围,刚上电瞬间,复位电路电容两端没电为0V,此时复位引脚处于低电平状态,同时电容一直在充电, 当电容电压上升到一定值时,复位引脚就变成高电平。

手动复位:按下按键,电容两端和地直接相连,电容放电,放电到低电平电压时,产生复位信号
原文链接 https://blog.csdn/weixin_42957722/article/details/105029395

STM32启动过程分析

原文链接:https://blog.csdn/luobeihai/article/details/117595762

1.1 STM32的程序在flash上的存储结构

1.2 STM32的数据在SRAM上的存储结构

2. STM32启动过程概述
STM32 启动过程主要指的是,系统上电后 CPU 执行的第一条指令,到调用用户写的 main 函数的这一段过程。具体启动过程的步骤和所完成的工作是:

(1) 上电复位,硬件设置 SP、PC 的值

(2) 找到了 Reset_Handler 的地址后,CPU 就从这里开始取指令运行程序;

(3) 调用 SystemInit 函数,设置系统时钟;

(4) 调用 __main 函数,软件对 SP 寄存器赋值,完成数据段的重定位、清除 bss 段,初始化栈空间等工作;

(5) 最终 __main 函数会调用用户的 main 函数,进入到用户程序

对于 Cortex-M3 内核,ARM 规定向量表的起始位置存放的是栈顶指针 MSP 的地址值,紧接着存放的是复位中断入口函数的地址。当刚上电的时候,硬件会根据向量表的地址找到向量表的具体位置(对于向量表的地址是可以通过 NVIC 中的一个重定位寄存器来设置的,复位时该寄存器的值为0),然后会根据向量表中的这两个数据,设置 SP、PC 的值,这时 CPU 就会从复位中断的入口函数开始取指令运行程序

汇编指令

import,标识符表明要调用的函数为本模块外部定义的
export,标识符表示本模块中定时的符号可以为外部模块使用
DCD
数据定义( Data Definition )伪指令
数据定义伪指令一般用于为特定的数据分配存储单元,同时可完成已分配存储单元的初始化。
DCD ( DCDU ) 用于分配一片连续的字存储单元并用指定的数据初始化。

汇编proto、proc、invoke伪指令与函数声明、函数定义、函数调用
一、proto伪指令–函数声明
功能和高级语言中的函数声明一样,在代码最前面写函数声明,在后面写函数定义

proto伪指令的格式

函数名 proto [距离] [语言] [参数1]:数据类型,[参数2]:数据类型,……

代码示例:

Asm_Function_1 proto stdcall arg1:dword,arg2:dword

二、proc伪指令–函数定义
使用proto指令用来函数声明,使用proc函数用来函数定义。使用规则和proto指令一样

代码示例:

proc stdcall arg1:dword,arg2:dword
  函数体代码块...
Asm_Function_1 endp

注意事项:
函数定义语句和proto一样,写完函数体代码之后需要以[函数名] endp结束函数定义
但proc和proto搭配使用时,proto可以省略参数名,但proc不能省略。(和C中的规则一模一样)

三、invoke伪指令–函数调用
使用invoke伪指令会帮你完成参数校检和压参操作,也就是说不用写压参的push指令。直接和高级语言一样直接调用函数即可

invoke伪指令的格式

invoke 函数名[,参数1][,参数2]……

代码示例:

invoke  Asm_Function_1,100,0x100

注意事项:
函数名称和参数,参数和参数之间都用 空格 隔开

原文链接:https://blog.csdn/u011770174/article/details/77914375

https://wwwblogs/yangguang-it/p/6746065.html

启动文件由汇编编写,是系统上电复位后第一个执行的程序。主要做了以下工作:

1、 初始化堆栈指针 SP=_initial_sp (差点把初始化堆栈指针跟初始化堆栈搞混·)
2、 初始化 PC 指针=Reset_Handler
3、 初始化中断向量表
4、 配置系统时钟
5、 调用 C 库函数_main 初始化用户堆栈,从而最终调用 main 函数去到 C 的世界

WEAK:表示弱定义,如果外部文件优先定义了该标号则首先引用该标号,如果外部
文件没有声明也不会出错。这里表示复位子程序可以由用户在其他文件重新实现,这里并
不是唯一的。
IMPORT:表示该标号来自外部文件,跟 C 语言中的 EXTERN 关键字类似。这里表
示 SystemInit 和__main 这两个函数均来自外部的文件。
SystemInit()是一个标准的库函数,在 system_stm32f4xx.c 这个库文件总定义。主要作
用是配置系统时钟,这里调用这个函数之后, F429 的系统时钟配被配置为 180M。
__main 是一个标准的 C 库函数,主要作用是初始化用户堆栈,最终调用 main 函数去
到 C 的世界。这就是为什么我们写的程序都有一个 main 函数的原因。如果我们在这里不
调用__main,那么程序最终就不会调用我们 C 文件里面的 main,如果是调皮的用户就可以
修改主函数的名称,然后在这里面 IMPORT 你写的主函数名称即可。

你可能会说,_main函数我们也没有写啊,为什么不报错,这个_main函数是MDK编译器自动给我生成的,不用用户操心。

在启动文件里面已经帮我们写好所有中断的中断服务函数,跟我们平时写的中断服务
函数不一样的就是这些函数都是空的,真正的中断复服务程序需要我们在外部的 C 文件里
面重新实现,这里只是提前占了一个位置而已。
如果我们在使用某个外设的时候,开启了某个中断,但是又忘记编写配套的中断服务
程序或者函数名写错,那当中断来临的时,程序就会跳转到启动文件预先写好的空的中断
服务程序中,并且在这个空函数中无线循环,即程序就死在这里。

下面这段话引用自《 CM3 权威指南 CnR2》 3.8—复位序列,CM4 的复位序列跟 CM3 一样。 —秉火
注。
在离开复位状态后, CM3 做的第一件事就是读取下列两个 32 位整数的值:
1、 从地址 0x0000,0000 处取出 MSP 的初始值。
2、 从地址 0x0000,0004 处取出 PC 的初始值——这个值是复位向量, LSB 必须是1。 然后从这个值所 对应的地址处取指。

本文标签: 初始化指针详解疑问操作