PSoC 4には、ウォッチドッグタイマ(Watch Dog Timer: WDT)というブロックがあります。この記事では、WDTをウォッチドッグとして使う方法をPSoC 4200DSを題材に考えます。
そもそもウォッチドッグとは、
ウォッチドッグというのは、番犬の意味です。この番犬は、餌があればおとなしいのですが、餌をやり忘れると吠えてきます。それは、本当に番犬なのか?一般的には、吠えられたMCUは、リセットがかかります。この仕組みを使うと、エサ係が何らかの事情(通常は暴走)で餌を持ってこなくなった非常事態を検出してリセットをかけることができます。
ウォッチドッグの仕組みでは、ある決められた時間までに餌をもらったかどうかを判別する必要があります。この時間を測定するため、数十kHzの内蔵クロックを数える比較的長周期のタイマを装備しています。
ウォッチドッグタイマの用途
このような長周期タイマは、一般的な周期割り込みとしても使い勝手が良いので、PSoC 4では、多くの場合、ウォッチドッグタイマを周期タイマとして使用しています。初期の高性能PSoC 4の場合には、WDTの中にタイマカウンタが3系統も存在し、それぞれが周期タイマ割り込みとしてもウォッチドッグリセットとしても使えるようになっていました。
PSoC 4100M/4200M Family PSoC 4 Architecture TRM, Document No. 001-95223
ところが、最近のPSoC 4では、もっと簡素な作りのウォッチドッグタイマが使われるようになりました。
PSoC 4200D Family PSoC 4 Architecture TRM, Document No. 001-98108
いや、なんか省略しすぎでしょう。
この図が描かれた文章には、16ビットのアップカウンタで出来ていて、MATCHレジスタとMASKレジスタで希望の周期が得られると書いてあります。
このウォッチドッグタイマは、リセットに使ってしまうと、事実上周期タイマには使えなくなります。周期タイマとしての使用例はあふれているので、この記事では、この簡素なウォッチドッグタイマをウォッチドッグとして使う方法を提供します。
回路図
ウォッチドッグを使うのだから、回路図にウォッチドッグコンポーネントを配置して…なんてことはありません。回路図には、ウォッチドッグに特有なものは何も必要ありません。
回路図においてあるコンポーネントは、非常事態をエミュレーションするためのスイッチ入力とリセットの要因を表示させるためのUARTだけです。
代わりに必要なのは、クロック設定です。"Low Frequency Clocks"タブで"Timer (WDT)"にチェックを入れて有効にします。そして、"Mode"を"Watchdog (w/ Interrupt)"に設定してウォッチドッグリセットとウォッチドッグ割り込みを有効にします。このプロジェクトでは割り込みは必要ないのですが、このチップでは片方だけ有効にするという選択肢がありません。割り込みの方は、"Unmask"しなければ動かないので、この設定で問題ありません。
タイマの周期を819.2msにしたので、少なくとも3倍の時間、約2.4秒間エサをやらないとリセットがかかります。
ファームウェア
ファームウェアにあるのは、main()
関数のみです。
# include "project.h"
# include <stdio.h>
int main(void)
{
uint32 reason;
char sbuf[64];
CyGlobalIntEnable; /* Enable global interrupts. */
/* Place your initialization/startup code here (e.g. MyInst_Start()) */
UART_Start();
UART_UartPutString("\r\nHELLO WORLD\r\n");
reason = CySysGetResetReason(CY_SYS_RESET_WDT | CY_SYS_RESET_PROTFAULT | CY_SYS_RESET_SW);
strcpy(sbuf, "RESET REASON:");
if (reason & CY_SYS_RESET_WDT) {
strcat(sbuf, " WDT");
}
if (reason & CY_SYS_RESET_PROTFAULT) {
strcat(sbuf, " FAULT");
}
if (reason & CY_SYS_RESET_SW) {
strcat(sbuf, " SW");
}
strcat(sbuf, "\r\n");
UART_UartPutString(sbuf);
前半では、 リセット要因を調べてUARTに出力します。
HELLO WORLD
RESET REASON:
HELLO WORLD
RESET REASON: WDT
リセット要因に何も書かれていなければ、通常のハードウェアリセット。WDTと書かれていればウォッチドッグリセットがかかったことを示します。
このプロジェクト例では、他のリセット要因も検出できるようになっていますが、このプロジェクト例のままでは他のリセット要因は発生しないはずです。
for(;;)
{
/* Place your application code here. */
if (Pin_SW1_Read()) {
CySysWdtClearInterrupt();
}
CyDelay(100);
}
}
後半では、メインループ内でウォッチドッグに餌をやっています。餌をやる条件は、スイッチ入力が"High"すなわちタクトスイッチが押されていない事です。タクトスイッチを押さずに放置していれば、ウォッチドッグリセットはかかりません。また、タクトスイッチを2.4秒間押しっぱなしにすると、ウォッチドッグリセットがかかります。
ウォッチドッグに餌をやるための関数がCySysWdtClearInterrupt()
です。関数の名前からはウォッチドッグに餌をやるための関数だとはとても想像できませんが、ウォッチドッグ割り込みと共用している関係上しかたがありません。気に入らなければ、マクロを使って違う名前で呼び出せるようにしましょう。
このプロジェクト例では、100ミリ秒ごとに餌をやっていますが、あまり意味はありません。重要なのは、周期的にメインループの中で餌をやって、メインループがどこかで止まっていないかを監視させることです。
GitHub リポジトリ
関連記事
PSoC 40xx でウォッチドッグ・タイマを使ってみる
新・ウォッチドッグタイマを使ってみる ~PSoC 42xx 編~
新・ウォッチドッグタイマを使ってみる ~PSoC 40xx 編~