[AT32F403/403A] 以startup_at32f403a_407.s为例详述启动文件,收获不小 临近放假偷得半日闲便来研究一下MCU的启动文件加上一直在用雅特力MCU芯片AT32F403A于是乎就以该芯片的启动文件startup_at32f403a_407.s为例与大家分享一下所学内容供大家指正和参考其他的启动文件一般大同小异3812769858ae28d2d8.png(135.1 KB, 下载次数: 2)下载附件2026-2-6 14:32 上传启动文件的后缀一般是.s格式即表示汇编语言assembly language所写的代码文件按其命名解释其作用无非就是“启动”的意思启动什么呢当然是启动MCU即每次MCU芯片上电运行之前第一个需要执行的代码主要负责初始化MCU硬件并引导至main主函数归根结底的说其核心作用主要包括初始化内存区域初始化中断向量表设置系统时钟调用初始化函数提供默认中断处理等等。接下来就逐个部分向大家阐述并将代码和作用对号入座一起来学习吧1、栈stack空间的大小及配置该部分的代码主要负责初始化配置栈空间默认值汇编指令EQU其实就是等于的意思即默认值为0x00000400字节即1024字节即1KB。当然你可以根据自身需求调整这个值但首先你得清楚栈上主要存储哪些内容主要包括局部变量函数内部声明的非static的变量、函数部分参数、返回地址等等。有时候一些比较诡异的让很多攻城狮头疼的程序bug比如设备运行一定时间后死机HardFault Exception异常等等其根本原因也许就是栈溢出即分配的栈空间太少了因为有时候随着程序运行时间的加长其所用的栈空间会越来越多说到底栈的本质是一种后进先出LIFO的数据结构。2、堆heap空间的大小及配置和栈空间类似该部分的代码主要负责初始化配置堆空间默认值即默认值为0x00000200字节即512字节。当然你可以根据自身需求调整这个值。堆也是一个重要的内存区域但堆与栈的最大区别就是堆需要程序员自己主动管理生命周期。堆的本质是一块由程序员在程序运行时动态管理的内存池一般会通过malloc(),calloc(), realloc() 等函数动态申请内存并通过free()函数释放内存。至于堆和栈的详细应用可以参考网上资料学习。1和2的配置作用其实就是对应的初始化内存区域的一部分。3、中断向量表地址映射这部分应该算是我们的应用程序里会经常用到的其实主要是列出了所有中断异常中断外设中断外部中断等的中断向量表的具体名称有时候我们需要使用中断服务程序ISR的时候不知道MCU的中断向量表名称是什么这个时候你就可以来启动文件里面寻找比如如果你需要用到定时器3中断就可以找到对应的是TMR3_GLOBAL_IRQHandler在应用程序里就可以这么实现有些外设功能的中断向量表是在一起的比如USBFS_L_CAN1_RX0_IRQHandler这个时候在软硬件设计的时候如果同时用上这两个功能的时候就需要考虑怎么设计了不然就会产生冲突。另外中断向量表的前面几个一般都是故障型的异常中断比如大家比较常见的也是看着就有点头疼的HardFault_Handler硬件故障中断不同MCU厂商在中断向量表名称的定义上都是有些差别的所以要知道这一点还是比较重要的。4、系统初始化配置Reset_Handler主要负责MCU芯片上电后的系统初始化操作会通过IMPORT汇编指令导入main函数和SystemInit函数其中的SystemInit函数就是启动微控制器系统的作用通过汇编语句LDR R0, __SystemInit将 SystemInit的地址加载到 R0 寄存器中再通过BLX R0执行SystemInit函数。通过汇编语句LDR R0, __main将 main 的地址加载到 R0 寄存器中再通过BX R0跳转到main函数。5、定义弱符号WEAK其实是一个汇编伪指令其主要作用就是定义弱符号所谓的弱符号就是允许链接器在特定情况下进行灵活的符号解析。通俗一点讲就是如果应用程序里没有实现这些函数链接器会使用这里默认的实现如果应用程序自定义重写了弱符号则链接器会使用应用程序里面的即所谓的强符号强符号可以覆盖弱符号。因为如果不加WEAK当用户没有实现某个中断处理函数时链接器会报告未定义符号的错误比如我把WWDT_IRQHandler屏蔽掉然后应用程序也没定义编译则会报错6、堆栈空间初始化以上汇编代码的主要作用其实就是系统实际初始化已分配好空间大小的堆和栈将栈和堆指针分配加载到R0R1R2R3等寄存器中其中Stack_Mem: 就是代表栈内存区域的起始地址Stack_Size: 就是代表栈的总大小以字节为单位即1所述的内容。Heap_Mem: 就是代表堆内存区域的起始地址Heap_Size: 就是代表堆的总大小以字节为单位即2所述的内容。汇编语句BX LR的作用就是返回到调用处跳回LR保存的地址继续从调用点之后执行。汇编代码的功底有限就不在这里班门弄斧了7、启动文件的Rebuild另外程序Rebuild的时候启动文件也会被加入build序列只是不像源文件使用“compiling”一样汇编文件会直接跳过“预处理”和“编译”的过程直接使用“assembling”进入汇编过程因为一般情况下从源代码到可执行文件是需要经过预处理Preprocessing、编译Compilation、汇编Assembly和链接Linking等过程。同样的启动文件经过汇编后也会产生对象文件.o目标文件和依赖文件.d这里的依赖文件的内容如下所示主要用于描述目标文件是由哪些源文件产生的这里的startup_at32f403a_407.o文件只由startup_at32f403a_407.s文件产生而对于包含多个文件的源文件而言则会有更多依赖关系如下所示的add_di.d应用文件此外还可以在工程的listings文件夹下面看到一个startup_at32f403a_407.lst文件这个文件我们可能很少关注因为貌似用不上其实这个文件是一个汇编列表文件一般由MCU的编译器或汇编器在编译过程中产生作用嘛主要包括三个方面吧提供源代码与机器码的对应关系即显示汇编指令和生成的机器码提供内存地址分配信息即每条指令在内存中的具体位置提供符号表信息即变量和函数的地址分配。在实际的bug排查过程中我倒是没有用过这个文件不知道哪位大佬用它来解决过问题欢迎来贴分享除此之外在在工程的listings文件夹下面的映像文件map里面也可以看到启动文件的相关信息以上所有便是我对启动文件的相关内容的研究和解读如有描述和解释不当之处欢迎大家指正和参考~~我们一起进步---------------------作者dffzh链接https://bbs.21ic.com/icview-3505855-1-1.html来源21ic.com此文章已获得原创/原创奖标签著作权归21ic所有任何人未经允许禁止转载。