かみやんの技術者ブログ

主にプログラムの話です

Toppers/JSPで割り込み・2相ロータリーエンコーダー

ロボットづくりの時間を作るのが大変。この作業も以前にやった作業。書く時間がなかなかとれない。さて、
http://d.hatena.ne.jp/kamiyan2/20090516
このエントリで、2相ロータリーエンコーダのハードウェアはできたので、次はファームウェアマイコンは、H8/3069Fなので、位相計数モードが1chしかない。位相計数モードというのは、カウンタ回路なのだがロータリーエンコーダ用ともいえるアップダウンカウンタ。位相計数の実装には次の方法がある。

  1. ハードウェアの位相計数モード(ペリフェラル)を使う
  2. 方形波の立ち上がり、立ち下がりで割り込みをかけて、インクリメント・デクリメントはソフトウェアで行う
  3. 割り込みではなく、方形波が入ってくる入力ピンの電圧をポーリングする

の3択。H8/3069は位相計数モードが1chしかないので、ステアリング式のロボットには問題ないが、私のAibiは独立二輪駆動なので、2ch必要。という訳で、2の割り込みで行く。

Toppers/JSPで割り込みは、cfgファイルに静的関数のDEF_INHで関数を定義。
が、ビルドして実行するとどうも割り込みハンドラ関数が呼ばれていない。
Aibiのシステムは、マイコン起動するたびにRAMにファームウェアをロードするタイプなので、仮想割り込みテーブルもRAMにあるので、割り込みテーブルの内容を直接書き換えることにした。
具体的には、

extern long vectors[64];

という感じでグローバル変数のvectorsを参照宣言して、

vectors[36]=(long)TimerHandler_CMIA0_entry;//仮想割り込みベクタの書き換え
vectors[38]=(long)TimerHandler_CMIA1_entry;//仮想割り込みベクタの書き換え

みたいな感じで、割り込みテーブルを書き換え。
ちなみに割り込みハンドラ関数は、

//割り込みハンドラ(CMIA0、vector36)
void TimerHandler_CMIA0()

というプロトタイプだが、ビルドしてシンボルファイルjsp.symsをみると

  00400aba T _TimerHandler_CMIA0
  00400b02 T _TimerHandler_CMIA0_disable_int
  00400aea T _TimerHandler_CMIA0_enable_int
  00402286 T _TimerHandler_CMIA0_entry
  0040230a t _interrupt_from_int_TimerHandler_CMIA0

という具合に自分の作った関数以外に、_disable_int,_enable_int,_entry,_interrupt_from_int_という関数(またはアセンブラのラベル)ができている。
よくToppersカーネルソースを見てみると、マクロで自動的に関数(やアセンブラのラベル)ができているようだ。
仮想関数テーブルを書き換える場合は、_entryでよいようだ(H8のcpu_config.h参照)。当初フリーズ多発で全く動かなかったがなんとか動くようになったソースが下記。

//割り込みハンドラ(CMIA0、vector36)
void TimerHandler_CMIA0()
{
	//TCSR(タイマコントロールステータスレジスタ)のCMFA(コンペアマッチフラグA)を下ろす
	//sil_anb_mem((VP)(H88TCSR0),~H88TCSR_CMFA);
	uint8 b=(*((volatile VB *) H88TCSR0));
	(*((volatile VB *) H88TCSR0))=b & ~H88TCSR_CMFA;
	g_countL++;
}

void TimerHandler_CMIA0_enable_int()
{
	//割り込みON
	//sil_orb_mem((VP)(H88TCR0),H88TCR_CMIEA);
	uint8 b=(*((volatile VB *) H88TCR0));
	(*((volatile VB *) H88TCR0))=b | H88TCR_CMIEA;
}

void TimerHandler_CMIA0_disable_int()
{
	//割り込み停止
	//sil_anb_mem((VP)(H88TCR0),~H88TCR_CMIEA);
	uint8 b=(*((volatile VB *) H88TCR0));
	(*((volatile VB *) H88TCR0))=b & ~H88TCR_CMIEA;
}

が、しかしロータリーエンコーダを回すとインクリメントされるが、素早く回すとフリーズ。
困りました。
どうもマクロで自動展開されて作られるTimerHandler_CMIA0_entryのアセンブラソースを見る限り、ここが重そうです。割り込みがかかって割り込み禁止する前に次の割り込みがかかってフリーズではないかと推定しています。このTimerHandler_CMIA0_entry関数の中でミューテックスだったかセマフォだったかの同期処理もしています。いかにも遅そう。ロータリーエンコーダのカウントは、非常に短い時間で多発するのでOSと排他処理しながらカウントするのは無理そうです。

困りました。次の手をどううつか。

  1. Toppers/JSPをやめてOSなしにする(アップダウンカウンタは、割り込み)
  2. ハードウェアで位相計数カウンタが2chあるマイコンに変える

迷いましたが、マイコンを変えることにしました。今まで書いたファームウェアが作りなおしになりますが、割り込みによるソフトウェアでのアップダウンカウンタは、素早くロータリーエンコーダを回したときにフリーズしたり、カウントミスする可能性が高いと判断しました。

で、マイコン調査。もやねさんが、AVRいいよ〜位相計数2chとか結構あるし。とのことでしたが、H8で慣れた面もあるので同じルネサステクノロジーのSHにすることにしました。
秋月のSH7125 4,800円にしました。

開発環境も、「Toppers/JSPテキストエディタgcc」から「HEW+OSなし」に変更。
RAMが2Mbyteから8kbyteへダウンのため、RAMにプログラムをロードするタイプからROM書き込みベースになります。
さて、どうなるか。

#あとで検索したら、だるまさんもSH7125なのね。安心。