打印
[STM32F0]

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

[复制链接]
手机看帖
扫描二维码
随时随地手机跟帖
21
3. 启动代码(Startup Code)
我们还是以下面这个最简单的GPIO翻转代码为例:

STM32Cube_FW_F0_V1.11.0\Projects\STM32F030R8-Nucleo\

Examples\GPIO\GPIO_IOToggle\MDK-ARM\Project.uvprojx

使用特权

评论回复
22
花间一壶酒sd|  楼主 | 2021-1-25 23:00 | 只看该作者
把此工程下载到单片机后,用调试器观察下面两个地址的内容:

我们会发现0x0000_0000开始的区域, 和0x0800_0000开始的区域,内容完全相同。这说明Flash 区的内容映射到了 0x0000_0000起始的这一段地址区域。

使用特权

评论回复
23
花间一壶酒sd|  楼主 | 2021-1-25 23:02 | 只看该作者

使用特权

评论回复
24
花间一壶酒sd|  楼主 | 2021-1-25 23:02 | 只看该作者
注意STM32F030使用的是小端模式(Litlle Edian)。

使用特权

评论回复
25
花间一壶酒sd|  楼主 | 2021-1-25 23:04 | 只看该作者
不同于 MCS51 在 0x0000 放的是复位向量,STM32F030 还有其它 ARM 芯片在零地址存放的是初始堆栈指针地址。

使用特权

评论回复
26
花间一壶酒sd|  楼主 | 2021-1-25 23:06 | 只看该作者
0x0000 0000: (0x2000 0428) 初始堆栈指针

0x0000 0004: (0x0800 00C9) 复位向量,上电或复位后最先加载入PC

使用特权

评论回复
27
花间一壶酒sd|  楼主 | 2021-1-25 23:07 | 只看该作者
注:单片机上电或复位后,堆栈指针初始化和 PC 初始值的加载总是从地址 0x0000_0000,0x0000_0004获取。
在上面这种用户模式下,实际是从 Flash 区的 0x0800_0000,0x0800_0004 获取的。

使用特权

评论回复
28
花间一壶酒sd|  楼主 | 2021-1-25 23:08 | 只看该作者
我们可以通过调试器观察一下芯片复位后 M0 内核的寄存器:

使用特权

评论回复
29
花间一壶酒sd|  楼主 | 2021-1-25 23:10 | 只看该作者

使用特权

评论回复
30
花间一壶酒sd|  楼主 | 2021-1-25 23:11 | 只看该作者
细心的同学这时可能发现了一个问题。

堆栈指针 SP 的内容和前面存储器中的内容是对的上的。但是 PC 里的内容好像对不上啊?PC 里的值是 0x0800_00C8,存储器里明明是 0x0800_00C9 啊!

使用特权

评论回复
31
花间一壶酒sd|  楼主 | 2021-1-25 23:12 | 只看该作者
这里牵涉到了 ARM 体系里的两种工作状态 ARM 和 Thumb。ARM 状态下执行32位指令,Thumb状态下执行16位指令。那么如何在这两者之间切换呢,一个方法就是靠跳转地址的最低位(Bit0), 当 Bit0 设为 1 时进入 Thumb 状态,当 Bit0 设为 0 时进入 ARM 状态。

使用特权

评论回复
32
花间一壶酒sd|  楼主 | 2021-1-25 23:14 | 只看该作者
对于单片机来说,16位的 Thumb 指令就足够了,而且16位指令比32位指令能节省存储器空间。所以 M0 内核只支持 Thumb 指令。

使用特权

评论回复
33
花间一壶酒sd|  楼主 | 2021-1-25 23:16 | 只看该作者
到这里我们就可以理解复位向量为什么是 0x0800_00C9 了。

使用特权

评论回复
34
花间一壶酒sd|  楼主 | 2021-1-25 23:17 | 只看该作者
接下来我们来看复位向量 0x0800_00C8 指向的第一条指令:

使用特权

评论回复
35
花间一壶酒sd|  楼主 | 2021-1-25 23:19 | 只看该作者

使用特权

评论回复
36
花间一壶酒sd|  楼主 | 2021-1-25 23:19 | 只看该作者
单片机将要执行的第一条指令 0x4804,这是什么意思呢?

使用特权

评论回复
37
花间一壶酒sd|  楼主 | 2021-1-25 23:21 | 只看该作者
先说结论:它就是下图中,单片机复位后光标指向的这条指令:

LDR     R0, =SystemInit

使用特权

评论回复
38
花间一壶酒sd|  楼主 | 2021-1-25 23:23 | 只看该作者

使用特权

评论回复
39
花间一壶酒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 这个文件里,主要完成系统时钟的初始化。可以点进去看一下具体的内容。

使用特权

评论回复
40
花间一壶酒sd|  楼主 | 2021-1-25 23:25 | 只看该作者

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则