Timer Watchdog

Funktion

Der Watchdog-Timer stellt eine Schutzfunktion dar, die den Mikrokontroller im Falle des Festhängens in einem Fehlerzustand per Reset wieder in einen definierten Ausgangszustand zurückbringen kann. Ein Zähler wird fortlaufend inkrementiert, bis er einen voreingestellten Wert erreicht, bei dessen Erreichen ein globaler Reset erfolgt. Der Zähler kann nur zurückgesetzt werden, indem ein bestimmtes Datenwort in das dafür vorgesehene Register geschrieben wird. Der Zähler zählt mit dem Timertakt, der noch durch einen Vorteiler geregelt werden kann.

Register

OffsetRegisterFunktionZugriff
0WDT_CTRLSteuerregisterread/write
1WDT_DATEnde Wert des Zählersread/write
2WDT_CHKPasswort zum Rücksetzen des Zählers.write
2WDT_CNTZählerread

Das Steuerregister WDT_CTRL enthält alle zur Steuerung der Funktionen des Watchdog-Timer-Moduls nötigen Bits. Bei einem Reset werden alle Bits mit Null initialisiert. Auf das Register kann lesend und schreibend zugegriffen werden. Bei einem durch das Signal Alarm ausgelöstem Reset wird Bit 5 gesetzt und kann damit beim Neustart abgefragt werden.
Das Vergleichsregister WDT_DAT enthält den Wert, bis zu dem der Watchdog-Timer zählt, bevor ein Reset ausgelöst wird. Bei einem Reset werden alle Bits mit Null initialisiert. Auf das Register kann lesend und schreibend zugegriffen werden.
Wird in das Register WDT_CHK die im Parameter WDT_CODE konfigurierte Bitfolge geschrieben, dann erfolgt ein Zurücksetzen des Watchdog-Zählers auf Null. Bei einem Reset werden alle Bits mit Null initialisiert. Auf das Register kann nur schreibend zugegriffen werden.

WDT_CTRLFunktion
Bit 0: Watchdog enable: 0 = disable, 1 = enable
Bit 1: Teiler enable: 0 = disable, 1 = enable
Bit 2 bis 4: Vorteiler:
000: 2¹
001: 2²
010: 2³
011: 2⁴
100: 2⁵
101: 2⁶
110: 2⁷
111: 2⁸
Bit 5: = 1 nach einem ALARM, wird beim schreiben immer gelöscht.
Bit 6 bis 17: nicht benutzt


watchdog.h

#ifndef __WATCHDOG_H
#define __WATCHDOG_H

#define WATCHDOG_EN         (1<<0)
#define WATCHDOG_PRE_EN     (1<<1)
#define WATCHDOG_PRE_VAL    (1<<2)          // *0 fuer 2^1  bis *7 fuer 2^8

#define WATCHDOG_PRE_2      (WATCHDOG_PRE_VAL * 0)
#define WATCHDOG_PRE_4      (WATCHDOG_PRE_VAL * 1)
#define WATCHDOG_PRE_8      (WATCHDOG_PRE_VAL * 2)
#define WATCHDOG_PRE_16     (WATCHDOG_PRE_VAL * 3)
#define WATCHDOG_PRE_32     (WATCHDOG_PRE_VAL * 4)
#define WATCHDOG_PRE_64     (WATCHDOG_PRE_VAL * 5)
#define WATCHDOG_PRE_128    (WATCHDOG_PRE_VAL * 6)
#define WATCHDOG_PRE_256    (WATCHDOG_PRE_VAL * 7)

#define WATCHDOG_ALARM      (1<<5)

typedef struct wdt {
        volatile unsigned int control;  // (r/w)
        volatile unsigned int limit;    // (r/w)
        volatile unsigned int val_rst;  // (r = val / w PIN = rst)
} watchdog_regs_t;
#endif

Konfiguration und Instanziierung


Bei der Instanziierung eines Watchdog-Timer-Moduls gibt es zwei Parameter, die man einstellen muss: BASE_ADR und WDT_CODE. BASE_ADR gibt den Offset der Adresse des Moduls zur Basisadresse der Peripherieregister an. Der Wert besteht aus den oberen sieben Bit der zehn Bit-Adresse eines Moduls (die unteren drei Bit werden nur modulintern benutzt). WDT_CODE ist das 18 Bit-Passwort, dass in das WDT_CHK-Register geschrieben werden muss, um einen Reset zu verhindern.

Der Watchdog-Timer hat zwei Taktleitungen, eine für den prozessorsynchronen Takt (clk_i) und eine für den externen Takt (clk_x). Als clk_i kann clk_peri oder der Ausgang einer TIMER-RTI-Kette verwendet werden. Der externe Takt wird benötigt, um das Resetsignal lange genug zu halten, so dass die DCM einen korrekten Reset ausführen können. Der Takt (clk_x) muss währen RESET aktiv ist ständig anliegen! Geeignet sind dafür die Signale der CLK-Generatoren des Boards.
Der Resetausgang des Moduls alarm muss an die entsprechende Resetleitung des SpartanMC angeschlossen werden.

Einstellungen für den Timer Watchdog



Ausschnitte aus dem Testprogramm wd_test.c für die Förderband3 Konfiguration

