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_CTRLFunktionReset
Bit 0: Watchdog enable: 0 = disable, 1 = enable 0
Bit 1: Teiler enable: 0 = disable, 1 = enable 0
Bit 2 bis 4: Vorteiler: 0
            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.0
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 wird der Parameter BASE_ADR vom jConfig automatisch eingestellt. BASE_ADR gibt den Offset der Adresse des Moduls zur Basisadresse aller Peripherieregister an. Der Wert besteht aus den oberen sieben Bit der zehn Bit-Adresse eines Moduls (die unteren drei Bit werden nur modulintern benutzt).

Der Parameter WDT_CODE ist das 18 Bit-Passwort, dass in das WDT_CHK-Register geschrieben werden muss, um einen Alarm 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

Image Image Image

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

Informationen zu den im Programm verwendeten Ansi-Sequenzen zur Farbsteuerung finden Sie hier.
// Startwert fuer die Zyklenanzahl der Watchdog Warteschleife
#define	ZYKSTART	255320  // Wert < min (min = 255961 max = 255986) vom Programm ermittelt

        .........

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

        .........

	// Initialisierung beendet
	// Ist es RESET oder Alarm?
	if (data2->wdctrl == 0) {		// Es ist RESET oder Neustart
		RTI_0->ctrl	= RTI_EN|RTI_EN_INT|(RTI_PRE_VAL*VT_RTI0);		// RTI_PRE_VAL = 2^3
		RTI_1->ctrl	= RTI_EN|RTI_EN_INT|(RTI_PRE_VAL*2);			// RTI_PRE_VAL = 2^2
		TIMER_1->limit	= LI_TIMER1;						// getesteter Wert fuer eine Sekunde
		TIMER_1->control= TIMER_EN|TIMER_PRE_EN|(TIMER_PRE_VAL*(VT_TIMER1-1));	// TIMER_PRE_VAL = 2^4
		interrupt_enable();
		data2->pgnr	= 0;
		test_timer_rti();
	}
	else {					// Es ist ein Watchdog Alarm
		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 \33\[1m%6u\33\[0m Zyklen",data2->wdzyk);
		// Die ESC-Sequenz \33\[u setzt den CU an die mit \33\[s gespeicherte Position.
		// Wenn diese Sequenz nicht arbeitet, dann hier durch \r\33\[2A ersetzen!
		// \33\[1m  -- Zeichen Fett   \33\[0m -- Zeichen normal
		printf(" (min=\33\[1;32m%6u\33\[0;37m max=\33\[1;31m%6u\33\[0;37m)\r\33\[5A",data2->zmin,data2->zmax);
		// \33\[1;32m  -- Zeichen gruen Fett   \33\[0;37m -- Zeichen weiss normal   \33\[1;31m -- Zeichen rot Fett
		// Die ESC-Sequenz \33\[5A setzt den CU um 5 Zeilen nach oben.
		data2->wdzyk	= ZYKSTART;
		// Zeit nach dem ALARM korrigieren
		uhr();				// Zeit inkrementieren
		uhr();				// Zeit inkrementieren
		volatile unsigned int i,j;	// Warten bis zwei Sekunden um sind
		for (i=15;i>0;i--) {
			for (j=262134;j>0;j--); // i=15 j=262134 max = 0x3ffff = 262143
		}
		RTI_0->ctrl	= RTI_EN|RTI_EN_INT|(RTI_PRE_VAL*VT_RTI0);		// RTI_PRE_VAL = 2^3
		RTI_1->ctrl	= RTI_EN|RTI_EN_INT|(RTI_PRE_VAL*2);			// RTI_PRE_VAL = 2^2
		TIMER_1->limit	= LI_TIMER1;						// getesteter Wert fuer eine Sekunde
		TIMER_1->control= TIMER_EN|TIMER_PRE_EN|(TIMER_PRE_VAL*(VT_TIMER1-1));	// TIMER_PRE_VAL = 2^4
		interrupt_enable();
	}
	while (1) {
		data2->pgnr	= 1;
		test_wdt();
		data2->pgnr	= 2;
		test_rotta();
		data2->pgnr	= 0;
		test_timer_rti();
	}
}


/*
 * 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 / 35937500 Hz) * 6 * 262143 = 0,0000000278260869565s * 6 * 262143 = 0,0437664834783s
 * Die Zeit des Watchdog Timers muss kleiner sein, damit ein Alarm ausgeloest
 * wird. Die Zeit ergibt sich zu (1 / 35937500 Hz) * VT * limit
 * (1 / 35937500 Hz) * 128 * 12000 = 0,0427408695652s ist kleiner bei 6 Befehlen!
 */
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	= 12000;	// 262143 = 0x3ffff
	WATCHDOG_0->control	= WATCHDOG_EN | WATCHDOG_PRE_EN | WATCHDOG_PRE_128;
	printf(" limit = %5u 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 = %5u  \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örderband4 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: 21:40:47  Hallo ich bin SpartanMC 18   

2. Test des Watchdog Timers
   Ende mit ESC
 limit = 12000 ctrl =    1B
 wdcnt = 11973  21:41:01 WDT-Alarm bei 255970 Zyklen (min=255965 max=255982)
SpMC loader v20140908

3. Test des Rotationstaster Moduls

   ESC = Programm Ende

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










CTRL-A Z for help | 115200 8N2 | NOR | Minicom 2.7 | VT102 | Online 0:56 | ttyUSB1



SpartanMC