連載
» 2006年12月19日 00時00分 公開

H8で学ぶマイコン開発入門(4):OSが起動する以前のスタートアップルーチン (3/4)

[山本 繁寿 ソフィアシステムズ,@IT MONOist]

3.ROM領域からRAM領域へ初期値データの転送

 組み込み用コンパイラは、次のデータがROM領域に配置されるようコード生成を行います。

  • 初期値を持つ外部変数およびstatic変数
  • 定数:const

 これら初期値を持つ変数や定数データはROM領域に配置されるため、プログラムから書き換えることができません。プログラム実行中に、これらを書き換える必要がある場合は、スタートアップルーチンで、ROM領域のデータをRAM領域へ転送しておきます(図4)。

ROM領域のデータをRAM領域へ転送 図4 ROM領域のデータをRAM領域へ転送

 リスト2は、そのプログラミング例です。

#define ROMstartAddr  ((unsigned char *)0x00400000)
#define ROMendAddr    ((unsigned char *)0x004000FF)
#define RAMstartAddr  ((unsigned char *)0x00410000)
void ROMtoRAM(void)
{
  unsigned char *rom, *ram;
    for(rom=ROMstartAddr,ram=RAMstartAddr;
        rom<=ROMendAddr;
        rom++, ram++)
  *ram=*rom;
}
リスト2 ROM領域のデータをRAM領域へ転送

 しかし、ROM領域からRAM領域へ初期値データを転送するプログラムは、その分だけメモリが余分に必要となります。このため、特別な理由がない限り、このようなプログラミングスタイルは取らないようにするべきだと筆者は考えます。

4.初期値を持たないデータのクリア(初期化)

 プログラムで初期化されていない外部変数は、システムに電源を入れた直後やリセット後には、不定な値を持っています。スタートアップルーチンでは、これを特定の値でクリア(初期化)します(図5)。

リセット直後の外部変数の値は不定 図5 リセット直後の外部変数の値は不定

 リスト3は、424000H番地から42400FH番地までを0クリアするプログラムです。

#define startAddr  ((unsigned char *)0x00424000)
#define endAddr    ((unsigned char *)0x0042400F)
void init_clr(void)
{
  unsigned char *p;
  for(p=startAddr; p<=endAddr; p++)
    *p=0x0;
}  
リスト3 初期値を持たないデータの0クリア

初期値を持たないデータの0クリア 図6 初期値を持たないデータの0クリア

5.ハードウェアおよびCPU内蔵レジスタの初期化、割り込み許可

 組み込みシステムではI/Oポートにさまざまな周辺機器が接続されています。また、H8マイコンに限らず多くのマイコンには、割り込みコントローラやタイマなど、CPU内蔵レジスタが存在しています。スタートアップルーチンでは、これらの周辺機器や内蔵レジスタが動作可能になるように初期化を行います。特にマルチプレクスされた端子は、その端子が信号線として使われるのかI/Oポートとして使われるのか、I/Oポートとして使われる場合は、それが入力か出力かをスタートアップルーチンで設定します。

 本連載で使っているH8/3048Fマイコンには、10本の入出力ポート(ポート1、2、3、4、5、6、8、9、A、B)と1本の入力専用ポート(ポート7)があり、各ポートは兼用端子となっています。各ポートは、入出力を制御するデータディレクションレジスタ(DDR)と出力データを格納するデータレジスタ(DR)から構成されています。リスト4は、マルチプレクスされたポート0を汎用I/Oポートとして設定し、さらに出力ポートに設定するためのプログラムです。

void initPort(void)
{
  *P0MD=0x01;   // ポート0を汎用I/Oポートに設定:
                // ポートモードレジスタ(P0MD:0)
  *P0DIR=0xff;  // ポート0を出力ポートに設定:
                // ポート入出力制御レジスタ(P0DIR:0-7)
}
リスト4 ポート0を汎用I/Oポート、出力ポートに設定

ポートモードレジスタとポート入出力制御レジスタの仕様 図7 ポートモードレジスタとポート入出力制御レジスタの仕様

6.アプリケーションプログラムの呼び出し

 スタックの設定や各種初期化が終了したら、最初に実行されるアプリケーションプログラムをスタートアップルーチンから呼び出します。

 WindowsやLinuxなどが搭載されたパソコンで動作するプログラム(ネイティブ環境)の場合、プログラムの最初の関数名は、int型のmainに限定されています。なぜint型のmainが最初の関数かというと、通常ネイティブ環境のスタートアップルーチンで最初に呼び出す関数がmainとなっているためです。これに対して組み込みシステムでは、スタートアップルーチンが呼び出す最初の関数はmainに限定されず、プログラマが自由に決めることができます。

Copyright © ITmedia, Inc. All Rights Reserved.