AKI-H8のウォッチドッグタイマの利用
自分でスタートアップおよび割り込みベクタテーブルを管理する中級者向け
簡単コマンドh8ccBasic.cmd利用版

Copyright(C)15Dec2003
coskx


1.はじめに
この文書はH8/3048におけるウォッチドッグタイマの利用を解説したものである。この内蔵タイマはタイマ割り込みとウォッチドッグタイマとして動作する。
ウォッチドッグタイマとは,一定時間内にカウンタをリセットしないとカウンタがオーバーフローし,その時CPUにリセットがかかるものである。プログラム中に一定時間内にカウンタリセット命令を埋め込んでおき,異常動作時にはカウンタがクリアされなくなるので,CPUリセットを起こすような使い方がされる。

プログラムのダウンロード

プログラムのダウンロード 
ウォッチドッグタイマ
DownLoad
プログラムのダウンロード 
タイマ割り込み
DownLoad


 

本文書で記述してある作業の特徴
startupBasicの環境を用います。

2.ウォッチドッグタイマサンプルプログラム

制御プログラムが暴走すると危険なことがおこります。これをある程度防ぐ目的で監視するのがウォッチドッグタイマです。動作は単純で,8ビットカウンタがアップカウントし,オーバーフローしたらCPUがリセットされてしまうからくりです。プログラムが正常に動作している場合は,適当な間隔で,この8ビットカウンタをクリアするとオーバーフローしないので,CPUはリセットされることなく動作します。しかし,プログラムの不具合で8ビットカウンタをクリアしなくなると,オーバーフローが生じ,CPUがリセットされてしまいます。

サンプルプログラムでは無限ループ中で,カウンタをクリアしていますが,シリアル通信から1文字受け取ると,内部無限ループに落ち込み,カウンタをクリアを行なわなくなるため,オーバーフローが生じ,CPUがリセットされてしまいます。そして最初から再び動作します。

ウォッチドッグタイマ割り込みによるオーバーフローリセット

/**********************************************************
ウォッチドッグタイマ割り込みによるオーバーフローリセット
**********************************************************/
#include "h8-01.h"

typedef union {
    unsigned char BYTE;        /*  Byte Access */
    struct {                   /*  Bit  Access */
        unsigned char OVF :1;  /*    OVF       */
        unsigned char WTIT:1;  /*    WT/IT     */
        unsigned char TME :1;  /*    TME       */
        unsigned char     :2;  /*              */
        unsigned char CKS :3;  /*    CKS       */
    } BIT;
} TCSR_t;
typedef union {
    unsigned char BYTE;        /*  Byte Access */
    struct {                   /*  Bit  Access */
        unsigned char WRST :1; /*    WSRT      */
        unsigned char RSTOE:1; /*    RSTOE     */
    } BIT;
} RSTCSR_t;

/* WDT TCSR Byte Read Address*/
#define WDT_TCSR_BREAD (*(volatile TCSR_t *)0xFFFFA8)
/* WDT TCSR Word Write Address*/
#define WDT_TCSR_WWRITE (*(volatile unsigned int *)0xFFFFA8)
/* WDT RSTCSR Byte Read Address*/
#define WDT_RSTCSR_BREAD (*(volatile RSTCSR_t *)0xFFFFAB)
/* WDT RSTCSR Word Write Address*/
#define WDT_RSTCSR_WWRITE (*(volatile unsigned int *)0xFFFFAA)
#define writeWDT_TCSR(x) (WDT_TCSR_WWRITE=0xa500+x)
#define clearWDT_TCNT() (WDT_TCSR_WWRITE=0x5a00)
#define clearWDT_WRST() (WDT_RSTCSR_WWRITE=0xa500)

