AKI-H8/3048fプログラミング
Renesas HEW 4.07 利用版
High-performance Embedded Workshop

Copyright(C)23Sep2011 coskx

1.はじめに

この文書は,Windows7パソコンにAKI-H8/3048fのC言語クロスコンパイル環境での,コンパイル作業のための方法を記述している。
コンパイラシステムは,RenesasHEW(High-performance Embedded Workshop)4.07を使う。あらかじめ指導者あるいはパソコン管理者が標準構築したHEWがインストールされている環境で,AKI-H8/3048fでプログラムが動作するまでを解説する。C言語のプログラミングについては別の文書で学んでほしい。



図1.1 TNCTマザーボードとAKI-H8/3048F

本解説中で使用しているファイルのダウンロード

FilesForHewPrg.zip

本解説中で使用している作業フォルダのダウンロード
適当な場所に解凍し,中のh8_3048.hwsをダブルクリックすると,HEWが起動し,ワークスペースが現れる。
ただし,解凍されて出てくるフォルダ名は「h8_3048」なので,衝突させないこと。

h8_3048.zip

2.本文書で記述してある作業の特徴

HEWは大きな規模の組み込みシステムを作成することを前提にして作られているようである。学習する為の小さなプログラムを作ろうとするとかなり大げさな作業となる。できるだけデフォルトの設定でコンパクトな作業ができるようにしている。
なお,途中でPCからマイコンにファイル転送するが,これには転送ソフト「h8w.exe」を使う。

「h8w.exe」はyamasan氏のオープンツールです。次の場所から入手できます。
http://ym3.plala.jp/yamasan/

適当な場所にインストールし,h8w.exeと同じフォルダ内にフォルダ「CTRL_MOT」があることを確認しておく。
次のようなCMDファイルを作成しておく。

goH8W3048.cmd (FilesForHewPrg.zipに収録)

rem カレントドライブ・カレントディレクトリへ移動
%~d1
cd %~p1

rem ★フラッシュメモリ書き込みに使用するプログラム
set downloader="C:\Program Files\h8v2\WRITER\H8W\h8w.exe"
rem ★フラッシュメモリ書き込みのためのCOMポート番号を設定します
set ComPortNumber=1

echo [AutoPgm] >myAutoPgm.ini
echo AutoStart=1 >>myAutoPgm.ini
echo AutoExit=1 >>myAutoPgm.ini
echo CtrlProgam=3048_F16M_P384.MOT >>myAutoPgm.ini
echo ComPortNo=%ComPortNumber% >>myAutoPgm.ini
echo UserMotPath=%1 >>myAutoPgm.ini
echo on
%downloader% -GO .\myAutoPgm.ini
@echo off
del myAutoPgm.ini

ここで,★のついたところを,自分の環境に合わせる必要がある。
「h8w.exe」をフルパスで定義すること。


3.プログラムの作成から実行まで

シングルボードマイコンAKI-H8/3048f内で動作するプログラムはパソコン上で開発され、シングルボードマイコンAKI-H8 /3048fのフラッシュメモリに書き込まれます。パソコンで開発されるソースプログラムはC言語で記述され、クロスコンパイラにより、オブジェクトプロ グラムに変換され、最後はフラッシュメモリ書き込み形式(XXXX.MOT)になる。
シングルボードマイコンAKI-H8/3048fを動作させるまでの大きな流れは以下のようになる。

(1)パソコン上でHEW作業用のワークスペースとプロジェクトを作る *1,*2
(2)パソコン上でHEWプロジェクト内のCソースプログラムの作成
(3) パソコン上でHEWのビルドコマンドでダウンロード形式ファイル(実行プログラム)の作成(クロスコンパイル、コード変換)
(4)パソコン上の転送ソフトによる,ダウンロード形式ファイル(実行プログラム)のAKI-H8/3048fへの書き込み操作
これら四つの作業によりシングルボードマイコン内で動作させることが出来る。

