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
Offset | Register | Funktion | Zugriff |
0 | WDT_CTRL | Steuerregister | read/write |
1 | WDT_DAT | Ende Wert des Zählers | read/write |
2 | WDT_CHK | Passwort zum Rücksetzen des Zählers. | write |
2 | WDT_CNT | Zähler | read |
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_CTRL | Funktion | Reset |
---|---|---|
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
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