FlashあるいはROMからコピーしてRAM上でプログラムを実行する
テクニカル・ノート 11578
アーキテクチャ:
ARM
コンポーネント:
general
更新日:
2020/06/30 9:40
はじめに
このテクニカルノートでは、アプリケーションを可能な限りRAMから実行する方法について説明します。
ここで説明する内容は、M3以降のCortex-Mデバイスに適用されます。
「IAR Development Guide for Arm」の「RAMからすべてのコードを実行する」章で説明されている方法では、期待したようにアプリケーションがRAMに配置されない場合は、これらのガイドラインを使用してください。
解説
ユーザガイドの「すべてのコードをRAMから実行する」章の手順に従ってください
この章は、「IAR Development Guide for Arm」に記載されています。結果として、アプリケーションがRAMに意図したように配置されない場合は、以下の提案をお読みください。
RAMに最大量のコードを配置する
IARツールは、プログラムの起動時にすべてまたはほとんどのコードをRAMにコピーするのに役立ちます。
以下を実行して下さい:
- .icfファイルを編集して、RAMへのコピーを有効化。
- 低レベルのソースコードを編集して、2番目のベクターテーブルを作成し、RAMに配置。
- アプリケーションのソースコードを編集して、VTORをRAMのベクターテーブルを指すように設定。
- [オプション] RAM内のベクターテーブルのリンク時保護を追加。
これは、STM32F103RB(Cortex-M3)デバイスのプロジェクトを使用して説明されます。
STM32F103RB (Cortex-M3) example project IAR Embedded Workbench for ARM 9.20.1.
サンプルプロジェクトには、アセンブラで記述された低レベルのコードが含まれています。また、 Cもカバーするために、このテキストの例はCで書かれています。
.icfファイルを編集して、RAMへのコピーを有効化
- プロジェクトが使用する.icfファイルのコピーを作成してください。
- Project>Options>Linker>Config を選択して、作成したコピーをデフォルトファイルの代わりに指定してください。
「RAMからのすべてのコードの実行」で説明されている変更を行います。
initialize by copy { readonly, readwrite }
except {
section .intvec, /* Don’t copy interrupt table */
section .init_array }; /* Don’t copy C++ init table */
.icfファイルに次の変更を加えます。
- RAMベクターテーブルが収まるように、RAM領域の開始を調整:
define symbol __ICFEDIT_region_RAM_start__ = 0x200000EC;
- RAMベクタテーブルの開始アドレスのシンボルを追加:
define symbol __RAM_intvec_start = 0x20000000;
- RAMベクターテーブルを保持するセクションを配置:
place at address mem: __RAM_intvec_start { section .intvec_RAM };
2つ目のベクターテーブルを作成してRAMに配置
- ベクトルテーブルを保持するファイルのコピーを作成してください。
- そのファイルをプロジェクトに追加してください。
ソースファイルのコピーに次の変更を加えてください。
- コピーしたベクターテーブルの名前を次のように変更:
__vector_RAM_table
- RAMのベクタテーブルは、割り込みハンドラへの参照を保持します。 (RAMのベクターテーブルは元のベクターテーブルのコピーであるため、テーブル自体を編集する必要はありません。)
- RAMのベクターテーブルは、Cでは次のようになります。
__root const IntVector __vector_RAM_table[] =
{__ptr = __sfe( ‘CSTACK’ ) },
__iar_program_start,
NMI_Handler,
HardFault_Handler,
. . .
- RAMベクタテーブルをセクション.intvec_RAMに配置
- 次の行をRAMベクタテーブルに追加してください:
#pragma location = ".intvec_RAM"
__root const IntVector __vector_RAM_table[] =
. . .
- ROMベクタテーブルを変更する必要があります。
- __ptr = __sfe( ‘CSTACK’ )または__iar_program_startは変更しないでください。
- 他のすべてのテーブルエントリは、Empty_Handlerという名前のダミーハンドラを参照する必要があります。
- ROMベクターテーブルは次のようになります:
const IntVector __vector_table[] =
{
{__ptr = __sfe( ‘CSTACK’ ) },
__iar_program_start,
Empty_Handler,
Empty_Handler,
Empty_Handler,
Empty_Handler,
. . .
- 次のように、ダミーのEmpty_Handlerのソースコードを記述してください:
void Empty_Handler(void)
{
for(;;);
}
RAM内のベクターテーブルを指すようにVTORを設定
アプリケーションにVTORを設定するソースコードがすでに含まれている場合は、そのコードを変更してください。それ以外の場合は、アプリケーションのソースコードの非常に早い段階で(少なくとも割り込みが有効になる前に)次の変更を追加してください。
#pragma section = ".intvec_RAM"
SCB->VTOR = (uint32_t)__section_begin(".intvec_RAM");
[オプション] RAM内のベクターテーブルのリンク時保護を追加
RAMベクターテーブルがリンクされた出力イメージに含まれていることを確認するには:
- main() 関数の直前に次の2行のコードを追加してください:
extern void * __vector_RAM_table [];
#pragma required=__vector_RAM_table
void main(void)
注: このテクニカルノートのオプションではない手順の1つ以上をスキップすると、ILINKリンカーはLi005エラーを発行します。
.mapファイルを使用して変更の影響を確認
.mapファイル中の以下セクションを調べます。
- PLACEMENT SUMMARY – どのメモリオブジェクトが配置されているかを確認します
- MODULE SUMMARY – オブジェクトの配置を確認 (r-o code vs r/w code)
- ENTRY LIST – 関数のアドレスを確認します
MODULE SUMMARY は、変更の結果を示します:
オリジナルプロジェクトのMODULE SUMMARYと比較してください:
2 256 bytes of readonly code memory
0 bytes of readwrite code memory
16 bytes of readonly data memory
2 052 bytes of readwrite data memory
修正されたプロジェクトの MODULE SUMMARY:
792 bytes of readonly code memory
1 808 bytes of readwrite code memory
1 253 bytes of readonly data memory
2 054 bytes of readwrite data memory
注意!スタートアップコードのリンカ保護
リンカは、スタートアップコードから参照されるセクションを、initialize by Copyディレクティブの影響を受けないように保護します。以下も含みます:
- __low_level_init と 同じコンパイル単位 (.c ファイル)内でコールされる/定義される 全ての関数
- (静的にリンクされた) グローバル C/C++ シンボル
リンカは、コピーの初期化が完了した後に実行されるコードのみがRAMにコピーされるようにします。そのため、初期化コマンドにreadonlyを追加しても安全です:
initialize by copy { readonly, readwrite };
RAM に配置されるbootloader の例
テクニカルノート160822 は、ブートローダーの作成方法に関するガイドラインが記載されており、サンプル プロジェクトが含まれています。
このリンク からコードの大部分が RAM に配置されるように変更されたサンプル プロジェクトがダウンロードできます。
まとめ
このテクニカルノートの提案は、ROMに配置され、ROMから実行されるコードの量を最小限に抑えます。
全ての製品名は、それぞれの所有者の商標または登録商標です