Keil社のMDKで非ゼロ初期化変数を設定する方法 - Keil社のMDKコンパイラの研究ノート(6)

一般的に、我々は一般的に次の変更フラッシュ変数は、ブート構成で読み取りまたはあなたが最後の最後の最後のデータ値が、Keil社の事実を読み取ることができ、に別の方法があるように、最後に保存したデータの一部を保存するためにフラッシュを使用しますデータ、分解下記をご覧保存します。

いくつかの産業の急速な回復のためのオンサイトの製品、システムをリセット(非リセット)の場合、リセットはRAMで保持ライブデータの前に必要になることがあり、あるいはませんが、瞬時にフィールドデバイスをリセットして再起動します。そして、Keil社のMDKのデフォルト、非リセットのいずれかの形式は、RAMデータの可変領域がクリアされて初期化されます。どのようにこの資料に記載される変数はゼロに初期化されていない未初期化データを、設定します。

       、コードとデータの保存ルールを見て道を与える前に、なぜプロパティ、およびリセットRAM初期化されていない変数は、それをゼロに初期化された後にデフォルト。

       どのようなデータ変数初期化され、何が非初期化されたデータ変数のですか?(私の言葉は必ずしも正確ではない記述するので、彼らはテキストの理解を助けるためにいくつかの例を与える傾向があります。)

       変数の定義:INT nTimerCount = 20; nTimerCount変数は初期値を有し、すなわち、変数初期化されます。

       あなたは、変数を定義した場合:int型nTimerCountを、変数nTimerCountはそれをZI入力セクションを配置する非可変割り当て、Keil社のMDKのデフォルトプロパティです。

       だから、「入力部は、」何を意味するかで、「ZI」は何ですか?このARMイメージファイル(イメージ)の、この部分の構成ビット退屈を見て、私はそれが把握することは非常に必要だと思います。

ARMのイメージファイルの構成は次のとおりです。

なる(また、「領域」として翻訳領域)、1つ以上のドメインによって画像ファイル
各ドメインは(また、「セクション」として翻訳セクション)は、1つ以上の出力部備える
各出力セクションの1つのまたは複数の入力を含みますセグメントの
各入力部は、オブジェクト・ファイル内のコードおよびデータを含む
       入力部におけるコンテンツの4種類含まれていますデータが初期化されたコードを、記憶領域は、記憶領域の内容をゼロに初期化され、初期化されていません。読み取り専用(RO)、読み書き(RW)及びゼロ(ZI)に初期化される。各セグメントは、対応する入力属性を有しています。

       同じ入力段RO、RW、およびZI特性を有する列の数を含む出力部とを備えます。同じ入力セグメント出力セクション属性プロパティがその中に含まれます。

       ドメインは、1〜3個の出力部から含まれ、各出力セクション特性が変化:RO特性、RW特性および性質をZI

       ここでは、通常の状況下で、コードが配置され、RO属性入力部を知ることができ、初期化されている変数は、RWプロパティ入力領域に割り当てされ、変数がゼロに初期化されるように、「ZI」属性入力部を理解することができますコレクション。

       変数の初期値は、ハードウェアがどこに配置され、初期化されていますか?(このような定義int型nTimerCount = 20;その後、20の初期値はどこに置かれている?)、私はこれは、コンパイルが完了した後、次のように、それは、情報コンパイル済みのファイルサイズを与えるなどKeil社など興味深い質問、だと思います。

合計ROサイズ(コード+ ROデータ)54520(53.24kB)
総RWサイズ(RWデータ+ ZIデータ)6088(5.95kB)
トータルROMサイズ(コード+ ROデータ+ RWデータ)54696(53.41kB)

       多くの人々は、この計算方法がわからない、でもROM /フラッシュコード番号に知りません。実際には、初期化されているこれらの変数は、プロパティには、RW入力セクションを配置し、これらの変数の初期値は、でROM /フラッシュに配置されています。初期値よりも時には、これらの大きな、Keil社は、ストレージスペースを節約するためにこれらの初期値を圧縮して、ROM / Flashになります。RAMにそれらを復元する際に、それらの初期値にしている人いますか?RAMがあり、それがゼロに初期化されるときにZI属性変数入力部?これらの事を理解するために、我々は、デフォルトの設定を見て、あなたが書いたCコードのmain関数を実行するために、システムをリセットする必要があり、Keil社はあなたを助けるために行わ。

       ハードウェアリセット後、最初のステップは、リセット処理プログラム、スタートコード(デフォルト)、皮質-M3抜粋リセットプロセス・エントリ・コードでプログラムエントリを実行することです。

