|
本帖最后由 酱哒哒 于 2017-2-25 00:05 编辑 声明:以下内容乃本人自我理解及部分学习资料综合而得,可能存在错误!敬请谅解,欢迎订正! BY Kismet ![]() 1.序言 首先,看了我写的这些东西,很可能对于各位嵌入式方面的项目开发,并没有太大的实质性作用。 但,我还是想要写出来,给新手大大们(包括自己这个菜鸟),看一看。 因为,我个人觉得,这些东西对于理解嵌入式开发,有着至关重要的作用。虽然,这些东西,可能对于你的项目开发,例如我要做一个CAN通信、USB通信等等,用处不是很大。但是,在我看来,项目开发实施,主要就是在讲 how to do,我想要告诉新手大大(包括自己这个菜鸟)why to do。 希望各位记住一点:软件不是魔法,程序开发是脱离不了物理介质的。任何程序运行,必然有对应的物理过程。如果你一直觉得,程序很神奇,很魔幻,那你完了。 ![]() 就如同,上一章我简单提到的各种变量的存储占用,其实就是想要说一个事实:程序脱离不了物理介质! 好了,又到了喜闻乐见的举例子时间: 利用for循环清零一个a[1024][1024]二维数组
结果:程序A消耗的时间比B消耗的时间短很多!! 分析:数组申请的空间,是沿着物理地址走的,CPU访问的时候,有远有近,程序A是按照顺序访问的,反观程序B,它每次跳着访问,存在走的路程有重复,所以消耗的时间自然就长!!(如果理解不了,你就画一个二维数组,按着程序清零的方式,试一下,我相信你们能理解的,嘿嘿) ![]() 2.STM32的startup 现在基本上大部分的嵌入式开发,都使用的C语言编程,所以启动过程以C语言为例。 而C语言有一个典型的特征,就是有且只有一个main函数! 那么,你有没有想过单片机上电后,如何寻找main函数入口呢? 不同开发者的程序,结构不同,变量函数等都不同,而C语言开发,变量/函数等地址是由编译器自行分配的,所以从硬件上来说main函数入口的地址不是一成不变的。这就导致,微控制器不能从硬件上直接锁定main的入口。 所以,就需要一个“启动文件”起到中转衔接的作用,负责“复位”到“main函数”这之间的工作。(当然,这个文件并不止起这点作用。) 这一步,ST已经替我们做了。(无论是MDK还是IAR等编译器,都必定有一个写好的启动文件,一般是汇编的形式。另外,如果你把编译器调试中runto main这个选项去掉,那么单步运行就能看到那个运行过程。) 用官方一点的语言表述,启动代码(startupcode)的作用就是,在应用进入main函数(callthe main function)之前,初始化整个系统,包括硬件和软件。 当然,在这儿我不会讲IDE工具中的启动文件的具体内容,这些东西,网上已经有很多讲解了,随便找一个读读,基本上都能理解的。 ![]() 3.嵌入式应用 作为嵌入式应用开发人员,自然关注的是嵌入式应用(EmbededApplication)本身的开发,一个嵌入式应用从生到灭,可以简单地分为三个大阶段。(当然,大部分的嵌入式应用都是无限循环,也就不存在灭)
本次,主要谈的就是这个初始化阶段(Initializationphase)。 另外,为啥要用英文?因为可以加强英语学习啊,嘿嘿。 Ⅰ. 初始化阶段 Initializationphase 初始化阶段就是系统复位到进入main函数之前,初始化阶段又可以简单地分为一下三部分: Ø硬件初始化:典型的就是系统启动文件中(XXXstartup.s)那样,当然也可以额外加入一些其他的。初始化一些硬件,例如CPU设置、复位一些硬件等。这部分就是为了软件C语言部分的初始化做准备。 Ø软件C/C++的初始化:进入main函数之前,正确初始化每一个全局或者静态链接的C/C++变量。 Ø应用的初始化:这部分自然就主要是开发者操作了,例如初始化RTOS、中断、外设等。 对于一个典型的ROM/Flash-based的系统,常量和函数总是放置在ROM中。RAM中所有的symbols在进入main函数之前,都将被初始化!然后,链接器(Linker)会把RAM划分好区域,供给变量、堆、栈使用。\ 以典型的IAR集成开发工具为例,初始化过程主要就分为以下四步: ①.应用开始,系统级启动代码(xxxstartup.s)执行硬件初始化,堆栈指针指向堆栈底部(预先设置的)。【这儿重点注意】 ②.ZI-data被初始化为0 ③.从ROM中将RW-data拷贝到RAM对应区域 ④.main函数启动 如下图所示
fig1.基于IAR的ROM+RAM初始化流程 注意: (1)①中,堆栈指针指向堆栈底部,这个只适用于IAR(前文提到过,IAR与GCC不同,它先分配stack和heap。MDK具体怎么的,我不清楚!) (2)ZI-data,在前文中我解释是,未初始化的变量(还包括初始化为0的变量,未初始化,编译器直接给0) (3)RW-data为何与ZI-data不同,还要占用Flash空间(ROM空间)?因为ZI-data是直接给0,而RW-data是含有具体数据的,所以编译器不可能无中生有,它不得不从Flash中拷贝到RAM中。并且,这也决定了,ZI-data在RAM中位于RW-data之上(先入)。 Ⅱ. 执行阶段 嵌入式应用常常都是一个无限循环,通常采用中断或者轮询的方式实现外部交互或者内部事件。利用中断方式的应用,在main函数开始的时候,就该完成中断的初始化。 假如应用对实时性的要求比较苛刻,并且还要求多任务机制,那么可以考虑引入RTOS。但是这也意味着,你必须在main函数开始的时候,完成各个任务的初始化。 Ⅲ.终止阶段 大部分嵌入式应用,都没有结束!也就不存在终止的操作,但是如果需要终止,那么就必须准备好一个合适的结束动作。 要以可控的方式终止程序,要么调用标准C语言函数exit,_Exit,abort,或者直接从main函数中return。如果使用return,exit函数就会执行,那么,所有的文件都会关闭。 当然,如果系统逻辑存在问题,那么应用也可能终止——也就是跑飞了。 ![]() 4.总结 一个完整的程序,由生到灭,就如同下图所示。
fig2.一个完整的程序(由生到灭) PDF下载
STM32进阶探究之应用启动(一).pdf
(214.66 KB, 下载次数: 20)
|
| 赞的,新手对于启动是重点 |
分享学习的内容,给楼主点个赞 |
STM32
超强工具——STM32CubeMX 你会用吗?
集结出发! STM32全国研讨会系列之一:ST智能门铃中国首秀
关于STM32启动文件的几个小问题
【银杏科技ARM+FPGA双核心应用】STM32H7系列35——USB_VCP_FS
【银杏科技ARM+FPGA双核心应用】STM32H7系列28——USB_HID
粉丝分享 | 图说CRC原理应用及STM32硬件CRC外设
STM32L151进入低功耗,并由RTC唤醒的故事
[转]stm32控制NFC模块(PN532)源码(P2P,模拟卡,读写卡等
STM32G070RB+LVGL移植
微信公众号
手机版