[C/C++]谈谈我对STM32启动过程的理解

从*.s文件看程序启动过程

如果没记错的话,C语言中我们看代码一定都是从main()看起吧?因为“main()函数是程序的入口”,大家都这么说。但实际上如果我们从硬件上电复位看起,它并不是直接来到main()的——对于stm32单片机来说它至少还要把工程文件中对应的.s文件的汇编代码跑完才跳转到我们的用户程序。

参考资料

  1. 《STM32上电启动代码详解》
  2. 《STM32 上电后的启动过程》
  3. 《STM32启动过程解读与跟踪验证》
  4. 《RM0008-STM32F10x_Reference manual》3.4节

这几个链接的文章基本讲得差不多了。

*.s文件干了什么

startup_stm32f10x_hd.s
以startup_stm32f10x_hd.s为例,可以看到单片机从复位(Reset引脚拉低、或重新上电)到进入用户main()函数之前执行了以下操作:

  1. 指定堆、栈的起始地址和大小(字节数),但未初始化它们(这是C标准库函数__main()做事情);
  2. 建立中断向量(含栈顶指针)表:Flash中从0x08000000开始,DCD表示分配1个4字节空间;第1个4字节(0x08000000-0x08000003)放栈顶指针值,第2个4字节(0x08000004-0x08000007)放Reset_Handler()中断函数地址;
  3. 以上步骤是编译阶段完成的,然后生成.bin文件;
  4. .bin文件里面第1个4字节(0x00000000-0x00000003)为栈顶指针值,第2个4字节(0x00000004-0x00000007)为Reset_Handler()中断函数地址;后面还依次存放了各个中断函数的地址;
  5. 烧到Flash(0x08000000),单片机复位后首先把0x08000000+0x00000000=0x08000000的栈顶指针值复制到SP寄存器,再把0x08000000+0x00000004=0x08000004的Reset_Handler()地址复制到CP寄存器。这两个地址是分别和.bin文件中的偏移位置对应的;
  6. 在Reset_Handler()中先调用SystemInit函数,配置单片机时钟分频倍频系数等,得到主频;然后返回到.s文件再调用__main()函数——这个是C标准库中的函数,包括初始化堆栈;然后再跳转到用户的main(),不再返回到.s文件。

就这样进入到用户程序了。

Cortex M3核和STM32单片机启动顺序的关系

Coter M3 CPU希望从0x00000000获取复位向量(Reset_Handler地址),但STM32使用一种特殊机制,使得CPU从0x00000000获取的是栈顶指针,然后从0x00000004获得真正的复位向量(Reset_Handler地址)。但是呢,这个0x000000000x00000004并不是真正的地址,它们真正指向的地址由BOOT0、BOOT1引脚配置来指定(给出地址和实际地址之间的转换称为“映射”、给出地址此时称为“别名”)(如下图,截自中文版F10x参考手册和参考博客):

  • SRAM启动时,
Cortex M3看到的地址实际被STM32指向的地址里面的值(地址值)(个人猜测,待验证
0x000000000x200000000x200026B0
0x000000040x200000040x2000019D
  • Flash启动时,
Cortex M3看到的地址实际被STM32指向的地址里面的值(地址值)
0x000000000x080000000x200026B0
0x000000040x080000040x8000019D

总是在SRAM中的,所以启动模式不会改变它在整个单片机存储器中的位置(不会从SRAM跑到Flash)。
BOOT0和BOOT1引脚配置BOOT模式
图片引用:https://blog.csdn.net/u010761559/article/details/83538220
看到这里可能有一个问题:
这个“别名”默认就是指向外面的其他地址吗?会不会一不小心真的把这个地址当做真实地址来用了?
比如:0x00000000会不会在某种情况下既不映射到0x20000000也不映射到0x08000000,而是真的就是0x00000000

这个问题的答案可以在数据手册的《存储器映像》一章里找到:
从下图可以看到——整个存储器的0x00000000-(0x08000000-1)范围被划为Aliased to Flash or system memory depending on BOOT pins,说明这一块本来就一定会映射到外面其他区域,并不会被错误使用为实际地址。所以不用担心会有数据错误地存放到0x00000000这样的范围里面。
存储器映像

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值