门户和网站的区别,上海正规建设网站私人订制,51wordpress,在阿里云安装wordpress1.STM32的启动过程模式
1.1 根据boot引脚决定三种启动模式 复位后#xff0c;在 SYSCLK 的第四个上升沿锁存 BOOT 引脚的值。BOOT0 为专用引脚#xff0c;而 BOOT1 则与 GPIO 引脚共用。一旦完成对 BOOT1 的采样#xff0c;相应 GPIO 引脚即进入空闲状态#xff0c;可用于…1.STM32的启动过程模式
1.1 根据boot引脚决定三种启动模式 复位后在 SYSCLK 的第四个上升沿锁存 BOOT 引脚的值。BOOT0 为专用引脚而 BOOT1 则与 GPIO 引脚共用。一旦完成对 BOOT1 的采样相应 GPIO 引脚即进入空闲状态可用于其它用途。BOOT0与BOOT1引脚的不同值指向了三种启动方式 从主Flash启动。主Flash指的是STM32的内置Flash。选择该启动模式后内置Flash的起始地址将被重映射到0x00000000地址代码将在该处开始执行。一般我们使用JTAG或者SWD模式下载调试程序时就是下载到这里面重启后也直接从这启动。从系统存储器启动。系统储存器指的是STM32的内置ROM选择该启动模式后内置ROM的起始地址将被重映射到0x00000000地址代码在此处开始运行。ROM中有一段出厂预置的代码这段代码起到一个桥的作用允许外部通过UART/CAN或USB等将代码写入STM32的内置Flash中。这段代码也被称为ISP(In System Programing)代码这种烧录代码的方式也被称为ISP烧录。关于ISP、ICP和IAP之间的区别将在后续章节中介绍。从嵌入式SRAM中启动。显然该方法是在STM32的内置SRAM中启动选择该启动模式后内置SRAM的起始地址将被重映射到0x00000000地址代码在此处开始运行。这种模式由于烧录程序过程中不需要擦写Flash因此速度较快适合调试但是掉电丢失。 总结不同的配置决定了MCU将何处映射到0x00000000。从这里又可以看到一点MCU眼里只有0x00000000。至于为啥可以从Flash0x08000000启动就是因为MCU内部做了映射。从其他位置启动时同理如第一列从Flash启动时原本储存在0x0800000的程序映射到0x000000位置如下图是STM32F4xx中文参考手册中的图可以看到类似的表述。同时在下图中也展示了STM32F4xx中统一编址下各内存的地址分配注意一点即使相应的内存被映射到了0x00000000起始的地址通过其原来地址依然是可以访问的。 1.2 内存空间解释
上电序列或系统复位后ARM处理器先从0x0000 0000地址获取栈顶值再从0x0000 0004地址获得引导代码的基地址然后从引导代码的基地址开始执行程序。所选引导源对应的存储空间会被映射到引导存储空间即从0x0000 0000开始的地址空间。如果片上SRAM开始于0x2000 0000的存储空间被选为引导源用户必须在应用程序初始化代码中通过修改NVIC异常向量表和偏移地址将向量表重置到SRAM中。当主FLASH存储器被选择作为引导源从0x0800 0000开始的存储空间会被映射到引导存储空间。由于主FLASH存储器的Bank0或Bank1均可映射到地址0x0800 0000通过配置SYSCFG_CFG0寄存器的FMC_SWP控制位所以微控制器可以使用该方法从Bank0或Bank1中启动。为了使能引导块功能选项字节中的BB控制位需要被置位。当该控制位被置位并且主FLASH存储器被选择作为引导源微控制器从引导装载程序中启动并且引导装载程序跳至主FLASH存储器的Bank1中执行代码。在应用程序初始化代码中用户必须通过修改NVIC异常向量表和偏移地址将向量表重置到Bank1基地址。
1.3 启动后bootloader做了什么 根据BOOT引脚确定了启动方式后处理器进行的第二大步就是开始从0x00000000地址处开始执行代码而该处存放的代码正是bootloader即.s启动文件名为startup_xxxx.s在.s启动文件中指明了向量表默认在0x08000000处栈顶是一个栈顶指针之后就是Reset_handler复位中断入口向量地址等等中断服务函数向量地址每个地址4字节所以是从MSP偏移0x00004字节处取出Reset_Handler。bootloader也可以叫启动文件每一种微控制器(处理器)都必须有启动文件启动文件的作用便是负责执行微控制器从“复位”到“开始执行main函数”中间这段时间(称为启动过程)所必须进行的工作。
1.3 bootloader中对内存的搬移和初始化
本节针对程序在内置Flash中启动的情况进行分析。
我们知道烧录的镜像文件中包含只读代码段.text已初始化数据段.data和未初始化的或者初始化为0的数据段.bss。代码段由于是只读的所以是可以一直放在Flash中CPU通过总线去读取代码执行就OK但是.data段和.bss段由于会涉及读写为了更高的读写效率是要一定搬到RAM中执行的因此bootloader会执行很重要的一步就是会在RAM中初始化.data和.bss段搬移或清空相应内存区域。因此我们知道当启动方式选择的是从内置Flash启动的时候代码依旧是在Flash中执行而数据则会被拷贝到内部SRAM中该过程是由bootloader完成的。bootloader在完成这些流程之后就会将代码交给main函数开始执行用户代码。
1.4 ISP、IAP、ICP三种烧录方式 虽然这个小节稍稍偏题但是由于上面在3中启动方式中介绍过了ISP烧录因此一并在此介绍剩下的两种烧录方式。 ICP(In Circuit Programing)。在电路编程可通过CPU的Debug Access Port 烧录代码比如ARM Cortex的Debug Interface主要是SWD(Serial Wire Debug)或JTAG(Joint Test Action Group)ISP(In System Programing)。在系统编程可借助MCU厂商预置的Bootloader 实现通过板载UART或USB接口烧录代码。IAP(In Applicating Programing)。在应用编程由开发者实现Bootloader功能比如STM32存储映射Code分区中的Flash本是存储用户应用程序的区间上电从此处执行用户代码开发者可以将自己实现的Bootloader存放到Flash区间MCU上电启动先执行用户的Bootloader代码该代码可为用户应用程序的下载、校验、增量/补丁更新、升级、恢复等提供支持如果用户代码提供了网络访问功能IAP 还能通过无线网络下载更新代码实现OTA空中升级功能。 IAP和ISP 的区别。 a、ISP程序一般是芯片厂家提供的。IAP一般是用户自己编写的 b、ISP一般支持的烧录方式有限只有串口等。IAP就比较灵活可以灵活的使用各种通信协议烧录 c、isp一般需要芯片进行一些硬件上的操作才行IAP全部工作由程序完成不需要去现场 d、isp一般只需要按格式将升级文件通过串口发送就可以。IAP的话控制相对麻烦如果是OTA的话还需要编写后台的。 e、注意这里介绍的bootloader功能显然跟之前介绍的启动文件bootloader有所区别其目的是为了能接受外部镜像进行烧录而不是为了运行普通用户程序。
2.启动文件startup_xxx.s非GCC环境
2.1 主要功能
在此我使用stm32f103-keil环境的启动文件startup_stm32f103xb.s为例进行简单的表述。startup_stm32f103xb.s是上电后执行的第一段代码 可看到该程序执行内容是
1.初始化堆栈指针 SP_initial_sp
2.初始化 PC 指针Reset_Handler;并实现了复位的异常处理函数Reset_Handler
3.初始化中断向量表
4.配置系统时钟
5.调用 C 库函数_main 初始化用户堆栈然后进入 main 函数。2.2启动文件内容分析
0. 启动文件涉及的几个汇编命令
1. Stack栈 * 栈的作用是用于局部变量函数调用函数形参等的开销栈的大小不能超过内部SRAM 的大小。当程序较大时需要修改栈的大小不然可能会出现的HardFault的错误。
第32行表示开辟栈的大小为 0X4001KBEQU是伪指令相当于C 中的 define。
第34行开辟一段可读可写数据空间ARER 伪指令表示下面将开始定义一个代码段或者数据段。此处是定义数据段。ARER 后面的关键字表示这个段的属性。段名为STACK可以任意命名NOINIT 表示不初始化READWRITE 表示可读可写ALIGN3表示按照 8 字节对齐。
第35行SPACE 用于分配大小等于 Stack_Size连续内存空间单位为字节。
第37行 __initial_sp表示栈顶地址。栈是由高向低生长的。2. Heap堆
堆主要用来动态内存的分配像malloc()函数申请的内存就在堆中。 开辟堆的大小为 0X200512 字节名字为 HEAPNOINIT 即不初始化可读可写8字节对齐。__heap_base 表示对的起始地址__heap_limit 表示堆的结束地址。PRESERVE8用于指定当前文件的堆栈按照8字节对齐THUMB表示后面的指令兼容THUMB指令现在Cortex-M系列的都使用THUMB-2指令集THUMB-2是32位的兼容16位和32位的指令是thumb的超集。 3. 向量表 * Cortex-M3 内核规定起始地址必须存放栈顶指针而第二个地址则必须存放复位中断入口向量地址这样在 Cortex-M3 内核复位后会自动从起始地址的下一个 32 位空间取出复位中断入口向量跳转执行复位中断服务程序。Cortex-M3 内核固定了中断向量表的位置, 但是起始地址是可变化的,__initial_sp就是栈顶指针。 * 向量表是一个WORD 32 数组每个下标对应一种异常该下标元素的值则是该 ESR 的入口地址。向量表在地址空间中的位置是可以设置的通过 NVIC 中的一个重定位寄存器来指出向量表的地址。在复位后该寄存器的值为 0。因此在地址 0 即 FLASH 地址 0处必须包含一张向量表用于初始时的异常分配。 * 值得注意的是这里有个另类 0 号类型并不是什么入口地址而是给出了复位后 MSP 的初值后面会具体讲解。
第55行定义一块代码段段名字是RESETREADONLY 表示只读。
第56-58行使用EXPORT将3个标识符申明为可被外部引用声明 __Vectors、__Vectors_End 和__Vectors_Size 具有全局属性。
第60行__Vectors 表示向量表起始地址DCD 表示分配 1 个 4 字节的空间。每行 DCD 都会生成一个 4 字节的二进制代码中断向量表 存放的实际上是中断服务程序的入口地址。当异常也即是中断事件发生时CPU 的中断系统会将相应的入口地址赋值给 PC 程序计数器之后就开始执行中断服务程序。在60行之后依次定义了中断服务程序的入口地址。
第121行__Vectors_End 为向量表结束地址。
第123行__Vectors_Size则是向量表的大小向量表的大小是通过__Vectors 和__Vectors_End 相减得到的。
4. 复位程序Reset_Handler * 复位程序是系统上电后执行的第一个程序复位程序也是中断程序只是这个程序比较特殊因此单独提出来讲解。
第128行定义了一个服务程序PROC表示程序的开始。
第129行使用EXPORT将Reset_Handler申明为可被外部引用后面WEAK表示弱定义如果外部文件定义了该标号则首先引用该标号如果外部文件没有声明也不会出错。这里表示复位程序可以由用户在其他文件重新实现这种写法在HAL库中是很常见的。
第130-131行表示该标号来自外部文件SystemInit()是一个库函数在system_stm32f1xx.c中定义的__main 是一个标准的 C 库函数主要作用是初始化用户堆栈这个是由编译器完成的该函数最终会调用我们自己写的main函数从而进入C世界中。
第132行这是一条汇编指令表示从存储器中加载SystemInit到一个寄存器R0的地址中。
第133行汇编指令表示跳转到寄存器R0的地址并根据寄存器的 LSE 确定处理器的状态还要把跳转前的下条指令地址保存到 LR。
第134行和132行是一个意思表示从存储器中加载__main到一个寄存器R0的地址中。
第135行和133稍微不同这里跳转到至指定寄存器的地址后不会返回。
第136行和PROC是对应的表示程序的结束。5. 中断服务程序
我们平时要使用哪个中断就需要编写相应的中断服务程序只是启动文件把这些函数留出来了但是内容都是空的真正的中断复服务程序需要我们在外部的 C 文件里面重新实现这里只是提前占了一个位置罢了。 * 这部分没啥好说的和服务程序类似的只需要注意‘B .’语句B表示跳转这里跳转到一个‘.’即表示无线循环。 6. 堆栈初始化 堆栈初始化是由一个IF条件来实现的MICROLIB的定义与否决定了堆栈的初始化方式。 这个定义是在Options-Target中设置的 需要注意的是ALIGN表示对指令或者数据存放的地址进行对齐缺省表示4字节对齐。 如果没有定义 __MICROLIB 则采用双段存储器模式即堆区和栈区是分开的如果不采用双段模式因为堆和栈增长的方向是相反的如果撞上了程序会崩溃且声明标号__user_initial_stackheap 具有全局属性让用户自己来初始化堆栈。 以上就是Startup文件全部内容
3.启动文件分析GCC环境
GCC环境下STM32 的启动出除了需要 startup_xxxx.s 文件还需要一个链接文件 .ld 文件
3.1 .ld 链接文件
先从STM32L051C8Tx_FLASH.ld 文件来看链接文件主要制定了入口函数堆栈大小和数据段的整体布局。
3.1.1 开辟栈空间和堆空间
指定入口地址开辟栈空间和堆空间
第53行指定入口地址为Reset_Handler复位中断
第56行最大的RAM地址
第58-59行指定堆、栈大小3.1.2 指定布局
指定各数据段的布局
第69行输出文件布局
第72-79行向量表放在最前面
第80-94行制定text段存放代码
第97-103行只读数据段第134行保存.data的地址
第137-146行指定数据段在RAM中只是刚开始保存在FLASH中启动的时候拷贝到RAM
第150-162行指定.bss段
第165-173行最后根据前面定义的堆栈大小指定堆栈段3.2 .s启动文件
3.2.1 基本说明
startup_stm32l051xx.s开头部分是基本说明
第29行CPU类型
第44行thumb指令集
第38-46行_sidata保存.data地址的变量_sdata保存.data段的起始地址 _edata保存.data段的结束地址 _sbss保存.bss起始地址 _ebss保存.bss结束这几个都在链接文件中定义3.2.2 Reset_Handler
Reset_Handler 是程序最开始执行的地方设置栈顶指针
第58-60行.section设置新的代码段.weak申明.type将Reset_Handler指定为函数
第64行系统初始化时钟
第67-70行将.data段从flash放到RAM中去3.2.3 跳转到SystemInit 和 main
回过头来看一下前面讲到的启动文件所做的工作
设置堆栈指针 SP _initial_sp
设置PC指针 Reset_Handler
配置系统时钟
配置外部 SRAM 用于程序变量等数据存储可选
调用C库的 _main 函数最终调用main函数最终这里也是跳转到了main函数 3.2.4 中断向量表部分
_estack是栈顶的值这个值保存在flash的0地址出flash的地址为0x08000000,所以0x08000000保存_estack的值接下来就是Reset_Handler和编译器环境中的启动文件部分一样
参考
https://blog.csdn.net/Setul/article/details/121685929https://jiayu.blog.csdn.net/article/details/135032170?fromshareblogdetailsharetypeblogdetailsharerId135032170sharereferPCsharesourcetao_scsharefromfrom_linkhttps://blog.csdn.net/zhuimeng_ruili/article/details/119709888https://blog.csdn.net/weixin_42328389/article/details/120656722?fromshareblogdetailsharetypeblogdetailsharerId120656722sharereferPCsharesourcetao_scsharefromfrom_link