/*--------------------------------------------------
ウォッチドッグタイマリセット動作の初期化
intervalIndex: 0..7
0:φ/2      0.000032[sec] 31250回で1秒
1:φ/32     0.000512[sec] 1953.125回で1秒
2:φ/64     0.001024[sec] 976.5625回で1秒
3:φ/128    0.002048[sec] 488.28125回で1秒
4:φ/256    0.004096[sec] 244.140625回で1秒
5:φ/512    0.008192[sec] 122.0703125回で1秒
6:φ/2048   0.032768[sec] 30.51757813回で1秒
7:φ/4096   0.065536[sec] 15.25878906回で1秒
(システムクロック16MHzの場合)
関数の返す値
1: ウォッチドッグタイマによるリセットがあったことを検出した
0: ウォッチドッグタイマによるリセットがあったことを検出していない
---------------------------------------------------*/
int initWatchdogTimer_forReset(int intervalIndex)
{
    int detected_WDTreset;
    TCSR_t tcsr;
    detected_WDTreset=WDT_RSTCSR_BREAD.BIT.WRST;
    clearWDT_WRST(); /*WRSTのクリア*/
    clearWDT_TCNT(); /*カウンタリセット*/

    tcsr=WDT_TCSR_BREAD;
    tcsr.BIT.TME=0; /*タイマ・割り込みディスエイブル*/
    writeWDT_TCSR(tcsr.BYTE);
    tcsr.BIT.CKS=(intervalIndex&0x7); /*クロック選択*/
    tcsr.BIT.WTIT=1; /*ウォッチドッグタイマとして使用*/
    tcsr.BIT.TME=1; /*タイマ・割り込みイネイブル*/
    writeWDT_TCSR(tcsr.BYTE);
    return detected_WDTreset;
}

main()
{
    static char *str[]={"*Power On Start*","*Watchdog Timer Reset*"};
    int ret;
    initLed();
    initSCI1();
    SCI1_printf("\n\n          *** Watchdog Timer Demonstration ***\n");
    SCI1_printf("The loop operation has started,");
    SCI1_printf(" and it keeps on clearing watchdog timer every loop.\n");
    SCI1_printf("If any key is hit, the loop doesn't clear watchdog timer.\n");
    SCI1_printf("It will cause 'RESET' next moment.\n");
    ret=initWatchdogTimer_forReset(7); /*timeout=0.065536[sec]*/
    SCI1_printf("%s is detected when watchdog timer is initialized\n",str[ret]);
    while(1){
        clearWDT_TCNT(); /*カウンタリセット*/
        if (0<chkgetCharSCI1()) { /*SCIの入力チェック 0以上なら入力あり*/
            SCI1_printf("\nSCI has recieved a code. ");
            SCI1_printf("Watchdog timer wont be clear any more.\n");
            while (1); /*無限ループに突入*/
        }
    }
}

ハイパーターミナルの実行時画面

          *** Watchdog Timer Demonstration ***
The loop operation has started, and it keeps on clearing watchdog timer every lo
op.
If any key is hit, the loop doesn't clear watchdog timer.
It will cause 'RESET' next moment.
*Power On Start* is detected when watchdog timer is initialized

[ここで何かのキーが押された]
SCI has recieved a code. Watchdog timer wont be clear any more.

[ここでタイマオーバフローが起こりCPU]がリセットされ初期表示に戻る]

          *** Watchdog Timer Demonstration ***
The loop operation has started, and it keeps on clearing watchdog timer every lo
op.
If any key is hit, the loop doesn't clear watchdog timer.
It will cause 'RESET' next moment.
*Watchdog Timer Reset* is detected when watchdog timer is initialized

[ここで何かのキーが押された]
SCI has recieved a code. Watchdog timer wont be clear any more.

[ここでタイマオーバフローが起こりCPU]がリセットされ初期表示に戻る]

          *** Watchdog Timer Demonstration ***
The loop operation has started, and it keeps on clearing watchdog timer every lo
op.
If any key is hit, the loop doesn't clear watchdog timer.
It will cause 'RESET' next moment.
*Watchdog Timer Reset* is detected when watchdog timer is initialized

フォルダの内容
h8-01.h           サービス関数類
h8ccBasic.cmd     コンパイル&ゴーコマンド
StartupBasic.src  スタートアップルーチン(割り込み関係はサポートしていない)
h8_3048.sub       リンカスクリプト(リンカサブコマンド)
WDT_ResetDemo.c   サンプルプログラムのCソース
to_H8.ht          ハイパーターミナル設定ファイル
readme.txt        説明ファイル

3. タイマ割り込みサンプルプログラム

ウォッチドッグタイマを通常のタイマ割り込みに使うことも出来る。しかしオーバーフロー割り込みのみなので,周期を自由に設定できない。周期を自由に設定したい場合はITUのタイマー割り込みを用いると良い。

