[STM32F0] STM32F0单片机快速入门三 MCU启动过程

[复制链接]
2161|49
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:00 | 显示全部楼层
3. 启动代码(Startup Code)
我们还是以下面这个最简单的GPIO翻转代码为例:

STM32Cube_FW_F0_V1.11.0\Projects\STM32F030R8-Nucleo\

Examples\GPIO\GPIO_IOToggle\MDK-ARM\Project.uvprojx
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:00 | 显示全部楼层
把此工程下载到单片机后,用调试器观察下面两个地址的内容:

我们会发现0x0000_0000开始的区域, 和0x0800_0000开始的区域,内容完全相同。这说明Flash 区的内容映射到了 0x0000_0000起始的这一段地址区域。
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:02 | 显示全部楼层
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:02 | 显示全部楼层
注意STM32F030使用的是小端模式(Litlle Edian)。
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:04 | 显示全部楼层
不同于 MCS51 在 0x0000 放的是复位向量,STM32F030 还有其它 ARM 芯片在零地址存放的是初始堆栈指针地址。
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:06 | 显示全部楼层
0x0000 0000: (0x2000 0428) 初始堆栈指针

0x0000 0004: (0x0800 00C9) 复位向量,上电或复位后最先加载入PC
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:07 | 显示全部楼层
注:单片机上电或复位后,堆栈指针初始化和 PC 初始值的加载总是从地址 0x0000_0000,0x0000_0004获取。
在上面这种用户模式下,实际是从 Flash 区的 0x0800_0000,0x0800_0004 获取的。
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:08 | 显示全部楼层
我们可以通过调试器观察一下芯片复位后 M0 内核的寄存器:
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:10 | 显示全部楼层
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:11 | 显示全部楼层
细心的同学这时可能发现了一个问题。

堆栈指针 SP 的内容和前面存储器中的内容是对的上的。但是 PC 里的内容好像对不上啊?PC 里的值是 0x0800_00C8,存储器里明明是 0x0800_00C9 啊!
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:12 | 显示全部楼层
这里牵涉到了 ARM 体系里的两种工作状态 ARM 和 Thumb。ARM 状态下执行32位指令,Thumb状态下执行16位指令。那么如何在这两者之间切换呢,一个方法就是靠跳转地址的最低位(Bit0), 当 Bit0 设为 1 时进入 Thumb 状态,当 Bit0 设为 0 时进入 ARM 状态。
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:14 | 显示全部楼层
对于单片机来说,16位的 Thumb 指令就足够了,而且16位指令比32位指令能节省存储器空间。所以 M0 内核只支持 Thumb 指令。
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:16 | 显示全部楼层
到这里我们就可以理解复位向量为什么是 0x0800_00C9 了。
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:17 | 显示全部楼层
接下来我们来看复位向量 0x0800_00C8 指向的第一条指令:
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:19 | 显示全部楼层
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:19 | 显示全部楼层
单片机将要执行的第一条指令 0x4804,这是什么意思呢?
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:21 | 显示全部楼层
先说结论:它就是下图中,单片机复位后光标指向的这条指令:

LDR     R0, =SystemInit
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:23 | 显示全部楼层
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:23 | 显示全部楼层
在这里详细解释一下 0x4804 这条指令:

它对应的机器码是 0100100000000100

Bit15 to Bit11 (01001)为LDR(literal)指令,既从PC偏移地址取数据送至寄存器Rt。

Bit10 to Bit8  (000)表明目的寄存器Rt为 R0

Bit7 to Bit0  (00000100)表明相对于 PC 的偏移量为 0b10000,既0x10。

注意PC的值是当前地址+4。

那么从 0x080000C8 + 0x4 + 0x10 = 0x080000DC 取出数据 0x0800092D 送至寄存器 R0。此地址是 SystemInit( )函数的地址。下一条语句 BLX R0 就是调用此系统初始化函数。

SystemInit( ) 这个函数在 system_stm32f0xx.c 这个文件里,主要完成系统时钟的初始化。可以点进去看一下具体的内容。
 楼主| 花间一壶酒sd 发表于 2021-1-25 23:25 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部