*1 ワークスペース 作業用のフォルダのこと
*2 プロジェクト 1つのプログラムを作成するファイル群 ワークスペース内に作られる
   ワークスペース内に複数のプロジェクトを作ることもできるし,1ワークスペースに1プロジェクトという構成でもよい。

4.ワークスペース・プロジェクトの作成

HEWを起動すると,ワークスペースとプロジェクトの設定画面が次々と現れてくる。

(1)ワークスペースとプロジェクトの設定

h8_3048というワークスペース内にLed1stというプロジェクトを設定したところ
フォルダの実体は,デフォルトでC:\WorkSpaceに作られるようになっている。
この場所にWorkSpaceというフォルダがなかったら,自分で作っておく必要がある。
ワークスペース名のフォルダC:\WorkSpace\h8_3048が作られる。
ワークスペースはほかの場所に作ってもよい。

(2)CPUの設定

CPUシリーズは「300H」,CPUタイプは「3048f」を設定する
(300H:AKI-H8/3048f,AKI-H8/3052f,AKI-H8/3069など,300:AKI-H8/3664など)
(3048f:AKI-H8/3048f,AKI-H8/3048f-oneなど)

(3)動作モード,アドレス空間の設定

動作モードはAdvanced,アドレス空間は1MByte(H8/3048fのモード7での使用なので)を設定する

(4)自動生成ルーチンの選択

標準入出力ライブラリは使わないので,「I/Oライブラリ使用」チェックを外す
動的メモリ確保(malloc,callocなど)はしないので,ヒープメモリは使わない。チェックを外す。
Cプログラムソースを作るのでmain関数を呼び出してもらう設定にしておく。
I/Oレジスタ定義(これは)は使用するのでチェックを付ける。
ハードウェアのセットアップは,学習用のため自分で明示的にプログラムする。「None」のまま残す。

ハードウェアのセットアップは,main関数呼び出し前に行うか,main関数内で行うか,2通りの考え方がある。
ここでは,main関数内で行うことにする。

(5)これ以降は変更しないので,この段階で「完了」ボタンを押してよい。

「完了」ボタンを押すと,「概要」が表示されるので,そのまま「OK」を押す。

 

5.Workshopでの作業

ここでWorkshopが自動的に開く。
左側の「プロジェクトペイン」のところに,最初に命名したワークペース名「h8_3048」とその中のプロジェクト「Led1st」が見える。

debugはしないので,下図の右赤丸のところをdebugからreleaseに変更して,debug構成からrelease構成に変更する。

 

参考

この段階でプロジェクト「Led1st」内に自動で作られたファイルは,次の通り。

dbsct.c

各セクションのアドレスなどの変数定義。このファイルには手を付けない。

intprg.c

割り込み関数の定義をするファイル,割り込みの記述をこのファイルに書いてもよいが,
ユーザ用のCファイルに割り込み関数を書いて,このファイル内の対応する関数をコメントアウトしてもよい。

Led1st.c

ここにmain関数をはじめ,必要なプログラムを書く。

resetprg.c

マイコンに電源が投入されてから,mainを呼び出すまでのスタートアップルーチン。
mainから制御が戻ってきてもsleep関数を使って暴走しないようになっている。
このファイルには手を付けない。

stacksct.h

スタックサイズの定義。このファイルには手を付けない。

typedefine.h

標準Cから拡張した型の定義。この定義を使った方が型宣言のあいまいさがなくなる。
このファイルには手を付けない。

 

6.Cプログラミング

左側の「プロジェクトペイン」のところの「Led1st.c」をダブルクリックして開いて,中身をすべて消去して,下記のプログラムを書き込む。
(コピー&ペーストしてよい。)

リスト プログラムソースファイル"Led1st.c"(FilesForHewPrg.zipに収録)

/**********************************************************
マザーボード上のLEDの1秒ごとのON-OFFを行う
**********************************************************/

#include "iodefine.h" //各ポート記述のための定義ファイル HEWが自動生成

