Keil¶
MDK¶
生成文件¶
Program Size: Code=100800 RO-data=14396 RW-data=1200 ZI-data=35312
Code:即代码域,它指的是编译器生成的机器指令,这些内容被存储到ROM区。
RO-data:Read Only data,即只读数据域,它指程序中用到的只读数据,这些数据被存储在ROM区,因而程序不能修改其内容。例如C语言中const关键字定义的变量就是典型的RO-data。
RW-data:Read Write data,即可读写数据域,它指初始化为"非0值"的可读写数据,程序刚运行时,这些数据具有非0的初始值,且运行的时候它们会常驻在RAM区,因而应用程序可以修改其内容。例如C语言中使用定义的全局变量,且定义时赋予"非0值"给该变量进行初始化。
ZI-data:Zero Initialie data,即0初始化数据,它指初始化为"0值"的可读写数据域,它与RW-data的区别是程序刚运行时这些数据初始值全都为0,而后续运行过程与RW-data的性质一样,它们也常驻在RAM区,因而应用程序可以更改其内容。例如C语言中使用定义的全局变量,且定义时赋予"0值"给该变量进行初始化(若定义该变量时没有赋予初始值,编译器会把它当ZI-data来对待,初始化为0);
ZI-data的栈空间(Stack)及堆空间(Heap):在C语言中,函数内部定义的局部变量属于栈空间,进入函数的时候从向栈空间申请内存给局部变量,退出时释放局部变量,归还内存空间。而使用malloc动态分配的变量属于堆空间。在程序中的栈空间和堆空间都是属于ZI-data区域的,这些空间都会被初始值化为0值。编译器给出的ZI-data占用的空间值中包含了堆栈的大小(经实际测试,若程序中完全没有使用malloc动态申请堆空间,编译器会优化,不把堆空间计算在内)。
概念区别¶
在keil里编译完后被分成5个内存段(堆、栈、bss段、data段、text段)
在stm32中flash就是ROM,掉电数据不会丢失;通常保存着text段、Code、Ro-data、Rw-data RAM就是运行内存,掉电数据就丢失;通常保存着堆、栈、bss段、data段、ZI-data、RW-data
优化等级¶
-O0 最少的优化,可以最大程度上配合产生代码调试信息,可以在任何代码行打断点,特别是死代码处。
-O1 有限的优化,去除无用的inline和无用的static函数、死代码消除等,在影响到调试信息的地方均不进行优化。在适当的代码体积和充分的调试之间平衡,代码编写阶段最常用的优化等级。
-O2 高度优化,调试信息不友好,有可能会修改代码和函数调用执行流程,自动对函数进行内联等。
-O3 最大程度优化,产生极少量的调试信息。会进行更多代码优化,例如循环展开,更激进的函数内联等。
另外,可以通过单独设置 --loop_optimization_level=option 来控制循环展开的优化等级。
警告
勾选了“use cross-module optimization//跨模块优化,KEIL每次都要编译全部文件并且每个文件编译三次
编程算法FLM¶
MDK在下载程序之前需要都在Debug设置的Flash Download子选项卡选择编程算法。大多数时候,我们只要安装了芯片包之后,就可以直接得到对应的编程算法,并不需要我们去修改它。
但是,当你是一个芯片包的开发者,或者你有独特的下载需求(比如在你的程序里加入一些校验信息),这个时候你就需要去了解它了!
编程算法主要功能就是擦除相应的内存块,并将我们的程序写入到相应的内存区域上去。在你点击下载按钮的时候,这段程序会被先下载到RAM上(RAM for Algorithm上的设置),然后才会通过它,将你的程序写入到指定的内存区域内。
格式输出¶
使用fromelf工具,通过上面的示例,想必都能很轻松的生成bin文件,今天补写一下fromelf工具的基本命令:
--bin:输出二进制文件 --i32:Intel 32位Hex --m32:Motorola 32位Hex --output <file>:file为输出文件名 -o<file>:这个是armcc编译器命令,也可用于这里,指定输出文件的名字
fromelf --bin "$L@L.axf" --output "$L@L.bin"
fromelf.exe --bin -o "$L@L.bin" "#L"
fromelf¶
romelf.exe绝对路径+空格+--bin(注意是两个短横的)+空格+--output(两短横)+空格+../输出目录相对路径+空格+名字.bin+空格+../输出目录相对路径+空格+名字.axf
fromelf.exe --bin --output .output@test2.bin .output@test2.axf
fromelf.exe --bin --output ..@test2.bin ..@test2.axf
fromelf 中$L、@L、L用来指定对应的路径或名称
L是指axf文件路径加文件名,例如 D:qitasouttest.axf
$L是指axf的文件路径不含文件名(包含最后“”),例如 D:qitasout
@L是指axf的不含axf的后缀文件名,例如 test
#L的 # 表示引用的是本身,#L即工程的输出文件
备注
$K表示的是KEIL MDK工具链的安装路径
使用技巧¶
HardFault_Handler
常见问题¶
MDK偶尔会出现错误提示“Error: Encountered an improper argument”。大概意思是说“错误:遇到不正确的参数”。 出现这种情况时,对话框关掉之后会再次出现,只能使用任务管理器强制停止才行。在官网上查一下这个错误信息,原来是Keil软件的BUG。
在某些情况下,当您退出调试会话时,可能会显示一个错误对话框,提示“遇到不正确的参数”。 如果发生这种情况,μVision需要使用Windows任务管理器终止。 在大多数情况下,亚洲使用Windows操作系统的客户在项目路径中使用亚洲字符时会受到此问题的影响。 很有可能你的工程路径中有中文(不过之前Keil是支持的),将路径变成中文就可以的了。
WARNING L2: REFERENCE MADE TO UNRESOLVED EXTERNAL
如果你在用C51编译器出现上面的警告,这个只是初学者和粗心者才会犯的错误:没把C文件添加到项目中! 另外,还有可能是因为存在没有被调用的已经定义的函数,或者相关的已经定义的变量没有使用。
WARNING L15: MULTIPLE CALL TO SEGMENT
该警告表示连接器发现有一个函数可能会被主函数和一个中断服务程序(或者调用中断服务程序的函数)同时调用,或者同时被多个中断服务程序调用。
出现这种警告的原因一般有两种:
第一,这个函数是不可重入函数,当该函数运行时可能被打断,打断后该函数又被再次运行,从而造成函数内部数据丢失;
第二,该函数的内部变量数据所占有的内存在link时被连接器认为是可覆盖的,因此在连接时进行了数据覆盖优化,但是连接器同时发现该函数在运行时被打断后,其他函数(如中断服务子程序)的运行造成了该函数的数据被覆盖。
WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
定义的函数没有调用而已