目次

・HEWとは

・ワークスペース、プロジェクトの新規作成

・HEWの生成するファイル群

・メイン関数のありか

・IOレジスタを操作する!!

・割り込み処理はどこに?

・math.hが使えない!?

・スタック領域を変える

・最適化オプション

・ルネサスコンパイラ固有の関数など

・割り込みが動かない!?

・プロジェクトの複製

・プロジェクトの追加

HEWとは

 HEW(High-performance Embedded Workshop)はルネサスが提供しているエディタ、コンパイラ、エミュレータといったツールを、使いやすくまとめてくれている統合開発環境です。

コンパイラ、リンカなど、各工程ごとに用意された複数のツールを、 あたかも多機能な一つのツールであるかのように 操作できます。

 HEWをインストールすればコンパイラもリンカも入っているので、HEWがあればルネサスエレクトロニクスのマイコンの開発はできるということになります。

プロジェクトの新規作成

 プロジェクトの作成についてはこのサイト↓に詳しく解説されています。

HEWでAKI-H8/3048Fのプログラミング

 色々な設定のうち、プロジェクト生成後に変更できないのはCPUの種類と、「Use Heap Memory」、「Use I/O Library」にチェックを入れるかどうかというところです。メモリ管理ライブラリや入出力関連のライブラリが要らない場合はいいです。しかしライブラリを生成しておいても後でプロジェクトから外すこともできますからチェックを入れてもいいかもしれません。

HEWの生成するファイル群

 HEWは初期設定が終わった段階で、ターゲットに合わせたファイルを自動的に生成します。以下のようなファイルです。

 初期設定の時にチェックマークを付けなければ生成されないものもあります。sbrk.c、sbrk.h、lowlvl.src、lowsrc.c、lowsrc.hは必ずしも要りません。

dbsct.c・・・_初期値がある変数、初期値がない変数のセクション初期化テーブルの設定。 ○○○.c(○○○はプロジェクト名)・・・メイン関数がある。 intprg.c・・・割り込み関数がある。 resetprg.c・・・パワーオンリセット時の処理が記述してある。 sbrk.c・・・メモリ管理ライブラリの低水準インターフェースルーチンなど。「Use Heap Memory」にチェックを入れると生成される。 sbrk.h lowlvl.src・・・入出力関連の低水準インターフェースルーチン。「Use I/O Library」にチェックを入れると生成される。 lowsrc.c lowsrc.h vecttble.c・・・ベクタテーブルがある。 vect.h・・・vecttble.cにある関数のプロトタイプ宣言 stacksct.h・・・スタックサイズが記述してある。ここは直接触らない。 typedefine.h・・・typedefを使って変数の型に別の名前をつけている。他のファイルでインクルードされて使われている。 iodefine.h・・・IO操作用の構造体などが定義されている。

 初心者の方は特にファイルの細部については気にしなくていいと思います。そのためのHEWなんですから。

でも一応、詳細はここにあります↓

http://documentation.renesas.com/jpn/products/tool/rjj10j0929_hew_s.pdf

メイン関数のありか

 HEWでプログラミングするとき、メイン関数はどこに書けばいいのでしょう?実はメイン関数は○○○.c(○○○はプロジェクト名)に自動生成で用意されています。では中身を見てみましょう。

○○○.c(○○○はプロジェクト名)を見ると、以下のようになっています。

//○○○.c //#include "typedefine.h" #ifdef __cplusplus //#include // Remove the comment when you use ios //_SINT ios_base::Init::init_cnt; // Remove the comment when you use ios #endif void main(void); #ifdef __cplusplus extern "C" { void abort(void); } #endif void main(void) { } #ifdef __cplusplus void abort(void) { } #endif

 C++で開発するときのためのマクロなどが設定されていますが、Cで開発するときは見にくければmain関数のプロトタイプ宣言とmain関数本体を残して他は消しても良いです。シンプルになります↓

//○○○.c void main(void); void main(void) { //ここにメインの処理を書いてください。 }

 このメイン関数の中にメインの処理を書いていきます。

 組み込みプログラミングでは必ずしもメイン関数からプログラムが始まるとは限りません。自動生成されたメイン関数にメインの内容を書いていい根拠はどこにあるのでしょう?resetprg.cを見ればわかります。

resetprg.cの中を見てみます。

