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 8.32.1.

サンプルプロジェクトには、アセンブラで記述された低レベルのコードが含まれています。また、 Cもカバーするために、このテキストの例はCで書かれています。

.icfファイルを編集して、RAMへのコピーを有効化

  • プロジェクトが使用する.icfファイルのコピーを作成してください。
  • Project>Options>Linker>Config を選択して、作成したコピーをデフォルトファイルの代わりに指定してください。

「RAMからのすべてのコードの実行」で説明されている変更を行います。

initialize by copy { readonly, readwrite };

.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 };

まとめ

このテクニカルノートの提案は、ROMに配置され、ROMから実行されるコードの量を最小限に抑えます。

全ての製品名は、それぞれの所有者の商標または登録商標です

申し訳ございませんが、弊社サイトではInternet Explorerをサポートしていません。サイトをより快適にご利用いただくために、Chrome、Edge、Firefoxなどの最新ブラウザをお使いいただきますようお願いいたします。