ウォッチドッグタイマ割り込みによってLEDのON-OFFを行う

/**********************************************************
ウォッチドッグタイマ割り込みによってLEDのON-OFFを行う
**********************************************************/
#include "h8-01.h"

typedef union {
    unsigned char BYTE;        /*  Byte Access */
    struct {                   /*  Bit  Access */
        unsigned char OVF :1;  /*    OVF       */
        unsigned char WTIT:1;  /*    WT/IT     */
        unsigned char TME :1;  /*    TME       */
        unsigned char     :2;  /*              */
        unsigned char CKS :3;  /*    CKS       */
    } BIT;
} TCSR_t;
/* WDT TCSR Byte Read Address*/
#define WDT_TCSR_BREAD (*(volatile TCSR_t *)0xFFFFA8)
/* WDT TCSR Word Write Address*/
#define WDT_TCSR_WWRITE (*(volatile unsigned int *)0xFFFFA8)
#define writeWDT_TCSR(x) (WDT_TCSR_WWRITE=0xa500+x)

/*--------------------------------------------------
ウォッチドッグタイマ割り込みの初期化
intervalIndex: 0..7
0:φ/2      0.000032[sec] 31250回で1秒
1:φ/32     0.000512[sec] 1953.125回で1秒
2:φ/64     0.001024[sec] 976.5625回で1秒
3:φ/128    0.002048[sec] 488.28125回で1秒
4:φ/256    0.004096[sec] 244.140625回で1秒
5:φ/512    0.008192[sec] 122.0703125回で1秒
6:φ/2048   0.032768[sec] 30.51757813回で1秒
7:φ/4096   0.065536[sec] 15.25878906回で1秒
(システムクロック16MHzの場合)
---------------------------------------------------*/
void initWatchdogTimerINT(int intervalIndex)
{
    TCSR_t tcsr;
    tcsr=WDT_TCSR_BREAD;

    tcsr.BIT.TME=0; /*タイマ・割り込みディスエイブル*/
    writeWDT_TCSR(tcsr.BYTE);
    tcsr.BIT.CKS=(intervalIndex&0x7); /*クロック選択*/
    tcsr.BIT.WTIT=0; /*インターバルタイマとして使用*/
    writeWDT_TCSR(tcsr.BYTE);
}

void startWatchdogTimer(void)
{
    TCSR_t tcsr;
    tcsr=WDT_TCSR_BREAD;
    tcsr.BIT.TME=1; /*タイマ・割り込みイネイブル*/
    writeWDT_TCSR(tcsr.BYTE);
}

main()
{
    initLed();
    initWatchdogTimerINT(5); /*タイマ割り込み0.008192[sec]*/
    E_INT();        /*CPU割り込み許可*/
    startWatchdogTimer();  /*時間割り込みタイマスタート*/
    while(1);       /*なにもしないループ*/
}

#pragma interrupt(watchdogTimerINT)/*この名前の関数は割込ルーチン仕様である*/
                                   /*プログラム中から呼び出してはならない*/
void watchdogTimerINT() /*割り込みルーチンの名前はIntTbl.srcで定義されている*/
{
    TCSR_t tcsr;
    static int loop=0;
    static int tick=0;
    if (loop==0) {
        if (tick==1) {
            turnOnLed(0);
            turnOffLed(1);
        } else {
            turnOffLed(0);
            turnOnLed(1);
        }
        tick=1-tick;
    }
    if (++loop==122) loop=0;
    tcsr=WDT_TCSR_BREAD;
    tcsr.BIT.OVF=0;
    writeWDT_TCSR(tcsr.BYTE);
}

フォルダの内容
h8-01.h           サービス関数類
h8ccBasic.cmd     コンパイル&ゴーコマンド
StartupBasic.src  スタートアップルーチン(割り込み関係はサポートしていない)
h8_3048.sub       リンカスクリプト(リンカサブコマンド)
IntTbl.src        割り込みベクタテーブルのソース
WDT_IntervalTimerDemo.c   サンプルプログラムのCソース
to_H8.ht          ハイパーターミナル設定ファイル
readme.txt        説明ファイル