noinit段对我们大多数搞单片机开发者来说并不陌生,该段如果被使用的话是会被编译器自动分配到芯片SRAM的一块区域中(注意是RAM区而非Flash),在该段定义的变量在除了掉电之外的任何芯片复位的情况下都不会被重新初始化,所以这个段的意义就大了,常用来保存一些敏感信息,特殊应用场合下的不能被复位的数据或者做复位判断标志等数据,个人感觉这个数据段的用途还是非常广的,且很好用。
那下面我们就以飞思卡尔Kinetis系列的KL26在IAR环境下为例,简单介绍一下noinit段的使用方法,方法还是非常简单的,如下图,定义noinit段的变量有两种形式,一种是直接在变量类型前面加上"__no_init”关键字,另一种是使用预编译指令#pragma这种IAR下常用的指定段的方式,俺还是prefer第一种方式的,简单明了。
实际上讲到这里已经算是结束了毕竟noinit段的使用方法还是比较简单的。但我并不想这么早就收尾了,还想介绍一下noinit使用的另一种情况(俺还没完了,呵呵),那就是正常情况下noinit段所在的SRAM区地址范围是被编译器自动分配的,但是如果我是强迫症的话(咳咳,俺不是啊,是假设啊,呵呵)或者用户有需要就是想把noinit中的变量指定到固定的地址中去(有些应用是需要的,比如带Bootloader的应用,因为Bootloader代码和用户代码是两个独立的工程且分开编译的,那Bootloader里面是没有这个变量的,所以需要告诉Bootloader用户代码中在noinit段定义的变量所在的具体地址,然后Bootloader直接去该地址读取),这就需要我们“耍些手段”去强制编译器把该noinit的变量分配到我们制定的地址去。当然实现这个功能,IAR下有几种方法,我这里只给出一种比较可靠的方法,即修改链接文件,在IAR的链接文件中给noinit区分配好指定的空间大小和地址范围,这样就可以根据外部变量的大小去来决定在链接文件中分给noinit区的空间大小和地址范围,具体方法如下:
1. 打开IAR下用户工程的链接文件(这里我以KL26 128kB flash的链接文件为例),如下图中所示在给RAM分配起始空间时可以预留出0x30即48个字节(下面应用中我定义了12个整型变量,需要48个字节);
2. 为noinit区指定一个固定的区(如果不指定的话是由编译器自动分配的),我这里给noinit区分配的地址范围设定为(RAMstart-0x30)到RAMstart(这样不会与其他数据冲突),占用0x30个字节,同时noinit区的首地址也确定下来了,即RAMstart-0x30;
3. 这一步就是把.noinit段范围分配到上面定义的noinit_region区,实际上就是告诉编译器以后被定义成__no_init的变量需要强制放到noinit_region区;
4. 然后在c文件中直接定义一个temp数组并声明成__no_init段,12个元素,共占用48个字节,如果你定义13个元素52个字节,编译器会出错提示超出范围了,所以如果我们需要更改变量的大小记得链接文件也要修改;
5. 最后编译整个工程,打开生成的.map文件,可以看到如下图示,即temp变量为固定分配到0x1ffff410地址,大小为0x30个字节,怎么样,很酷吧,呵呵。
到这里才可以说算是结束了,不知道盆友们认真看下来是否有所收获,有,这篇文章就到这了,未完待续~