徒然日記 電子工作編でタグ「H8」が付けられているもの

 昨日、完全 ROM 化してエージングをかけていると不具合発生。15分程度動かしていると、強制的に’under'状態になり、表示がちらつく感じ。
 調べてみると、プログラム内部の基準クロックにしていた、TimerA の割り込みで 31.25ms ごとに更新される 16bit のフリーランカウンタの扱いに問題があった。
 16bit の符号無し整数でボローが出たときの処理が、x86 の gcc と違うような気がするのだが気のせいか?

-----
 一晩エージングしたが、特に問題はないよう。

  • ごく希に、一瞬だけ 'under' を表示する
  • data セグメントの定数にうまくアクセスできない
という不具合はすでに判明しているのだが、どちらもタチが悪そうなので今回は目をつぶる (^^;
090617003.JPG  今日はすでに ROM 化してある TimeW のルーチンをチェック後、全部の動作を組み合わせてみた。ようやくそれらしく動いた (^^
 今日はここまで 30分。のこり 30分は...。結局コード圧縮に勤しむ。全部の関数を main に入れたり、2進->10進変換に H8OS API を使ったりで 256byte ほど圧縮。

  あとは、正常動作、回転数高すぎ、回転数低すぎ、エンジン停止の状態を作ればプログラムは一応完成。作ること自体は難しくないのだが、メモリが足りない...。
  RAM 上で動作チェックはやめて、いきなり ROM で動かすことにしようか?
-----
  ちなみに、自分で作った H8+GCC 向けの「吐き出されるオブジェクトの小さい2進->10進変換」のソースはこちら。10分かそこらで作ったたいしたコードではないのだが、記念に残しておこう (^^;

    short i,ptr,n,m;
    ptr = 19;
    for (i = 0;i < 4;i++) {
//    while(x > 0) {
        n = x / 10;
        m = x - n * 10;
        LcdRam[ptr--] = m + '0';
        x = n;
    }
 今日は LCD アクセスルーチンの ROM 化。の前に、昨日作業を終えてから気がついた TimerW アクセスルーチンの<del>バグ</del>不具合を直して動作確認。

 そのあと、LCD アクセスルーチンを ROM 化し、テストプログラムを書いたのだが、あっという間にコードが膨れ上がり RAM 容量の壁にぶち当たる。

----
 このプロジェクトを始めてから、早一月半。LCD アクセスルーチンのファイルのタイムスタンプは丁度一ヶ月前。いくらなんでも2ヶ月以内に完成させたいと、今日の作業時間は2時間。
 予想外のところに時間を吸い取られていく...。
----
 H8+gcc は異様にコード効率が悪い。

struct sLcdFont {
    unsigned char code;
    unsigned char *dat;
};
void    lcd_font_set_up(void)
{
    int    i;
    struct sLcdFont buf;

    for (i = 0;i < 6;i++) {
        buf.code = i;
        buf.dat = font[i];
        func_tbl[SetLcdFont]((int)&buf);
    }
}
SetLcdFont は定数。

 この関数が 92byte。

void    put_disp(unsigned short x)
{
    disp_bar(x);
    disp_number(x);
    func_tbl[RewriteLcd](0);
}
RewriteLcd は定数
 この関数が 50byte

 ちなみにコンパイルオプションは -O。引数のレジスタ渡しとかしないのだろうか?

 開発中のコードに使える RAM 領域は 1kbyte 強ある。これだけあれば何とかなると思っていたのだが、全然足りなくなってきた。



 昨日作った ROM化した TimerA アクセスルーチンを使うためのプログラムを作る。

 「関数のポインタの配列へのポインタ」をアクセスするのに悩んだが、なんとか一発で動く。

 ROM にある関数のアクセスはこんな感じ。

enum {dummy,InitTimerA,GetTimerA_Counter};
#define func_tbl_ptr (int (**)(int))(*(volatile unsigned long *)0x5800)
int (**func_tbl)(int);
func_tbl = func_tbl_ptr;
func_tbl[InitTimerA](0);

 このあと、二つの *.mot ファイルを CPU の FLASH に書き込むのに手間取るが(結局二本の *.mot をエディターで結合した)、ROM 化した関数のアクセス・動作は問題なく成功。

 明日は TIimerW アクセスルーチンの ROM 化だ。



 プログラム全体のサイズが H8OS/3664 の RAM 領域で開発できる範囲を大きく超えることが明らかになったので、今まで作ったルーチンを少しずつ ROM 化していくことにした。
 最初はサイズが小さく機能も少ない TimerA 割り込み関連の処理から。H8OS 本体のリンカスクリプトを見ながら専用のリンカスクリプトを作る。関数ベクタテーブルの ROM 化に手間取ったがとりあえずそれらしい *.mot ファイルが完成。

 しかし、こういうのは最近の組み込みの範疇に入るのだろうか?いや、入るのだろうが、おそらく「プリミティブ」なごく一部な領域になるのだろう。

 今日はここで time up。明日は呼び出す側のプログラム作成、ROM への書き込み、そして debug だ。

----
 関数へのポインタの配列を定数化にするのに、少し悩む。

const int (*func_tbl[])(int) = {main,...};
 だと、const int を返す関数のポインタへの配列になってしまう。

int (* const func_tbl[])(int) = {main,...};
 正解はこちら。やっぱりポインタは難関だ。
----
 gcc は(同じファイルにない)外部関数のアドレスを引っ張ってこれる。以前使っていた 8/16bit の C コンパイラではこれが出来なくて苦労した記憶がある。
----
 今日、ヘキサファイルを眺めていて気付いたが、H8 の gcc はポインタが 4byte もある。コードがでかくなるわけだ。

 昨日少し調べたが、H8 CPU は 16bit レジスタが 16本もある。なるほど、C で割り込みハンドラを書くとスタックを馬鹿食いたくさん使うわけだ。


 昨日に引き続いて、タイマW のソースにタイマA を組み込むとうまく動かない不具合の調査。色々やっていくうちに、スタックがコードを食い荒らしているのではなかろうかと考え H8OS のメモリダンプやらメモリクリアを使って見て行くと、確かにスタックがコードまでは行かなくても bbs 領域まで侵食した跡が見える。

 割り込みハンドラの終わり方を間違ってスタックを食い続けているか、いや、ハンドラの管理は H8OS だし。CPU の data sheet を見ても特殊な「お約束」があるようにも見えないし...。

 あれこれやった結果、割り込みを使うとその分スタック使用量が増えて、H8OS のユーザーRAM 領域にまで入り込むらしいことがわかった。これなら使わないソースを組み込んだだけで動作がおかしくなるのも納得がいく。

 今日はここまでで 20分のオーバー。つまらないことで一日半も使ったと思うと悔しいが、2時間と思えば、そうでもない。

-----
 これ以上は RAM 上での開発は無理。ここから先は毎回フラッシュに焼いていかなくてはならない。CPU の書き込み制限 100回以内に完成させられるか?

----
 それにしても、H8 のメモリ利用率は、8086/Z80 に比べて異様に悪い気がする。気のせいなのか、いまどきの CPU はこんなものなのか?
001.JPG  昨日接続した車両エミュレータと開発ボードを使って周期測定ルーチンのデバッグ開始...。あっさり動いた (^^;。
 ここは手こずると思っていたのでうれしい。

 時間が余ったので何をしようかと悩んだが、周期測定テストプログラム(タイマW使用)にタイマA テストプログラムを合体させることにした。が、ここでハマる。
 タイマA 関連を別ファイルにしてコンパイルしたのだが、動かず。まぁ、割り込み関係だし、とタイマA 関連の関数をコメントアウトして周期測定プログラムを元に戻してコンパイルするも動かず。まさか...。Makefile からタイマA のソースを外すと動く。リンカの問題?タイマA のソースを周期測定プログラムに持ってきて...、それでも同じ。コードが入るだけで(呼び出さなくても)動かない。なぜ??

 今日はこれで 10分オーバー。

 人間、運の総量は決まっているのだろうか、やっぱり。
 今日は朝から頭が痛いが、こういうときこそウォーミングアップの意味がある。
-----
 表示の更新周期 100ms を得るためにタイマwを使おうと思ったが、面倒くさいのでタイマAを使って更新周期を 125ms とする。時間をかければ 100ms を得られるのだが、Project 4 もすでに始まってから一ヶ月以上。あまり長引くと完成する前に飽きてしまう (^^;

 タイマAはあっさり動く。31.25 ms の割込み4発で 125ms を得る目処が立つ。

 タイマwを使って周期を得るところもコーディングは終わり。

 これで部品はすべてそろったので組み合わせようとすると...、最初の部品(周期から周波数への変換)の中身を忘れている。

 今日はここで時間切れ。明日はメモリサイズを考えずに全体をまとめてみたい。
 昨日考えたアルゴリズムを基にコード書く。100行近いコードを書いて、コンパイルエラーになったのは ';' を ':' と typo した一箇所だけ。幸先よい?

 LCD の更新周期の 100ms もタイマW を使って得るつもりだったが、桁^H ビット数が足りない。ちょっと悩みどころ。

 10000rpm まで 1rpm 単位で計測するには、カウンターは、4MHz を入力して 18bit 必要になる。残念ながら H8/3664 のカウンターは 16bit しかないので 2bit をソフトで何とかしなくてはならない。
 単純に 16bit のカウンタがオーバーフローしたところでソフトが管理するカウンタをインクリメントするだけだと、オーバーフローとインプットキャプチャーのタイミングが重なったところで誤動作してしまう。計算すると 16bit のカウンターがオーバーフローするあたりの回転数は、3662rpm。 対策をしないと良く使うエンジン回転数でときたま表示がちらつくという非常にいやらしい不具合になりそうだ。

 同じような仕様のこちらコードを見ると、きちんと対策は打ってあるが H8 と AVR の割り込みコントローラーの仕様の違いからこのままでは使えない。頭を捻ってアウトプットキャプチャーを二本使うロジックを考える。

 今日はここでタイムアップ。明日は今日考えたロジックの検証だ。
 
 今日は H8-3664 のタイマの動作確認。フリーランで走らせて、オーバーフロー割り込みでカウンタをインクリメントさせてみた。あっさり成功。30分も時間が余った。

 こういう状況は考えていなかったので、次にやることが思いつかない (^^;。余った時間で H8OS ドキュメントの 3664 版との正誤表をちょっと作ってみた。
 今日は実際の動作をイメージした LCD表示ルーチンの作成。バーグラフ表示は出来ているし、自前の 10進変換を作れば良いだけのはずだったのだが...。

 現在、表示の時間待ちに H8OS の sleep を使っているのだが、最短の待ち時間が少々長い。ソースを見ると タイマー V を使っているので、パラメータを変更して入力クロックを 1/128 から 1/32 にしようとレジスタを直接アクセスしたのだが...、動かない。2-30分ほどやってみたが原因不明。
 ここでハマって入るわけにもいかないので、途中であきらめ 10進変換ルーチンを作成開始。と、「メモリが足りない」のメッセージが。どうやら 変数÷変数 を実行すると演算ライブラリがリンクされて 200byte 程度コードが増えるようだ。変数÷定数だとリンクされないのだが...。
 アルゴリズムを変え、使っていない LCD アクセスの関数削除したりして何とか動くようになったが、ゼロサプレスが入りそうもない。

 予想外のところに時間をとられて今日は1時間オーバー。

-----
 表示周りはとりあえずここまでにして、明日からは周期測定部に入ろう。まずは車両エミュレーターの作成か。
 今日はコード圧縮の続き。やっている途中で LCD の初期化に失敗する理由がわかった。時間待ちの関数の中の for のダミーループが最適化で無くなっていた orz。for で使う変数を volatile 宣言し、時定数を調整するとオリジナルのソースで問題なく表示できるようになった。本当はオシロを引っ張り出してきて波形を見ながら調整したほうが良いのだが、仕事じゃないし、良いことにしよう (^^;

 IO レジスタのアクセスに構造体を使うのをやめてコードの圧縮も完了。H8 はメモリ間接のアドレッシングで論理演算が出来ないらしく、結構手間取る。ソースはかなり見づらくなったが、1bit 操作するだけで 16byte も使われてはかなわない。
 結局 1K 弱のコードから 100byte 程度削った。

 切のいいところまでやってしまって、今日も 30分の時間オーバー。

 明日は表示部を仮fix 予定。次はいよいよカウンターを使ってパルス間の周期測定だ。

-----
 こういうことをするのなら、アセンブラを使いたいところだが、H8 のアセンブラは未経験。手を広げすぎてプロジェクト自体が収束しなくては本末転倒。

 今日はコード圧縮。40分ほどかけて IOレジスタへの構造体アクセスを外したあと、動かしてみると、動かない (^^;。調べて行くと、どうやら LCD の初期化に失敗している模様。

 やめるにやめられなくなり、時間を延長して調べて行くと、初期化の一番最初のタイミングが早すぎる模様。このままやっていくとエンドレスになりそうなので 40分ほどオーバーしたところ作業中止。

 せっかく変更したコードをほとんど戻してしまった。やっぱり不具合はひとつずつつぶし、変更は一歩一歩確実にいくべきだったか。
 昨日作ったソースを見直してから動かしてみると...、動かない (; ;)。見直しをかけると、CGRAM に送るデータをコマンド(RS=0)として送っていた。そこを直すと無事動いた。フォントもこちらでイメージしたとおり。

 と、ここで不具合発見。自前のプログラムから直で LCD をアクセスするとうまく表示されない。一度 H8OS を使って LCD 表示をしてからだとうまくいく。初期化ルーチンに問題があるのか...。

 それはそれとして、今日の残り時間はコードを短くする検討に入る。
 ネットをあちこち回って調べると、皆さん色々とやっておられる。ソースは「 PIC24Fの紹介と実験」から拝借。データとフォントパターンの関係については、「 LCDのCGRAMに書き込んでみた・・・」のを参考にさせていただいた。

 コンパイルすると、「4byte ほど bss に fit できない」とリンカーがエラーを出してくる。H8OS+3664 だと開発に使える RAM は 1.25KB しかないのだが、もう一杯になってしまったか。ちょっとやりくりしてとりあえずメモリに収める。今日はここで時間切れ。
 マップファイルをちょっと見ると構造体を使った I/O のアクセスはかなりコード効率が悪いみたいだ。いろいろやる価値はありそうだ。
 H8/OS のサポートする LCD アクセスはターミナル型で、任意の位置にアクセスできないので使えない。

 で、「キャラクタ液晶SC1602をテキストRAM形式で扱う」のソースを拝借しようと思ったのだが、こちらは、SC1602 -CPU 間の制御線が2線。せっかく3線つないだので、最下位のアクセスレイヤーは「H8/3694F 液晶パネルを使ってみる」からソースを拝借。
 ポートの割り当てだけをアサインしなおして実行すると...、動かない。よく見るとオリジナルはデータと制御線を別ポートに割り当ててあるせいか、データアクセス時に未使用の bit まで変化させている。今回の回路ではひとつのポートをデータと制御線で使っているのでそのせいで動かなかった。
 そこのところを修正して動かすと...、動いた、んだけど、2行全部に表示させたはずが1行しか表示されない。あれこれ調べること30分、何のことはない、大元で2行表示させたつもりが1行分しかデータを更新していなかった orz。貴重な時間を 30分ほどドブに捨ててしまった。

-----
 今日はドブに捨てた分の30分が時間オーバー。明日は CG-RAM アクセスルーチンのコーディング。
 昨日作った LCD表示プログラムを H8/OS 上のコマンドインタープリターで動くようにあれこれやってみる。
 この環境は何年か前に使ったことがあるのだが、そのときは H8/OS のページにあるLinux 上で動くコンパイラを使ったので割とすんなり行ったのだが、今回は GDL と一緒にインストールした Windows 版の gcc をコマンドラインから使うのでいろいろうまくいかない。

 H8/OS のサンプルプログラムの Makefile と リンカスクリプトを使ったがそのままではコンパイルできない。    

 あれこれやって、結局
   Makefile は    h8300-hms-* -> h8300-elf-*
 ram3664.x は OUTPUT_FORMAT("coff-h8300") ->OUTPUT_FORMAT("elf32-h8300")

 ぐらいでそれらしいヘキサ (*.MOT)ファイルを吐くようになった。

 ちなみにコードサイズ自体は 0x324 byte 。H8/OS + コマンドインタープリター環境ではユーザーの使える RAM サイズは 1.5KByte 程度なので、当分はなんとかなるだろう。

----
 このあとの工程は、
  H/W 作成
  H8/OS をインストールさせてコマンドインタープリタの動作確認
  H8/OS の API を使って LCD 接続確認
  自作 LCD アクセスルーチンのテスト・デバッグ
  パルス幅検出部のコーディング
  車両エミュレーターの作成
  車両エミュレータを使ってのテスト
  全体のコーディング
  車両エミュレータを使ってのテスト
  実車両を使って実パルスを測定
  パルス入力部分の設計・実装
  実車両に積んでテスト

    ....ずいぶんあるなぁ。一日一時間ずつやってるんだけど、何ヶ月かかるか...。
  

  

 

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

track feed Subscribe in a reader
Powered by Movable Type 4.01