当前位置:   article > 正文

漫谈关于AT32F415的启动流程与内存分配_at32的booto

at32的booto

       AT32F415裸机开发时,启动流程一般包含:上电->复位->取字(栈指针、PC的初始值)->复位向量执行->跳转到主函数执行程序。

    1.  至于ARM芯片为何需要复位,这里不展开说明,感兴趣可以去找资料。

    2.系统复位后以及处理器开始执行程序前, 处理器会从 CODE 存储器中读出前两个字。
 从地址0x0000_0000处取出主栈指针( MSP)的初始值;从地址0x0000_0004处取出程序计数器( PC)的初始值, 这个值是复位向量, LSB必须是1。然后从这个值所对应的地址处取值。

3.在 AT32F415 中,可以将主闪存存储器启动程序存储区片上 SRAM 这三块存储器重映射到
0x0000_0000~0x07FF_FFFF 的 CODE 区,由 BOOT1 和 BOOT0 管脚来设定 CODE 从哪块存储器启动,当{BOOT1, BOOT0}=00/10 时, CODE 从主闪存存储器启动,当{BOOT1, BOOT0}=01 时, CODE从启动程序存储器启动,当{BOOT1, BOOT0}=11 时, CODE 从片上 SRAM 启动。系统复位后或从待机模式退出时, BOOT1 和 BOOT0 管脚值都会被重新锁存。
启动程序存储器中包含内嵌的 Bootloader 程序, 可提供 flash 编程功能, 通过 USART2 或 USB 接口对flash 进行重新编程;也可以提供通信协议栈等额外的固件,可被软件开发人员通过 API 调用。

图1 AT32F415的内存映射与启动位置说明

4.程序在FLASH和SRAM的空间分配

    当使用keil进行单片机的开发时,运行一段程序后,在output输出框会看到如下图的结果。

图2  程序编译结果

其中,Compiler编译器,使用的版本是 V5.06,程序会先经过编译、后链接linking生成可执行的代码,如果要下载单片机的Flash上,还需要转换成二进制(bin)或者十六进制(hex)的文件。具体过程如下:

图3 keil的编译过程

值得注意的是,经过编译后,并不会给变量赋地址(.o文件),只有经过链接器链接后变量才有地址,链接的作用可以看做是便于管理而做的分类,在链接阶段起作用的是分散加载文件,分散加载文件用来描述生成映像文件时所需的信息,即通过分散加载文件指定ARM链接器在链接阶段如何分配Code、RO-data、RW-data、ZI-data地址,只用使用了分散加载文件后,你程序的变量、函数等数据才会有地址,只有如此做,程序在运行时,才能根据分配的地址去下一步执行程序,分散加载文件后面会详细讲解,这里只初步了解一下就可以。经链接后代码分为Code、RO-data、RW-data、ZI-data四部分。接下来是老生常谈的问题,每个区都是干嘛的呢?

  • CODE:代码区,指程序中代码即函数体的大小,注意程序中未使用的函数也会算在CODE中,也即会占用FLASH空间,因此不用的函数最好删除掉,以免占用过多FLASH空间;
  • RO-DATA:RO就是只读的意思,程序中只读的变量(也就是带Const的)和已初始化的字符串等;
  • RW-DATA:特指已初始化的可读可写全局/静态变量;
  • ZI-DATA:未初始化的可读可写全局/静态变量,注意初始化为0也算做未初始化,用到的堆空间和栈空间也会被算入这里面;

  之前我一直在想的一个问题是我的局部变量存放在哪里,其实是这样的,局部变量只有在程序运行的过程中才会生成,当程序不运行,即将关闭单片机的电源后,是没有局部变量的。所以这就要涉及到程序的两种状态存储态和运行态。

图4 程序的存储态和运行态

存储态:向Flash中下载程序时,其实仅仅下载的是CODE+RO-data+RW-data的内容,意思就是说,在掉电情况下,Flash里面的内存仅包含CODE+RO-data+RW-data这三块。

图5 程序在用户Flash上的结构(存储态)

运行态:当上电后,程序运行时,首先程序会从特定的地址进行启动,启动时会将RW-data的数据加载到SRAM中(启用文件中有一段代码是干这件事的,说的在具体点是分散加载文件会做这件事,在默认情况下,keil中的链接器armlink工具(D:\Keil_v526\ARM\ARMCC\bin\armlink.exe)已经帮你做完了这件事),单片机的 RO区域不需要加载到 SRAM,内核直接从 FLASH 读取指令运行。那ZI-data的数据怎么办呢?对于初始值为0全局变量来说,因为要在Code区要调用该全局变量,所以肯定要对其进行描述,程序运行时就知道了,原来你是初始值为0的全局变量呀,然后分散加载文件就在SRAM中给它分配了一段固定区域的地址;对于局部变量来说, 会自动分配大小,不用我们管。RW-DATA+ZI-DATA就是程序运行总共会占用SRAM的长度,为什么说总共呢?因为当某一个函数运行完后,在这个函数内部的局部变量会被释放掉。

再次强调一下,堆空间栈空间包含在ZI-data区的范围

图6 程序的组成

通常,对于栈生长方向向下的单片机,其内存一般模型是:

图7 内存模型

根据AT32F415的内存映射图可知SRAM的开始地址是:0x20000000,而根据图2程序编译结果可以看到RW-data=360 ZI-data=7392.由图7可知栈顶地址 = 0x20000000 +  RW-data + ZI-data = 0x20001e48,下面观察MDK中,地址0x0000_0000处取出主栈指针( MSP)的初始值:

图8 仿真观察到的内存值

可以看到MSP=0x20001e48,与计算结果吻合。PC=0x0800024d,表示复位中断的入口地址为0x0800024d(BOOT引脚设定程序从FLASH启动)。

下面是一段程序变量的位置:

图9 内存位置示例

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

闽ICP备14008679号