// Startwert fuer die Zyklenanzahl der Watchdog Warteschleife
#define ZYKSTART        259900

void main(void) {

        // Initialisierung der Geraete
        interrupt_disable();
        data2->wdctrl   = WATCHDOG_0->control;  // Reset Status des WD merken

        .........

        // Initialisierung beendet
        interrupt_enable();
        if (data2->wdctrl == 0) {
                printf("\f\r\n");               // Loesche Terminal
                printf(startMeldung);
                data2->pgnr     = 0;
                test_timer_rti();
                }
        else {
                if (data2->wdzyk > data2->zmax) data2->zmax = data2->wdzyk;
                if (data2->wdzyk < data2->zmin) data2->zmin = data2->wdzyk;
                printf("\33\[u\t\t\t WDT-Alarm bei %6u Zyklen",data2->wdzyk);
                // Die ESC-Sequenz \33\[u setzt den CU an die mit \33\[s gespeicherte Position.
                printf(" (min=%6u max=%6u)\r\33\[5A",data2->zmin,data2->zmax);
                // Die ESC-Sequenz \33\[5A setzt den CU um 5 Zeilen nach oben.
                data2->wdzyk    = ZYKSTART;
        }

        while (1) {
                data2->pgnr     = 1;
                test_wdt();
                data2->pgnr     = 2;
                test_rotta();
        }
}


/*
 * Test des Watchdog Timers
 *
 * Die Schleife while (i > 0) i--; hat im GCC zur Zeit 6 Befehle.
 * Bei maximal 262143 = 0x3ffff Schleifenzyklen ergibt das ein Zeit von:
 * (1 / 25000000 Hz) * 6 * 262143 = 0,00000004s * 6 * 262143 = 0.06291432s
 * Die Zeit des Watchdog Timers muss kleiner sein, damit ein Alarm ausgeloest
 * wird. Die Zeit ergibt sich zu (1 / 25000000 Hz) * VT * limit
 * (1 / 25000000 Hz) * 256 * 6100 = 0.062464s ist kleiner!
 */
void test_wdt(void) {
volatile unsigned int   i       = data2->wdzyk;
volatile unsigned int   wdcnt   = 0;
volatile unsigned char  d       = ' ';
        printf("\r\n\n2. Test des Watchdog Timers\r\n   Ende mit ESC\r\n");
        WATCHDOG_0->limit       = 6100; // 262143 = 0x3ffff
        WATCHDOG_0->control     = WATCHDOG_EN | WATCHDOG_PRE_EN | WATCHDOG_PRE_256;
        printf(" limit = %4u ctrl = %5x\r\n\33\[s",WATCHDOG_0->limit,WATCHDOG_0->control);
        // Die ESC-Sequenz \33\[s merkt sich die CU-Position.
        while (d != 0x1b) {
                d = uart_getstat();
                i = data2->wdzyk;
                WATCHDOG_0->val_rst     = 0x12345;      // Reset Pin
                while (i > 0) i--;      // Schleife wird durch Watchdog Timer abgebrochen!
                wdcnt   = WATCHDOG_0->val_rst;
                WATCHDOG_0->val_rst     = 0x12345;      // Reset Pin
                data2->wdzyk++;
                printf(" wdcnt = %4u\r",wdcnt);
                if (data->aktzeit != data->i) {
                        putzeit();
                        data->aktzeit = data->i;
                }
        }
        WATCHDOG_0->control     = 0;
}

Protokoll des Testprogramms wd_test.c für die Förderband3 Konfiguration

Timer, RTI, Watchdog, LED, UART und Rotationstaster Test in C

1. Zeit auf der Konsole anzeigen
   Ende bei jeder Eingabe
   Stellen mit dem Rotationstaster oder
CTRL+B Stunden mit + stellen
CTRL+C Minuten mit + stellen
CTRL+D Sekunden mit + stellen
CTRL+E Ende Stellen

 Aktuelle Zeit: 16:02:14  Hallo ich bin SpartanMC 18   

2. Test des Watchdog Timers
   Ende mit ESC
 limit = 6100 ctrl =    1F
 wdcnt = 6094   16:05:30 WDT-Alarm bei 260218 Zyklen (min=260218 max=260229)
SpMC loader v20120927

3. Test des Rotationstaster Moduls

   ESC = Programm Ende

0    0    1    1    2    2    3
0....5....0....5....0....5....0
                        ^         

2. Test des Watchdog Timers
   Ende mit ESC
 limit = 6100 ctrl =    1F
 wdcnt = 6097   16:07:56 WDT-Alarm bei 260218 Zyklen (min=260218 max=260234)
SpMC loader v20120927

3. Test des Rotationstaster Moduls

   ESC = Programm Ende

0    0    1    1    2    2    3
0....5....0....5....0....5....0
     ^                            

2. Test des Watchdog Timers
   Ende mit ESC
 limit = 6100 ctrl =    1F
 wdcnt = 6095   16:08:45 WDT-Alarm bei 260229 Zyklen (min=260218 max=260234)
SpMC loader v20120927








 CTRL-A  Z = Hilfe |115200 8N2 | NOR | Minicom 2.5    | VT102 | Online 00:33



SpartanMC