void msecwait(int msec)
/*mesc間なにもしない時間稼ぎ関数*/
{
    int i,j;
    for (i=0;i<msec;i++) {
        for (j=0;j<4190;j++);    /*4190は実測によって求めた値 25MHz駆動*/
    }
}

main()
{
    /*P5の下位4ビットを出力に設定*/
    /* P5のDDRの下位4ビットに1を与えるとこの設定になる*/
    /*DDRとはDataDirectionRegister(データ方向設定レジスタ)*/
    P5.DDR =  0x0f;     /*0xc0 = 11000000(二進数)*/
    while(1) {/*これは無限ループ*/
        /*LED0をONにする  P5のDRの第0ビットを1にする*/
        /*DRとはDataRegister(データレジスタ)*/
        P5.DR.BIT.B0=1;
        /*LED1をOFFにする  P5のDRの第1ビットを0にする*/
        P5.DR.BIT.B1=0;
        /*LED2をONにする   P5のDRの第2ビットを1にする*/
        P5.DR.BIT.B2=1;
        /*LED2をOFFにする  P5のDRの第3ビットを0にする*/
        P5.DR.BIT.B3=0;
        msecwait(1000);/*1000msecの間なにもしない*/
        /*LED0をOFFにする  P5のDRの第0ビットを0にする*/
        P5.DR.BIT.B0=0;
        /*LED1をONにする   P5のDRの第1ビットを1にする*/
        P5.DR.BIT.B1=1;
        /*LED2をOFFにする  P5のDRの第2ビットを0にする*/
        P5.DR.BIT.B2=0;
        /*LED3をONにする   P5のDRの第3ビットを1にする*/
        P5.DR.BIT.B3=1;
        msecwait(1000);
    }
}

赤丸で示した「プロジェクトペイン」でLed1st.cをダブルクリックして編集できるように開き,書き換えたところ

 

7.実行形式プログラムの転送形式ファイルのビルド

Cプログラムから実行形式プログラムを作り,さらに転送形式ファイルを作る。
Workshopのビルドメニューからビルドコマンドを選択すればよい。

左下に「Build Finished」が出てくる。
このとき「L1100 (W) Cannot find "C" specified in option "start"」のような警告が出てくるが,
使用していないセクションが見つからないと言っているだけなので,無視してよい。

また,「プロジェクトペイン」内に,「iodefine.h」が自動的に生成されている。

 

8.転送形式ファイルの転送

転送形式ファイル「Led1st.mot」が,ワークスペースフォルダ「h8_3048」内のプロジェクトフォルダ「Led1st」内のフォルダreleaseにある。
これを転送プログラムでマイコンのフラシュメモリに書き込み,実行する。

フラッシュメモリ書き込み形式ファイルの作成とROMライター書き込み操作から実行までの手順

 

パソコン側

マイコンH8側

(1)  

H8/3048fのTNCTマザーボード上のモードスイッチを「Prog」側に倒してから電源スイッチをONにします。
電源LEDが点灯します。

重要 電源をONしてからモードスイッチを切り替えるという逆手順では動作しません。

(2)

転送形式ファイル「Led1st.mot」を最初に作成しておいたgoH8W3048.cmdにドラッグ&ドロップする。
h8w.exeの画面が開いて転送される。

 
(3)  

<1>転送が終了したら、TNCTマザーボード上の電源スイッチをOFFにします。
<2>モードスイッチをラン(Run)にしてから電源スイッチをONにします。
電源LEDが点灯します。

重要 電源をONしてからモードスイッチを切り替えるという逆手順では動作しません。

ここまでの作業が順調に出来ていたら,AKI-H8/3048fマザーボード上の2つのLEDが点滅して動作が確認できるはずです。

 

9.Workshopの終了と,再起動

