- ベストアンサー
H8マイコンのソースでWDTを使っているか確認
- 現在H8S2368のソースコードでウォッチドックタイマを使用しているのか確認したい
- ウォッチドックの動作を確認できず、フリーズする現象を解決するためのコーディング方法も知りたい
- AVRStudioのwdt_enableやwdt_reset関数のようなH8マイコンでのWDT利用方法が知りたい
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
>"#define WATCH_FUNC"という宣言がみつからないので、#else以下が起動しているようです(どちらも同じコードですが・・・) 「WATCH_FUNC」が未定義なら「#ifndef」は「もし未定義ならば」になるので、#elseより「上」が実行されています。 つまり「OS_ENTER_CRITICAL();の無い方」が実行されてます。 >このような値を設定している意味がよくわかりません。 >それぞれのレジスタは8bitのレジスタとH8S2368のデータシートには記述されていますが、16bitの値をを代入しているのでしょうか? レジスタは「バイトサイズ」ですけど「書き込む時はワードサイズで、上位8ビットを特定の値にして書き込みしないと、値がセットされない」ように作られてます。 これは「プログラムが暴走して、メモリを無茶苦茶に書き換えてしまった時」に「不正にレジスタが書き換えられるのを防ぐため」です。 バイトサイズで書き込んだ場合は「書き込み動作が無視される」ようになっていますし、ワードサイズで書き込む時に上位バイトが特定の値以外の時も「書き込み動作が無視される」ようになっています。 読み出す時は「レジスタの中身は書き換えないので、普通にバイトサイズで読み出せば良い」です。 >なので、なぜこれでシステムリセットがかかるのかも不思議です。 これでシステムリセットがかかるのは「ウォッチドックタイマーが正常に働いているから」つまり「無限ループに入って、ウォッチドックタイマーをリセットしなくなるので、ウォッチドックタイマーで割り込みが実行され、割り込みルーチンでシステムリセットされるから」です。 つまり、結論は「ちゃんとウォッチドックタイマーが実装されてる。それでもハングアップするとしたら『どこかで割り込み禁止状態のまま無限ループに落ち込んでる』か、『どこかでウォッチドックタイマーを停止したまま無限ループに落ち込んでる』か、『どこかでウォッチドックタイマーをリセットし続けながら無限ループに落ち込んでる』のどれかだろう」という事です。
その他の回答 (3)
- skp026
- ベストアンサー率45% (1010/2238)
ソースは別として、使っているかどうかは、 デバッガで走らせるだけで確認できそうに思います。 再現環境でなくても良いので、 走らせてブレークかけてWDT設定用のアドレスに、 何が入っているか見れば完了です。 WDTの使用不使用は、フリーズ解決には、 直結する可能性は低いと私も思います。 おそらく大変なのかもしれないですが、 デバッガ環境でフリーズ再現できたら、 調査は進むと思います。 機材持ち込みとか、再現する環境にはりつくとか、 その手のチカラワザが手っ取り早いかもしれないです。
お礼
回答頂きありがとうございます。 とりあえずですが、フリーズした場合でも、とりあえずはウォッチドックがかかってシステムリセット後に通常動作に戻れるような修正を追加してみました。 ただ、テスト環境では現場で問題になったフリーズ現象を完璧に再現することができなかったのが今でも疑問として残っていて、実際にその現象が発生した場合に今回の急場しのぎ的なウォッチドックの使用でちゃんと回避できるのかは少し時間をかけてみてかなければならない可能性がありそうです。 その問題の現象が出た場所が少々遠隔地で、飛行機で行かなないといけないなど、自分たちで直接確認が難しいところというのも苦しいところです。 今回は、現場で設置にあたっていらっしゃる方たちの協力を借りながらという感じです。 多少、インターネット環境で今回の装置を運用していただけると、こちらからクラウド接続で直接経過観察したいと思うのですが、ネット環境はないとのことでした。現場で作業している方からの携帯での通話のみが頼みの綱という感じでその点も少し今回の調査や作業に響いている感じはします。 なかなか時間がかかりそうです。
- chie65536(@chie65535)
- ベストアンサー率44% (8742/19841)
>H8マイコンでも同様のコードなどありますでしょうか? ありますが、それを使わずにWDTを実装している場合があります。 WDTの仕組みは ・初期化ルーチンで、監視用タイマーを初期化して、一定時間経つと割り込みが入るようにしておく。例えば「10秒経過すると割り込みを発生させる」など。 ・メインルーチンなどで、一定間隔(タイマーよりも短い)で必ず通る「待機ルーチン」で、タイマーのリセットを行なう。例えば「必ず1秒以内でタイマーをリセットする」など。 ・割り込み処理ルーチンでは、タイマー割り込みが来たら「メインルーチンがハングアップした」と判断して、CPUをリセットする。 という物です。 これで、メインルーチンが正常動作していれば、1秒ごとにタイマーがリセットされて、割り込みは発生しません。しかし、もし「メインルーチンがハングアップ」すると、タイマーICが「10秒カウント」して「割り込みがかかる」ので、その結果、CPUがリセットされます。 これらの処理を「wdt_enable」や「wdt_reset」などの関数で行なっている場合もあれば、同等の関数を自前で作成して自前で行なっている場合もあれば、関数化しないで、必要なハードウェア制御を直に書いている場合もあります。 なので、結局は「ソースコードを隅々まで読み込まないと、WDTを実装しているかどうか判らない」です。 もしかしたら「タイマーICの制御ポートへの書き込みを、直にメインループの中に書いてあるかも知れない」です。 そして、その「書き込み処理」では「WDT」などのマクロ定義を使わず「定数が直に書いてあるかも知れない」です。なので「ソースコード上で、WDTなどの文字列を探してみる」と言うのも無意味です。 もしかしたら (char *)(0xffc0) = 0xa5; とかって感じで「マクロを使わないで直書きしている」かも知れません。
お礼
回答頂きありがとうございます。 本当に助かります。 新たにわかったことなのですが、複数のソースコードファイルの中でWDTに関するレジスタを操作している関数 void task_reset() という関数があることがわかりました。この関数は複数の箇所で使われており、実行するとシステムリセットしてmain関数からのスタートとして使用されていることがわかりました。 コード内容は下記の内容です。 void task_reset() { int i; #ifndef WATCH_FUNC WDT.WRITE.RSTCSR = 0x5A40; WDT.WRITE.TCSR = 0xA565; WDT.WRITE.RSTCSR = 0xA500; #else WDT.WRITE.RSTCSR = 0x5A40; WDT.WRITE.TCSR = 0xA565; WDT.WRITE.RSTCSR = 0xA500; OS_ENTER_CRITICAL(); #endif while(1); } "#define WATCH_FUNC"という宣言がみつからないので、#else以下が起動しているようです(どちらも同じコードですが・・・) このtask_reset()をmainスタートの後に置いてみたところシステムリセットがかかるようになりました。 ただ、このコードでRSTCSR と TCSRのレジスタに WDT.WRITE.RSTCSR = 0x5A40; WDT.WRITE.TCSR = 0xA565; WDT.WRITE.RSTCSR = 0xA500; このような値を設定している意味がよくわかりません。なので、なぜこれでシステムリセットがかかるのかも不思議です。 それぞれのレジスタは8bitのレジスタとH8S2368のデータシートには記述されていますが、16bitの値をを代入しているのでしょうか? もしよければ引き続きよろしくお願い致します。
- terminator_5
- ベストアンサー率37% (182/487)
システムがフリーズする原因の究明とWDTが使われているか否かの調査は切り離して対応すべき問題ですね。 仮にWDTを有効にすることでフリーズ現象が救済できたとしても、頻繁に再起動を繰り返す不安定なシステムになってしまいます。 通常WDTを使用する場合は、ソースコードの初期化ルーチン内においてWDT関連のレジスタを初期設定してWDTを有効化してからメインルーチンに移行するはずです。 また、メインルーチンは正常動作が行われている限り繰り返し必ず通る箇所においてWDTクリアを行うはずです。 ただし、繰り返しの箇所がタイマー割り込み等のサブルーチンに起因するものであればWDTとしての意味を為さなくなってしまいます。 https://support.renesas.com/hc/ja/articles/210901258-FAQ-1006640-ウォッチドッグ-タイマの基本 実機においてデバッガーが使える環境であれば、初期化終了時点でWDT関連のレジスタの状態から、WDT機能を有効にしているかどうかによって判断が可能です。
お礼
回答頂きありがとうございます。 WDTを使用する際に私もそのような注意点を聞いたことがあります。今回のソースコードが単純な1つのタスクのみならばタイムアップでシステムリセットをかけるのは簡単なのですが、複数のタスクを動かしている場合だとウォッチドックタイマカウントのリセットのタイミングが難しくなるような気はしています。 確か、作成者さんも同様のことを言っていたような気がします。 main関数からスタートしてその後、複数のタスクを起動できるようなuCOSの初期化に関するコードが実行されるのですが、 タスクの1つでわざと while(1); というコードでループ動作を停止させてみても、他のタスクは正常に動作しているため、起動後にはウォッチドックは動作していないのではないかと考えています。 また、新たにわかったのですが、複数のソースコードファイルの中でWDTに関するレジスタを操作している関数 void task_reset() という関数があることが分かりました。この関数は複数の箇所で使われており、実行するとシステムリセットしてmain関数からのスタートとして使用されていることがわかりました。 コード内容は下記の内容です。 void task_reset() { int i; #ifndef WATCH_FUNC WDT.WRITE.RSTCSR = 0x5A40; WDT.WRITE.TCSR = 0xA565; WDT.WRITE.RSTCSR = 0xA500; #else WDT.WRITE.RSTCSR = 0x5A40; WDT.WRITE.TCSR = 0xA565; WDT.WRITE.RSTCSR = 0xA500; OS_ENTER_CRITICAL(); #endif while(1); } "#define WATCH_FUNC"という宣言がみつからないので、#else以下が起動しているようです(どちらも同じコードですが・・・) このtask_reset()をmainスタートの後に置いてみたところシステムリセットがかかるようになりました。 ただ、このコードでRSTCSR と TCSRのレジスタに WDT.WRITE.RSTCSR = 0x5A40; WDT.WRITE.TCSR = 0xA565; WDT.WRITE.RSTCSR = 0xA500; このような値を設定している意味がよくわかりません。なので、なぜこれでシステムリセットがかかるのかも不思議です。 それぞれのレジスタは8bitのレジスタとH8S2368のデータシートには記述されていますが、16bitの値をを代入しているのでしょうか? もしよければ引き続きよろしくお願い致します。
お礼
回答頂きありがとうございます。 ”#ifndef” この件に関しましてご指摘頂き大変ありがとうございました。 完全に見落としていました。 てっきり”OS_ENTER_CRITICAL();”がある方で動作していると勘違いしていました。再度確認したいと思います。 void task_reset() { int i; #ifndef WATCH_FUNC WDT.WRITE.RSTCSR = 0x5A40; WDT.WRITE.TCSR = 0xA565; WDT.WRITE.RSTCSR = 0xA500; #else WDT.WRITE.RSTCSR = 0x5A40; WDT.WRITE.TCSR = 0xA565; WDT.WRITE.RSTCSR = 0xA500; OS_ENTER_CRITICAL(); #endif while(1); } この内容を実行すると、 TCNT (前)00--->(変更後)01(FFFFBD番地) TCSR (前)18--->(変更後)7F(FFFFBC番地) RSTCSR (前)---->(変更後)5F(FFFFBF番地) このように値を変更して、ウォッチドックが有効に機能していることを確認できました。 とりあえず、ソースコード上には用意されていた void InitWatchDog() { #ifdef WATCH_FUNC WDT.WRITE.RSTCSR = 0x5A40; WDT.WRITE.TCSR = 0xA567; WDT.WRITE.RSTCSR = 0xA500; #endif } void ClearWatchDog() { #ifdef WATCH_FUNC WDT.WRITE.TCSR = 0x5A00; WDT.WRITE.RSTCSR = 0xA500; #endif } この2つの関数を使用することでシステム起動後すぐにInitWatchDog()関数でウォッチドックを起動して、特定のタスク内の永久ループでClearWatchDog()関数でウォッチドックタイマをクリアしていって暴走時に備えようと思っております。 それと、書き込み時のWDTの16バイトに関しても解説頂きありがとうございました。