将ULink下载工具的一端通过USB线连接到电脑USB口上,另一端连接到教学开发板上的JTAG口上。接好后,按图1.30(a)~(c)所示过程依次配置,安装ULink驱动。
图1.30 ULink下载工具驱动的安装
将ULink和教学开发板连接好,打开教学开发板电源开关。单击Project下的Options for Target(工程属性),弹出“Options for Target”对话框。或者单击“Flash”菜单下的“Configure Flash Tools”,按照如图1.31(a)~(f)所示进行配置。
图1.31 ULink下载配置
图1.31 ULink下载配置(续)
图1.31 ULink下载配置(续)
这样ULink下载工具就配置好了。如图1.32所示,单击 图标(或通过“Flash→Download”操作),程序就开始下载了,下载结束如图1.33所示。
图1.32 程序下载
图1.33 程序下载结束
下载时,先擦除上次Flash存储器中的程序,再将刚才编译好的程序下载,最后经校验无误后,下载结束。此时,按教学开发板的Reset复位键,下载的程序开始运行。
Flash存储器
Flash是存储芯片的一种,通过特定的程序可以修改里面的数据。Flash存储器又称闪存,它结合了ROM和RAM的长处,不仅具备电子可擦除可编程(EEPROM)的性能,还不会断电丢失数据,同时可以快速读取数据(NVRAM的优势)。U盘和MP3里用的就是这种存储器。嵌入式系统以前一直使用ROM(EPROM)作为它们的存储设备,20世纪90年代中期开始,Flash全面代替了ROM(EPROM)在嵌入式系统中的地位,用做存储程序代码或者Bootloader及操作系统,现在则直接当U盘使用。
目前Flash主要有两种:NOR Flash和NAND Flash。NOR Flash的读取和我们常见的SDRAM的读取是一样的,用户可以直接运行装载在NOR Flash里面的代码,这样可以减少SRAM的容量,从而节约了成本。NAND Flash没有采取内存的随机读取技术,它的读取是以一次读取一块的形式来进行的,通常是一次读取512字节,采用这种技术的Flash比较廉价。用户不能直接运行NAND Flash上的代码,因此使用NAND Flash的嵌入式系统开发板除了使用NAND Flash以外,还做上了一块小的NOR Flash来运行启动代码。
一般小容量的用NOR Flash,因为其读取速度快,多用来存储操作系统等重要信息,而大容量的用NAND Flash,最常见的NAND Flash应用是嵌入式系统采用的DOC(Disk On Chip)和我们通常用的“闪盘”,可以在线擦除。目前市面上的Flash主要来自Intel,AMD,Fujitsu和Mxic,而生产NAND Flash的主要厂家有Samsung和Toshiba及Hynix。
SRAM存储器
SRAM是英文Static RAM的缩写,它是一种具有静止存取功能的内存,不需要刷新电路即能保存它内部存储的数据。而DRAM(Dynamic Random Access Memory)每隔一段时间,要刷新充电一次,否则内部的数据即会消失,因此SRAM具有较高的性能,访问速度快。但是SRAM也有它的缺点,即价格高、集成度较低、功耗较大,相同容量的DRAM内存可以设计为较小的体积,但是SRAM却需要很大的体积。SRAM只用来存储变量数据和提供给堆栈来使用。在嵌入式系统中,Flash的容量一般要大于SRAM的容量,如STM32F103VB芯片,其Flash容量为128K,SRAM容量为20K;STM32F103VE芯片,其Flash容量为512K,SRAM容量为64K。其他,8/16位单片机、ARM9或ARM11等嵌入式系统也是如此。
当生成的可执行文件大于Flash存储空间时,则不能被下载到Flash中。如果出现类似下面的错误,则表示生成的可执行文件大于Flash存储空间:
Error:L6406W:No space in execution regions with.ANY selector matching Section.text(***.o).
这时,可以对程序进行优化,例如,减小缓存尺寸,减少全局变量,少定义尺寸大的数组而多用指针等方法。此外,合理调整RealView MDK的编译和链接配置,也可以减小生成的可执行文件大小。比如,在链接脚本中指定代码的存储布局,将代码段、只读数据段、可读写数据段分别存放,以减小生成的可执行文件大小。常有下面3种解决方法。
(1)使用微库:在图1.31(a)所示的对话框中选中“USE MicroLib”,以使代码减少。
(2)修改链接脚本:在“Options For Target”对话框的“Linker”页面,将Use Memory Layout from Target Dialog前面的复选框勾上,如图1.34所示。然后在“Target”页面(图1.31(a)所示的对话框)中修改存储空间中只读部分(Read/Only Memory Areas)和可读写部分(Read/Write Memory Areas)的起始和大小,一般来说加大只读部分大小(该部分存放程序中的指令),而减小可读写部分的大小(该部分存放堆栈、局部变量等)。
图1.34 代码尺寸优化:配置“Linker”页面
(3)修改优化级别:在“Options For Target”对话框的“C/C++”页面,可使用编译选项“-Ospace”进行编译,将着重对空间进行优化,让编译器自动减小代码大小。另外,还可以选更高的选优化级别“Level 3(-O3)”,如图1.35所示。Level 3的优化等级最高,最适合下载到最终的产品芯片中,而Level 0为不优化,这种模式最适合调试,因为它不会优化掉代码。在学习时,使用“Level 0(-O0)”,以方便程序的调试。
图1.35 代码尺寸优化:配置C/C++页面
关于MicroLib
使用微库,将以更精简短小的C库替代标准C库,减小代码大小。MicroLib是默认C库的备选库。它主要用于内存有限的嵌入式应用程序中。这些应用程序不在操作系统中运行。
如果你发现在Keil RealView MDK中使用printf函数,不能向串口输出信息,或者今后发现可以软件仿真,不能硬件仿真,注意要在图1.31(a)中的设置对话框选中“USE MicroLib”。MicroLib提供了一个有限的stdio子系统,它仅支持未缓冲的stdin、stdout和stderr。这样,即可使用printf()来显示应用程序中的诊断消息。
要使用高级I/O函数,就必须提供自己实现的以下基本函数,以便与自己的I/O设备(如串口)配合使用。
为所有输出函数:fprintf()、printf()、fwrite()、fputs()、puts()、putc()和putchar()等需要实现fputc()函数。
为所有输入函数:fscanf()、scanf()、fread()、read()、fgets()、gets()、getc()和 getchar()等需要实现fgetc()函数。
由于MicroLib进行了高度优化,以使代码变得很小。因此,MicroLib不完全符合ISO C99库标准,仅提供有限的支持,不具备某些ISO C特性。并且其他特性具有的功能比默认C库少, MicroLib与默认C库之间的主要差异是:
(1)MicroLib不支持IEEE 754关于二进制浮点算法标准,否则会产生不可预测的输出的结果,如NaN、无穷大。
(2)MicroLib中不支持的转换为%lc、%ls和%a。
(3)MicroLib进行了高度优化,以使代码变得很小。
(4)MicroLib不支持与操作系统交互的所有函数,如abort()、exit()、atexit()、clock()、time()、system()和getenv()。不能将main()声明为带参数的,并且不能返回内容。
(5)不支持与文件指针交互的所有stdio函数,否则将返回错误。仅支持三个标准流:stdin、stdout 和 stderr。即不完全支持stdio,仅支持未缓冲的stdin、stdout 和 stderr。
(6)MicroLib不提供互斥锁来防止非线程安全的代码。
(7)MicroLib不支持宽字符或多字节字符串。如果使用这些函数,则会产生链接器错误。
(8)与stdlib不同,MicroLib不支持可选择的单或双区内存模型。MicroLib只提供双区内存模型,即单独的堆栈和堆区。
该你了!——比较一下这几种优化方法所生成的可执行文件大小