Workshopを終了する。
終了した状態で,ワークスペースフォルダ「h8_3048」を見ると。そのなかにプロジェクトフォルダ「Led1st」がある。
ワークスペースフォルダ「h8_3048」内のファイル「h8_3048.hws」をダブルクリックすると,Workshopが再起動する。
このときワークスペース「h8_3048」がWorkshop上に開いている。
Led1st.cがエディタ上で開いているので,左下のLed1st.cのタグ上を右クリックして閉じておく。
「プロジェクトペイン」でLed1st.cをダブルクリックすると再びエディタで編集することができる。
最後に,ここではLed1st.cは閉じておこう。

 

10.新規プロジェクトの追加,サービス関数(h8_3048.h)の利用

ここでは,次の2つのことを行う。
A.新規プロジェクトLed2ndをワークスペースh8_3048に追加すること
B.サービス関数定義が記述されたh8_3048.hの利用
  これを利用するとh8/3048fのポートに対する記述が隠ぺいされ,移植性の良いプログラミングができる。

注 新規プロジェクトは,別な新規ワークスペース上に作ることもできるが,それは「4.ワークスペース・プロジェクトの作成」ですでに述べた方法で作成できる。

「8」で述べたように,ワークスペースフォルダ「h8_3048」内のファイル「h8_3048.hws」をダブルクリックすると,Workshopが再起動すると,ワークスペース「h8_3048」がWorkshop上に開いている。
Led1st.cがエディタ上で開いているので,左下のLed1st.cのタグ上を右クリックして閉じておく。

「プロジェクトペイン」の一番上の「h8_3048」はワークスペースを表している。
h8_3048のところで,右クリックして「プロジェクトの挿入...」で,新規プロジェクトをワークスペース「h8_3048」に追加することができる。
「4.ワークスペース・プロジェクトの作成」とおなじように,プロジェクトの設定画面が次々と現れてくる。

「4.(1)」のところで,ワークスペース名は「h8_3048」そのままにし,プロジェクト名のみ「Led2nd」に設定し,ディレクトリ名はHEWが自動でつくるのに任せる。
「4.(2)」〜「4.(5)」までは全く同じ設定でよい。
設定が終わると,プロジェクト「Led2nd」が見えてくる。

プロジェクトLed2ndがアクティブになっていることを確認して,「5」の最初とおなじように,debug構成からrelease構成に変更する。

「プロジェクトペイン」で,Led2ndの文字が強調されているが,ビルドを行うと,Led2ndがビルドされることを示している。
別な表現をすれば,Led2ndが作業対象になっているという意味だが,このことをアクティブプロジェクトと呼んでいる。
もし,Led1stをアクティブプロジェクトにしたければ,Led1stのところで右クリックし,「アクティブプロジェクトに設定」でよい。
元に戻すには,Led2ndのところで右クリックし,「アクティブプロジェクトに設定」でよい。

FilesForHewPrg.zipに収録されている「h8_3048.h」と「h8_3048.c」をWindows上で,プロジェクトフォルダ「Led2nd」にコピーする。
コピーしただけでは,Workshop上に反映されてこない。
「プロジェクトペイン」の「Led2nd」を右クリックして,「ファイルの追加...」でプロジェクトフォルダ「Led2nd」内の「h8_3048.h」と「h8_3048.c」を追加する。
「プロジェクトペイン」のLed2nd配下に「h8_3048.h」と「h8_3048.c」が見えてくる。

「6」と同じように操作して,「Led2nd.c」を次の内容にする。

リスト プログラムソースファイル"Led2nd.c" (FilesForHewPrg.zipに収録)

/**********************************************************
msecwait関数で1秒ごとのLEDのON-OFFを行う
**********************************************************/
#include "iodefine.h"    //各ポート記述のための定義ファイル HEWが自動生成
#include "h8_3048.h" //サービス関数群の定義ファイル 小坂が作成したもの

void msecwait(int msec)
{
    int i,j;
    for (i=0;i<msec;i++) {
        for (j=0;j<4190;j++);    /*4190は実測によって求めた値 25MHz駆動*/
    }
}

