このページには、日立製作所製組み込みマイコン Tiny H8, H8/3664 のC言語による開発環境方法をメモしておきます。
だれの役に立つかわかりませんが、少なくとも、私の覚え書きにはなります。
そもそも、いまとなってはobsoluteな方法な気が非常にしますが、私は相変わらず当時のままの開発環境(H8TurboWriteにはなりましたが)なのですが...。
私がお世話になった東北大学江村研では秋月電子通商のAKI-H8 をロボット制御のコントローラとして使用していました。
AKI-H8 の研究室への導入は、相原氏(2001年1月現在M2)によるところが多く、研究室での導入1号は、氏の代が4年生の時に作りあげた知能ロボットコンテストロボット参加用ネコ型ロボット、「ポチEvolution」の改良型「ポチ EVO 2」です。
最初外部のパソコンによって制御されていたポチは、この改良により自立型ロボットに進化しました。
その際、仙台電波高専の熊谷先生(研究室の大先輩ではありますが私の親戚ではありません<一時父親説が流れた(^^;)らの情報に基づき、秋月電子のCコンパイラの利用環境の構築をしています。
このあと、H8の利用技術は研究室内に広まり、2000年には、やはり秋月の300円ブレッドボードを2枚搭載し、簡単な回路の試験は十分可能な、H8ベースボードが小泉氏(同M2)によって開発されました。
C言語開発環境もより使いやすいものに進化しました。
さらに、これをベースに、USBから5V電源を取り、DC-DCコンバータで書き込み用電源を生成するH8BB改がくまがいによって試作されました。
従来必要だった15V程度のACアダプタが不要となり、シリアルポート、USBのあるノートパソコンと組み合わせることで、開発がさらに容易となりました。
(残念なことに、某アニメによってUSBを電源とする案は公知となってしまいましたが、それとは一切関係ありません)
そんな 2000年秋、秋月電子より新たなH8として、TinyH8 のキットが発売されました。Tiny H8 は特徴として、5V単電源の書き込みをサポートし、H8/3048とインストラクション上位互換、ピン数削減による省面積および低コスト化が図られ、ちょっとした制御、センシングなどの目的にはより便利なものとなりました。
しかしながら、C言語による開発手法はそれほど知られておらず、試行錯誤が必要でした。ここでは、その手法の一つを公開します。
なお、現在は秋月電子より、Cコンパイラ込みの開発環境が提供されていますので、それを利用するのが無難です。
追加投資抜きに、H8/3048 の開発セットをそのまま流用する場合には、うまくいくかもしれません。
また、秋月のコンパイラも新しくなっていると思われますので、「CPUを300HNにして、SUBファイルのメモリ配置を64K空間に併せる」ところを基本に調整してみてください。
- 秋月電子通商 H8 Tiny (全部入った2800円のほう)
- 秋月電子通称 H8 C コンパイラ
- ヘッダファイル:ルネサス→開発環境→同意する
ZIP展開→include\300L\3664.h
BASEDIR\writer\
3664.mot hterm.exe readmer.txt
Tiny H8 付属の hterm 関係を入れておく
3664.mot はデータ転送用
ここに最終バイナリがおかれることになる
BASEDIR\c\
1-A38h.exe 2-L38h.exe 3-C38h.exe
c38asmb.exe c38cgnb.exe c38frntb.exe
c38midb.exe c38pepb.exe cc38h.exe
include\ library\
Compile.bat
作業ディレクトリである。基本的に秋月電子のCコンパイラの
なかみをぶちまけた上で、Compile.bat を用意する↓。
BASEDIR\c\work
コンパイルの生成ファイルが移動される。
BASEDIR\c\include
H8 Tiny のヘッダファイルを 3664.h としておいておく。
コンパイルを行う Compile.bat を以下に示します。
ECHO OFF
ECHO AKI-H8 tiny 用モトローラ形式hexファイル作成バッチコマンド
set BASE=d:\h8\tiny\c\ ← 作業ディレクトリを設定
1-A38h.exe %2.mar >%1.res
cc38h.exe -CPU=300HN -LIST -INCLUDE=include %1.c >>%1.res
2-L38H.exe %1.obj %2.obj -output=%1 -print=%1 -SUBCOMMAND=%1.sub >>%1.res
3-C38h.exe %1.abs >>%1.res
type %1.res
copy %1.abs %BASE%..\Writer >> NUL
copy %1.map %BASE%work >> NUL
copy %1.obj %BASE%work >> NUL
copy %1.mot %BASE%work >> NUL
copy %2.obj %BASE%work >> NUL
copy %2.lis %BASE%work >> NUL
del %1.map >>NUL
del %1.obj >>NUL
del %1.mot >>NUL
del %2.obj >>NUL
del %2.lis >>NUL
このバッチファイルは引数を2つ取ります。1つ目はコンパイルすべきCソース、
2つ目はスタートアップルーチンの.marファイルです。その他に、
ソースと同名の .subファイルが必要です。これはコンパイラの
出力するプログラム・データなどの領域をH8のメモリ空間(EEPROM/RAM)に
配置するために必要です。
このバッチファイルを実行すると、コンパイルが正常に終了した場合、
ソースと同名の .abs ファイルがライタのフォルダにコピーされます。
これを付属説明書にしたがって hterm で Alt-F して 3664.mot に
続けて転送して書き込みを行います。
動作を確認した プログラムを以下に示します。
/* test.c */
#include <3664f.h>
int dummy;
char *ds="auau";
void main(void)
{
int i,j,k;
IO.PMR5.BYTE&=0x3f; /* disable special function -> IO */
IO.PCR5=0xff; /* output direction */
IO.PDR5.BYTE=0x31; /* output */
while(1) /* count length is good! for tester(near 1s) */
{
for(k=0;k<63;k++)
{
IO.PDR5.BYTE=k;
for(i=0;i<30000;i++)
for(j=0;j<10;j++)
;
}
}
}
次にstart.marを示します。もとは高専の熊谷先生から
もらってきて研究室内で変質した上に、H8 Tiny 用に変更しました。
H8 Tiny は H8 シリーズのノーマルモード(アドレス16bit)で動作するため、
H8/3048用のアドバンスモードの設定では動きません。そこで、 .cpu の
オプションを "300hn" にしています。なお、割り込みベクトルが
小さくなっているため、スタートは 100h より下げられますが、
いまのところ放置しています。
;"start.mar" for startup routine
; 1998.08.27 by ckuma <- for H8 3048
; 2000.12.26 changed for H8 tiny 3664 by m.kumagai
.cpu 300hn
.print list
.import _main
;
ramend: .equ h'ff80 ;fff7+1
;
.section vect,data,locate=h'0 ;ベクタ領域
.data.w init ;リセットベクタ
.org h'100 ;初期設定領域(-h'1ff)
init: mov.l #ramend,er7 ;スタックポインタ設定
ldc #0,ccr ;Clear interrupt mask bit(permition of interrupt),not use UI bit
;
jmp @_main ;Cのメインルーチンへ
;
.end
次に、test.subです。
LIB library\c38hnb
START P,C,D(200),B(0F780)
EXIT
ここで領域名 B をRAMの先頭に、P,C,D(プログラム、固定データ、文字列定数らしい)
をEEPROM領域の200〜に配置しています。ちなみに、RAMの最後からスタックは
取られていきます。これを Compile test start
とすると test.abs ができます。
5V単電源で動くと言うことで最初から USB接続モデルにしています。
レギュレータも載せずに、USBケーブルをはんだづけしてしまっているので、
パソコンがなければ動きません。そのかわり、ノートパソコンとセットで
もちあるけば、どこでも遊べるモバイル Tiny H8 となっています(笑)。
A/D 8チャネルがフルに活かせる、フラットパッケージも入手済みなので、
そのうちにそっちも使えるようにしたいと考えています。H8/3048 で
持て余すような場合には便利だと思いますよ。
あ、I2Cさっぱりつかってないじゃん(笑)
その他、これまで試験したプログラムを以下に示します。
/* SCI test program */
#include <3664f.h>
/* dummies */
int dummy;
char *ds="auau";
void main(void)
{
int i;
SCI3.SMR.BYTE=0; /* P179/315 0000 0000 */
SCI3.SCR3.BYTE=0x00; /* P180/315 0000 0000 */
SCI3.BRR=25; /* P185, 16MHz - 19200 - 0 - 25 - 0.16% */
SCI3.SCR3.BIT.RE=1;
SCI3.SCR3.BIT.TE=1;
IO.PMR1.BIT.TXD=1; /* P22 -> TXD */
for(i=0;i<1000;i++)
; /* dummy wait for clock */
for(i=0;i<26;i++)
{
while(!SCI3.SSR.BIT.TDRE)
;
SCI3.TDR='A'+i;
}
while(1)
{
while(!SCI3.SSR.BIT.RDRF)
;
while(!SCI3.SSR.BIT.TDRE)
;
SCI3.TDR=SCI3.RDR;
}
}
最初にA-Zを出力して、おうむ返しをするようになります。
/* SCI test program */
#include <3664f.h>
/* dummies */
int dummy;
char *ds="auau";
unsigned char str2hex1(char c)
{
if((c>='0')&&(c<='9')) return c-'0';
if((c>='A')&&(c<='F')) return c-'A'+10;
if((c>='a')&&(c<='f')) return c-'a'+10;
return 0;
}
unsigned char str2hex2(char *s)
{
return str2hex1(s[0])*16+str2hex1(s[1]);
}
void Putchar(c)
{
while(!SCI3.SSR.BIT.TDRE)
;
SCI3.TDR=c;
}
void PutString(char *s)
{
while(*s)
{
Putchar(*s);
s++;
}
/* Putchar('\r');
Putchar('\n');*/
}
void PrintUInt(unsigned int i)
{
char tmp[7];
int c=5;
tmp[6]='\0';
while(i)
{
tmp[c]=(i%10)+'0';
c--;
i=i/10;
}
if(c==5) { tmp[5]='0'; c--; }
PutString(tmp+c+1);
}
void InitSCI(void)
{
int i;
SCI3.SMR.BYTE=0; /* P179/315 0000 0000 */
SCI3.SCR3.BYTE=0x00; /* P180/315 0000 0000 */
SCI3.BRR=25; /* P185, 16MHz - 19200 - 0 - 25 - 0.16% */
for(i=0;i<1000;i++)
; /* dummy wait for clock */
SCI3.SCR3.BIT.RE=1;
SCI3.SCR3.BIT.TE=1;
IO.PMR1.BIT.TXD=1; /* P22 -> TXD */
}
void Puts(char *s)
{
PutString(s);
PutString("\r\n");
}
void main(void)
{
int i;
char buff[51];
InitSCI();
/*for(i=0;i<1000;i++)
PrintUInt(i);*/
while(1)
{
for(i=0;i<50;i++)
{
while(!SCI3.SSR.BIT.RDRF)
;
buff[i]=SCI3.RDR;
if(buff[i]=='\r') break;
if(buff[i]=='\n') break;
}
buff[i]='\0';
Puts(buff);
for(i=0;;i+=2)
{
if((buff[i]=='\0')||(buff[i+1]=='\0')) break;
PrintUInt(str2hex2(buff+i));
Putchar(' ');
}
Puts("");
}
}
とある目的のために、16進数を受け取れるようにしたプログラム。
ただし、まだ割り込みとかは使ってません。今後使えるようにする
つもりではあります。
(H8/3048 ではバックグラウンド送受信ルーチンを開発済み)