//resetprg.c void PowerON_Reset_PC(void) { set_vbr((void *)((_UBYTE *)&INT_Vectors - INT_OFFSET)); _INITSCT(); // _CALL_INIT(); // Remove the comment when you use global class object // _INIT_IOLIB(); // Enable I/O in the application(both SIM I/O and hardware I/O) // errno=0; // Remove the comment when you use errno // srand((_UINT)1); // Remove the comment when you use rand() // _s1ptr=NULL; // Remove the comment when you use strtok() // HardwareSetup(); // Use Hardware Setup set_cr(SR_Init); main(); // _CLOSEALL(); // Close I/O in the application(both SIM I/O andhardware I/O) // _CALL_END(); // Remove the comment when you use global class object sleep(); }

 void PowerON_Reset_PC(void)という関数がありますが、これは電源が入った時に実行される関数です。このPowerON_Reset_PC()関数の中でmain()が呼び出されているので、電源が入ったときにmain()が実行されるわけです。 これがmain関数にメインの処理を書けばいいことの根拠です。

 mainという名前が嫌な人はここの名前を書き換えればいいのです。

IOレジスタを操作する!!

 iodefine.hというヘッダファイルには、ターゲットに応じたIOレジスタ操作のための構造体(及び共用体、ビットフィールド)が宣言されています。ずらーっと構造体が並んでいて、一番下のところで、構造体の先頭アドレスが決められてています。

struct st_sci {                                         /* struct SCI   */               union {                                   /* SCSMR        */                     unsigned char BYTE;                 /*  Byte Access */                     struct {                            /*  Bit  Access */                            unsigned char CA  :1;        /*    C/A       */                            unsigned char CHR :1;        /*    CHR       */                            unsigned char _PE :1;        /*    PE        */                            unsigned char OE  :1;        /*    O/E       */                            unsigned char STOP:1;        /*    STOP      */                            unsigned char MP  :1;        /*    MP        */                            unsigned char CKS :2;        /*    CKS       */                            }      BIT;                  /*              */                     }           SCSMR;                  /*              */ //~~~~~省略~~~~~~~~~~~~~~~~~~~~~~~~ #define SCI0 (*(volatile struct st_sci *)0xFFFFC000)/* SCI0 Address*/ #define SCI1 (*(volatile struct st_sci *)0xFFFFC080)/* SCI1 Address*/ #define SCI2 (*(volatile struct st_sci *)0xFFFFC100)/* SCI2 Address*/ #define MTU2 (*(volatile struct st_mtu2 *)0xFFFFC20A)/* MTU2 Address*/ //~~~~~省略~~~~~~~~~~~~~~~~~~~~~~~~

#define SCI0 (*(volatile struct st_sci *)0xFFFFC000)

という記述ですが,これは構造体の先頭アドレスを分かりやすい単語として定義しているところです。  まず、 (volatile struct st_sci *)0xFFFFC000 で0xFFFFC000が構造体を指すポインタ型に変換されています。  それを間接参照演算子で括って (*(volatile struct st_sci *)0xFFFFC000) となっているわけです。これを#defineでそれぞれ適当な名前に置き換えています。  SCI0のCAビットの値を操作したければ

SCI0.SCSMR.BIT.CA=1;

という風にすればいいです。  ビットサイズを操作したいときに、&や|演算子を使ってアクセスする流儀もありますが、ルネサスのコンパイラにおいては全く違いはありません。可読性を優先してビットフィールドを使ったほうがいいかもしれません。

割り込み処理はどこに?