Reset_Handler PROC; PROC機能と同等であるが、関数の開始、及びENDPを相対的に表しますか? 

	EXPORT Reset_Handler [WEAK] 
	IMPORT SystemInit 
	IMPORTの__main 
	LDR R0、= SystemInit 
	BLX R0 
	LDR R0、= __メイン 
	BX R0 
	 ENDP 

(SystemInit機能)基本となる初期化コードを実行した後、スタックポインタを初期化した後、ユーザ定義、Cライブラリ関数__main機能が完了し、一連の呼び出し機能、__main次コード呼び出しが解凍、コードとデータをコピーしますおよびZIデータの初期化はゼロ。レプリケーションの初期値を含むデータの圧縮と複製のためのソリューションは、外出先に対応したROM /フラッシュRAMに格納された変数を初期化します。変数の場合、それはRWプロパティエリアを配置されます初期化されたRO属性変数を配置することが最も可能性の高い可変領域を変更修飾子constの持つ3つの属性を持っていること、そして残りの変数は、ZI属性ゾーンを配置します。デフォルトでは、ゼロは全て初期化データZI ZIデータ領域がゼロで初期化され、各リセット後にCコードの主な機能の前に実行されるプログラムは、コンパイラによって、「前方」が終了。我々はリセット後にゼロに初期化されずにCのコード内のいくつかの変数を設定する必要がありますので、それは我々がいくつかのルール、制約、どのようなコンパイラを使用し、「不正な動作」にコンパイラを許してはなりません。

       散布は、ZIデータセクションエリアのゼロ初期化__main避け、実行部を修正するためにUNINITを使用して、スキャッタファイルでは、コネクタへの重要なファイル。これは、変数の非ゼロの初期化を解決するための鍵です。したがって、我々はUNINIT変更されたデータセクションを定義することができ、そして、この領域への変数の非ゼロ初期化することを望みます。したがって、最初の方法があります。

MYRAM命名1.変更スキャッタファイルは、UNINITによって修飾実行部と、実行部開始アドレス0x1000A000、長0x2000でバイト(8キロバイト)を、増加させます。

LR_IROM10x000000000x00080000 {; loadregionsize_region
	ER_IROM10x000000000x00080000 {; loadaddress = executionaddress
		* .oの(RESET、+ファースト)
		*(InRoot $$セクション)
		.ANY(+ RO)
	}
	RW_IRAM10x100000000x0000A000 {; RWdata
		.ANY(+ RW + ZI)
	}
	MYRAM0x1000A000UNINIT0x00002000 {
	.ANY(NO_INIT)
	}
}

那么,如果在程序中有一个数组,你不想让它复位后零初始化,就可以这样来定义变量:

unsigned char plc_eu_backup[PLC_EU_BACKUP_BUF/8] __attribute__((at(0x1000A000)));

       变量属性修饰符__attribute__((at(adder)))用来将变量强制定位到adder所在地址处。由于地址0x1000A000开始的8KB区域ZI变量不会被零初始化,所以处在这一区域的数组plc_eu_backup也就不会被零初始化了。

       这种方法的缺点是显而易见的:要自己分配变量的地址,如果非零初始化数据比较多,这将是件难以想象的大工程(以后的维护、增加、修改代码等等)。所以要找到一种办法,让编译器去自动分配这一区域的变量。

2. 分散加载文家同方法1,如果还是定义一个数组,可以用下面方法:

unsigned char plc_eu_backup[PLC_EU_BACKUP_BUF/8] __attribute__((section("NO_INIT"),zero_init));

       变量属性修饰符__attribute__((section(“name”),zero_init))用于将变量强制定义到name属性数据节中,zero_init表示将未初始化的变量放到ZI数据节中。因为“NO_INIT”这显性命名的自定义节,具有UNINIT属性。

3. 如何将一个模块内的非初始化变量都非零初始化?

假如该模块名字为test.c,修改分散加载文件如下所示:

LR_IROM10x000000000x00080000{	;loadregionsize_region
	ER_IROM10x000000000x00080000{	;loadaddress=executionaddress
	*.o(RESET,+First)
	*(InRoot$$Sections)
	.ANY(+RO)
	}
	RW_IRAM10x100000000x0000A000{	;RWdata
	.ANY(+RW+ZI)
	}
	RW_IRAM20x1000A000UNINIT0x00002000{
	test.o(+ZI)
	}
}

定义时使用如下方法:

int uTimerCount __attribute__((zero_init));
       这里,变量属性修饰符__attribute__((zero_init))用于将未初始化的变量放到ZI数据节中变量,其实keil默认情况下,未初始化的变量就是放在ZI数据区的。

4.将整个程序的非初始化变量都非零初始化 看了上面的,这个已经没有必要说了。

原文链接:https://blog.csdn.net/zhzht19861011/article/details/8780837

おすすめ

転載: www.cnblogs.com/CodeWorkerLiMing/p/12120777.html