他のスレッドで「H8/36094:IRQ0の処理が起動しないことがある」というのを見かけましたが
SH7670で下記のようなソースで自作関数を作成しています
ソースここから→
/////////////////////////////////////////////////////////////////////////タイマを設定するTIME_PROC tproc[]={{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},};BOOL bWaitTimer=FALSE;BOOL WaitTimer(int msec,void (*pc)()){ int i; CMT.CMSTR.BIT.STR1=0;//タイマ停止 for(i=0; i<10; i++){ if(tproc[i].msec ==0){ tproc[i].msec =msec; tproc[i].pc =pc; //1m Sec タイマ開始 if(!bWaitTimer){ bWaitTimer=TRUE; cpu_ms1_start //タイマを開始させるマクロ } CMT.CMSTR.BIT.STR1=1;//タイマ開始 return TRUE; } } //登録できない return FALSE;}/////////////////////////////////////////////////////////////////////////////////////1mSインターバルタイマvoid cmi1_(void){ BOOL flg; int i; void (*pc)(); CMT.CMCSR1.BIT.CMF &= 0; CMT.CMSTR.BIT.STR1=0; flg=FALSE; for(i=0; i<10; i++){ if(tproc[i].msec > 0){ tproc[i].msec--; if(tproc[i].msec == 0){ pc = tproc[i].pc; tproc[i].pc=0; pc(); } } if(tproc[i].msec > 0)flg=TRUE; } if(!flg){ bWaitTimer=FALSE; return; } CMT.CMCSR1.WORD=0; CMT.CMCNT1.WORD=0; CMT.CMCOR1.WORD=1000; CMT.CMCSR1.BIT.CKS=1;//11:Pφ/512 CMT.CMCSR1.BIT.CMIE=1; CMT.CMSTR.BIT.STR1=1; cpu_ms1 ++;}/////////////////////////////////////////////////////////////////////////タイマ関数 end///////////////////////////////////////////////////////////////////////
→ソースここまで、これを使用するには
void test(void)
{
}
に飛ばしたい場合に
WaitTimer(100, &test );
等とすると、100ミリ秒後にtest()が実行されるという仕組みですが
どうやらたまに実行されない場合があるということで、なにが原因なのか思案しています
アドバイスお願いできませんでしょうか?
Higetakaさん ご丁寧に説明してくださり、一時的に「割り込み禁止」ということだったんですね、 「タイマを停止しても、直前に割り込み要因が成立していれば、 割り込みは発生します。cmi1_関数が実行されるとタイマは再び 動作し始めます。そしてこの後の処理でも割り込みががんがん 発生する可能性があります。タイマ登録した関数の処理時間が 合計で1msを超えれば、数回の割り込みがこの後で発生する かもしれません。」 なるほど、そうですね、この現象が発生するのは、複数登録している場合に限らず発生します、例えば極端にTIME_PROC tproc[]を廃止してシングルにしても不都合が発生するのを確認しています。
わわいです >遅延関数で実行されるのはLEDを消すためにポートをLOWにするとか、実行フラグをFALSEにするとかの後処理です で、あればいいんでしょうけどねえ。 そういう自分のコードの中の約束事をずっと覚えておけばいいんです。そこの関数を登録するときに、ここは割り込み内だから、変数を使うときはメインルーチンとの輻輳を気にしなければならない、スタックを使いすぎないように、時間がかかる処理はだめ、かんたんな処理しか登録できない、と。 まあ、それで今組んでるやつに関しては大丈夫かもしれないです。きちんと動いているならそれでOKOK。 しかし、半年たって修正の必要が出たときにそれをキチンと覚えておけるか、とか、会社に新人が入ってきて、そのコードを引き継いだときにどーなるか、 あるいは別の仕事で、ああ、タイマルーチンは前に組んだこれあるからそのままもってきたらいいぢゃん、ああ、ちゃんと動くし、わざわざ組まなくてラッキやねー とかなんとか考えていくと、なんか暗いストーリーしか思い浮かばないですねー
現状のコードでは 「合計で1msを超えれば、数回の割り込みがこの後で発生するかもしれません。」 というのは、ないかもしれないと思えてきました。 (割込み側でタイマを停止してから関数呼び出しをしているので) 今のコードの延長でも、資源管理をしっかりすれば、なんとかなると思いますよ。 管理するべき資源はタイマ(CMT)とテーブル(tproc)です。 WaitTimerは急に割り込まれても大丈夫なように割り込み禁止でガードをかけるのがポイントです。 (但し、禁止期間はなるべく短くしたいものです。他の緊急な割り込みが遅れたりする事があるので) 今の延長で私がデザインするとしたら、以下のような疑似コードにします。 // IKUZOさんのコードとほぼ同じ // 但し、CMTの制御はStartだけ行う。 WaitTimer() { ★ タイマ停止は行わない for (i) { if (tproc[i]が未使用) { ★ テーブル&CMT制御は割り込みに邪魔されないようにする。 disable_irq テーブル登録 if (CMT停止中) { CMT Start } enable_irq } } ★ タイマ再開は行わない } // IKUZOさんのコードとほぼ同じ // 但し、CMTの制御はStopだけ行う。 cmi1_() { ★ タイマ停止は行わない waiting = false; for (i) { if (tproc[i].msec > 0) { tproc[i].msec--; if(tproc[i].msec == 0){ func呼び出し } } if (tproc[i].msec > 0) waiting = true; } ★ 有効な登録がなければ停止する if (!waiting) { CMT Stop } ★ タイマ再開は行わない }