 intprg.cに割り込み時の処理を書き込みます。  例えば、CMTの割り込みを使いたければ以下の部分を使います。

void INT_CMT0_CMI0(void){ ///* sleep(); */を消去してここに処理を書く }

 ちなみに、ルネサスの中の人の本SuperHファミリのCプログラミング(香取祐二 著)によると

今から紹介する割り込み関数内での関数呼び出しはシステムに多大な影響を与えます。(中略)割り込み関数内で他の関数を呼び出した場合、無駄なCPU内部レジスタの待避・復旧が行われることになります。

とあり、割り込み関数内で他の関数を呼び出さないほうがいいことが言われています。

 必要なら、マクロを利用したりルネサスコンパイラのインライン展開を利用することが推奨されてます。

 ここらへんはコンパイラがうまいことやってはくれないところというわけです。

math.hが使えない!?

 プロジェクトの生成時にチェックを入れておかないと数学関数やその他関数が使えないことがあります。後からヘッダファイルを追加するには、

メニューのビルドSuperH RISC engine toolchein標準ライブラリ

からカテゴリ:標準ライブラリを選びます。

 そして、math.hのとこにチェックを入れてOK押せばいいです。その他ライブラリについても同様です。

スタック領域を変える

 これもプロジェクト生成時に決めてありますが、当然、後から変更できます。

メニューのプロジェックト構成の編集スタック

のところで変えます。

最適化オプション

ルネサスコンパイラ固有の関数など

 ルネサスコンパイラではC言語だけでは記述できない部分について組み込み関数を用意しています。普通はアセンブラで書くとこですね。よく目にするものを一部紹介します。

SRを操作する関数

void set_imask(int)割り込みマスクの設定
int get_imask(void)割り込みマスクの参照
void set_cr(int)SRの設定
int get_cr(void)SRの参照
void set_vbr(void*)VBRの設定
void *get_vbr(void)VBRの参照
void sleep(void)SLEEP命令

#pragmaを使った拡張機能もあります。

#pragma interrupt(関数名[割り込み仕様])割り込み処理関数を指定
#pragma section 名前or数値セクション名の変更、名前の指定無しでデフォルトに戻る
#pragma inline(関数名)関数をインライン展開
#pragma stacksize 定数セクションSを指定した領域で確保

割り込みが動かない!?

 割り込みマスクレベルが最高になったままだからでは無いでしょうか?

 ともかく割り込みマスクレベルを0にしてやればどんな割り込み優先度の割り込みも実行されます。

 割り込み優先度をゼロにするには

resetprg.cの20行目あたりにある、

#define SR_Init 0x000000Fを

#define SR_Init  0

に変えてやればいいです。

 ファイルに手を加えたくない場合はset_imask()関数を使えばいいです。

set_imask(0);

をmain関数の初期化部分に書いておきます。

プロジェクトの複製

 現状正常に動いているプロジェクトに手を加えたくなく、プロジェクトを複製したい場面があると思います。

プロジェクトを複製する方法として最初に思いつくのはWorkSpaceフォルダの中身のプロジェクトのフォルダをコピーして名前変更して複製することではないでしょうか。しかしこの方法ではHEWには新しいプロジェクトとして認識してもらえません。プロジェクトとファイルの依存関係が.hwpファイルに記述されており、その内容を変えないままコピーしてもダメなのです。ただ、この.hwpファイルをテキストエディタなどで編集するのはちょっと面倒です。変更し忘れる箇所もあるかも知れません。ですから、HEWの機能を使ってプロジェクトを複製するに越したことはないのです。

 しかしながら、HEWにはずばり複製というコマンドがありません。ちょっと手順を踏む必要があります(大したことは無いんですけど)

 まず、複製元のプロジェクトを開いた状態でプロジェクトプロジェクトタイプの作成を選択します。

「新規プロジェクトタイプで使用する名前を入力してください」

とあるので、好きな名前を入力して完了をクリックします。

これで下準備はOKです

 あとは普通にプロジェクトを生成するときと同じようにプロジェクトを生成しますが、ここでプロジェクトタイプの項目に先ほど作成したプロジェクトタイプが追加されています。それを選択しプロジェクトを生成すると、複製ができあがります。

 不満なのは、ただコピーするためだけに新しいプロジェクトタイプなるものが追加登録されてしまうことです。

プロジェクトの追加

 1つのワークスペースには複数個のプロジェクトを含めることが出来ます。新しくプロジェクトを作りたいときにワークスペースも新しく作ってしまうのではなく、関連するワークスペース上に追加して作ったほうが後々プロジェクトどうしを連携させることなどできて便利です。何よりちょっと整理されて気持ちがいいです。

 

プロジェクトを追加するにはプロジェクトプロジェクトの挿入を選んで、あとは普通にプロジェクトを作成すればOKです。

左に表示されているプロジェクトウィンドウのツリーにプロジェクトが追加されていると思います。

複数のプロジェクトのうち、どのプロジェクトで作業するかは

プロジェクトアクティブプロジェクトに設定

から選択するか、左のプロジェクトウィンドウで右クリックしてアクティブプロジェクトに設定で決められます。