STM32启动流程
Posted csczq54
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32启动流程相关的知识,希望对你有一定的参考价值。
启动文件主要工作: 1. 设置堆栈指针SP=_initial_sp 2. 设置PC指针=Reset_Handler 3. 配置系统时钟 4. 配置外部SRAM用于程序变量等数据存储(可选) 5. 调用C库中的_main函数,最终调用main函数
注意:CortexM4复位后,处于线程模式,指令权限是特权级别(最高级别),堆栈设置为主堆栈 复位流程: 1. 硬件复位后,CPU内的电路完成如下两个工作(Flash为例子) 2. 将0x08000000位置存放的堆栈栈顶地址存放到SP中(MSP) 3. 将0x08000004位置存放的向量地址装入到PC程序计数器 4. CPU从PC寄存器指向的物理地址取出第一条指令开始执行程序,也就是Reset_Handler。 qi
复位中断程序会调用SystemInit函数(C语言)来配置时钟、配置FSMC总线上的SRAM,然后跳转到C库的_main函数,最后由_main函数调用用户写的main()函数执行C程序 IAR中main中具体流程(http://www.cnblogs.com/mssql/archive/2011/01/29/tt146.html) 参考程序IAR(W1-Main-F4工程)// Reset_Handler LDR R0, =SystemInit;//将SystemInit函数的地址放到R0中 BLX R0;//跳转SystemInit函数 LDR R0, =__iar_program_start;// __iar_program_start函数的地址存放到R0, BX R0 PUBWEAK NMI_Handler SECTION .text:CODE:REORDER:NOROOT(1) //然后跳转到main函数中(__iar_program_start到main中还有很多隐藏部分,可不理解) Keil参考程序(STM32-X3开发板:ADC的8通道扫描模式) ; Reset handler ;利用PROC、ENDP这一对伪指令把程序段分为若干个过程,使程序的结构加清晰 Reset_Handler PROC;过程的开始 EXPORT Reset_Handler [WEAK];//弱定义,意思是如果在别处也定义该标号(函数),在链接事用别处的地址,如果没有其他地方定义,编译器也不会报错,以此地址进行链接,EXPORT提示编译器该标号可以为外部文件使用 IMPORT SystemInit;;通知编译器要使用的标号在其他文件 IMPORT __main LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP https://www.cnblogs.com/afeibfp/archive/2013/01/08/2850408.html ;BX是ARM指令集和THUMB指令集之间程序的跳转 ;使用“=”表示LDR目前是伪指令不是标准指令。这里是把__main的地址给RO __main函数由编译器生成,负责初始化栈、堆等,并在最后跳转到用户自定义的main()函数 NMI_Handler PROC EXPORT NMI_Handler [WEAK] B . ;原地跳转(即无限循环), ENDP Stack_Size EQU 0x00000400 ;//定义堆栈大小 AREA STACK, NOINIT, READWRITE, ALIGN=3 ;//定义一个数据段 按8字节对齐 ;AREA 伪指令用于定义一个代码段或数据段 NOINIT:指定此数据段仅仅保留了内存单元,而没有将各初始值写入内存单元,或者将各个内存单元值初始化为0 Stack_Mem SPACE Stack_Size ;//保留Stack_Size大小的堆栈空间 分 配连续 Stack_Size 字节的存储单元并初始化为 0 __initial_sp ;//标号,代表堆栈顶部地址,后面有用 ; <h> Heap Configuration ; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> ; </h> Heap_Size EQU 0x00000200 ;//定义堆空间大小 AREA HEAP, NOINIT, READWRITE, ALIGN=3 ;//定义一个数据段,8字节对齐 __heap_base ;//标号,代表堆末底部地址,后面有用 Heap_Mem SPACE Heap_Size ;//保留Heap_Size的堆空间 __heap_limit ;//标号,代表堆界限地址,后面有用 ;PRESERVE8 指令指定当前文件保持堆栈八字节对齐。 它设置 PRES8 编译属性以通知链接器。 ;链接器检查要求堆栈八字节对齐的任何代码是否仅由保持堆栈八字节对齐的代码直接或间接地调用。 PRESERVE8 ;//指示编译器8字节对齐 THUMB ;//指示编译器以后的指令为THUMB指令 ;******************************************************************************* ; User Stack and Heap initialization ;******************************************************************************* ;堆和栈的初始化 IF :DEF:__MICROLIB ;“DEF”的用法——:DEF:X 就是说X定义了则为真,否则为假 ;如果定义了MICORLIB, EXPORT __initial_sp ;则将栈顶地址, EXPORT __heap_base ;堆起始地址赋予全局属性, EXPORT __heap_limit ;堆末端界限地址赋予全局属性,使外部程序可调用 ELSE ;如果没定义__MICROLIB,则使用默认的C运行时库 IMPORT __use_two_region_memory ;;通知编译器要使用的标号在其他文件__use_two_region_memory EXPORT __user_initial_stackheap ;声明全局标号__user_initial_stackheap,这样外程序也可调用此标号 ;则进行堆栈和堆的赋值,在__main函数执行过程中调用 ;如果使用默认的C库,程序启动过程中就不会执行该标号下的代码 __user_initial_stackheap ;标号__user_initial_stackheap,表示用户堆栈初始化程序入口 ;//则进行堆栈和堆的赋值,在__main函数执行过程中调用。 LDR R0, = Heap_Mem ;保存堆始地址 LDR R1, =(Stack_Mem + Stack_Size) ;保存栈的大小 LDR R2, = (Heap_Mem + Heap_Size) ;保存堆的大小 LDR R3, = Stack_Mem ;保存栈顶指针 BX LR ALIGN ;填充字节使地址对齐 ENDIF END
以上是关于STM32启动流程的主要内容,如果未能解决你的问题,请参考以下文章