main()
{
    initLed();
    while(1) {
        turnOnLed(0); /*LED0のON*/
        turnOffLed(1); /*LED1のOFF*/
        msecwait(1000);
        turnOffLed(0); /*LED0のOFF*/
        turnOnLed(1); /*LED1のON*/
        msecwait(1000);
    }
}

 

「7.」と同じように,ビルドする。

「8.」と同じように,マイコンに転送し,LEDが点滅すれば成功。

 

11.割り込み処理(例外処理)の記述

ここでは,割り込み処理の記述についてのべる。

「10.」を参考に,新規プロジェクトint1stを作成する。

プロジェクトint1stがアクティブになっていることを確認して,「5」の最初とおなじように,debug構成からrelease構成に変更する。

FilesForHewPrg.zipに収録されている「h8_3048.h」と「h8_3048.c」をWindows上で,プロジェクトフォルダ「int1st」にコピーする。
コピーしただけでは,Workshop上に反映されてこない。
「プロジェクトペイン」の「int1st」を右クリックして,「ファイルの追加...」でプロジェクトフォルダ「int1st」内の「h8_3048.h」と「h8_3048.c」を追加する。
「プロジェクトペイン」のint1st配下に「h8_3048.h」と「h8_3048.c」が見えてくる。


「6」と同じように操作して,「int1st.c」を次の内容にする。

リスト プログラムソースファイル"int1st.c" (FilesForHewPrg.zipに収録)

/**********************************************************
時間割り込みによってLEDのON-OFFを行う
**********************************************************/
#include <machine.h>
#include "typedefine.h"  //拡張された型宣言の定義ファイル HEWが自動生成
#include "iodefine.h"    //各ポート記述のための定義ファイル HEWが自動生成
#include "h8_3048.h" //サービス関数群の定義ファイル 小坂が作成したもの

main()
{
    initLed();
    initTimer1Int(10000); /*時間割り込み10000μsec=10msec ITUch1使用*/
    set_imask_ccr((_UBYTE)0);  /*CPU割り込み許可,禁止したい時は1を与える*/
    startTimer1();  /*時間割り込みタイマスタートch1*/
    while(1);       /*なにもしないループ*/
}

// この関数は1秒に1回呼ばれている
void CyclicWork(void)
{
    static int tick=0;
    if (tick==1) {
        turnOnLed(0);
        turnOffLed(1);
    } else {
        turnOffLed(0);
        turnOnLed(1);
    }
    tick=1-tick;
}

/*タイマ割り込みルーチン*/
// vect=28の割り込み関数をここで定義するので,
// intprg.cのvect=28の関数定義をコメントアウトすること
// 以下の記述で割り込みベクトルも設定される。

__interrupt(vect=28) void TimerIntFunc(void)
{
    static int count=0;
    clearTimer1Flag();
    if (count==0) CyclicWork();
    if (++count==100) {
        count=0;
    }
}

説明

「__interrupt(vect=28)」というのは,次の関数は割り込み関数であり,割り込みベクタは28であることを示している。
これにより,この関数が機械語になった時には,レジスタと退避と復帰が組み込まれることになる。
また割り込みベクタ領域の28番(アドレス0x70 28×4=114の16進表現が0x70)に,
関数TimerIntFuncの先頭アドレスが設定される。

ベクタ28の割り込み関数は,HEWも「intprg.c」に自動で生成している(何もしない関数が書かれている)ため,
それを消さなければ,二重定義になってしまう。
そこで,プロジェクトペインのプロジェクトintist配下の「intprg.c」を修正する。
以下のようにvect=28の定義をコメントアウトする。

変更前 //  vector 28 IMIA1
__interrupt(vect=28) void INT_IMIA1(void) {/* sleep(); */}
変更後 //  vector 28 IMIA1
//__interrupt(vect=28) void INT_IMIA1(void) {/* sleep(); */}

あるいは,intprg.cそのものを消去してもよい。

「7.」と同じように,ビルドする。

「8.」と同じように,マイコンに転送し,LEDが点滅すれば成功。