AVR-GCC. WatchDog (Προσοχή σκύλος).

Θα δούμε ένα εργαλείο που μάχεται ενάντια στα λάθη και τις ατέλειες του προγραμματιστή. Τον WatchDog timer.
Όσο και αν εξασκηθούμε δεν θα καταφέρουμε σχεδόν ποτέ μα ποτέ αναπτύξουμε ένα πρόγραμμα που δεν θα περιέχει λάθη. Ο μετρητής WatchDog δεν θα μας κάνει καλύτερους προγραμματιστές. Αυτό που κάνει ο WatchDog είναι να σιγουρέψει πως το πρόγραμμα μας δεν θα κολλήσει. Σε περίπτωση που το πρόγραμμά μας πέσει σε μία κατάσταση που δεν μπορεί να ξεκολλήσει (π.χ. ατέρμον βρόχο) τότε ο WatchDog θα το επανεκκινήσει προκαλώντας μία κατάσταση Reset τον μικροελεγκτή.

Άρθρο της Wikipedia για τον WatchDog timer.
Τεκμηρίωση του ATmega8.

Ας υποθέσουμε πως έχουμε τον παρακάτω κώδικα.

    uint8_t x;

    x = 10;

    while (x >= 0){
      // Κάνουμε κάτι

      x--;
    };

Αν δούμε προσεκτικά τον παραπάνω βρόχο θα παρατηρήσουμε πως δεν πρόκειται να ολοκληρωθεί ποτέ. Γιατί; Απλά επειδή η μεταβλητή x είναι τύπου uint (μη προσημασμένη) και δεν μπορεί να πάρει αρνητικές τιμές (ίσως ο μεταγλωττιστής να μας προειδοποιήσει). Όταν φτάσει στο 0 θα υπερχειλίσει στην τιμή 255 κ.ο.κ. Ο βρόχος λοιπόν θα τρέχει για πάντα. Εδώ ακριβώς είναι που έρχεται στην παρέα μας ο WatchDog.

Τι θα κάνει ο WatchDog;
Ο WatchDog έχει ένα ξεχωριστό timer/counter (μετρητή) που χρονίζεται από ένα εσωτερικό σήμα ρολογιού του 1 MHz στα 5 volts. Μερικοί μικροελεγκτές έχουν ξεχωριστό ταλαντωτή για τον WatchDog. Για παράδειγμα ο ATtiny2313 με 128 kHz. Από την στιγμή που θα ενεργοποιηθεί ο WatchDog και θα ρυθμιστεί κατάλληλα ο prescaler θα αρχίσει ο μετρητής από το 0. Αν περάσει ο αριθμός κύκλων που καθορίστηκε από τον prescaler ο WatchDog θα δημιουργήσει ένα σήμα reset στον μικροελεγκτή. Για να αποτρέψουμε τον WatchDog από το κάνει reset και σε κανονική λειτουργία πρέπει να επανεκκινούμε τον μετρητή του τακτικά. Αυτό συνήθως το κάνουμε το κάνουμε μέσα από τον κύριο βρόχο του προγράμματος.

Για να αποφευχθούν κατά λάθος απενεργοποιήσεις του WatchDog πρέπει να ακολουθηθεί μία ειδική διαδικασία για την απενεργοποίηση του. Πρέπει τα bit WDCE και WDE να γίνουν ταυτόχρονα ένα (1) και μετά το WDE να γίνει μηδέν (0). Η avr-libc διαθέτει συναρτήσεις που κάνουν την διαδικασία αυτή αυτόματα. Ο καταχωρητής για τις ρυθμίσεις του WatchDog είναι ο WDTCR.

WDTCR (WatchDog Timer Counter Register):

Bit7:5:
Δεν χρησιμοποιούνται. Στο ATmega8 διαβάζονται πάντα ως μηδέν (0).

WDCE (WatcDog Change Enable):
Το bit αυτό χρησιμοποιείτε για την απενεργοποίηση του WatchDog. Μετά από τέσσερις (4) κύκλους γίνεται αυτόματα μηδέν από τον μικροελεγκτή.

WDE (WatcDog Enable):
Όταν αυτό το bit γίνει ένα (1) ενεργοποιείται ο WatchDog. Αυτό το bit μπορεί να γίνει μηδέν (0) μόνο εάν το WDCE bit είναι (1).

WDP2:0 (WatchDog Prescaler):
Τα bit αυτά ρυθμίζουν τον αριθμό των κύκλων του ταλαντωτή του WatchDog που θα ενεργοποιηθεί το σήμα για reset.

Το αρχείο κεφαλίδας που περιέχει τις απαραίτητες συναρτήσεις για τον έλεγχο του WatchDog είναι το “avr/wdt.h”. Παρακάτω είναι οι συναρτήσεις που περιλαμβάνει.

wdt_enable(uint8_t timeout)
Η συνάρτηση αυτή ενεργοποιεί τον WatchDog και τοποθετεί την τιμή του timeout στα WDP2:0 bits του καταχωρητή WDTCR. Η avr-libc έχει μερικές προκαθορισμένες τιμές.

wdt_dissable()
Η συνάρτηση αυτή απενεργοποιεί τον WatchDog. Η διαδικασία που περιγράψαμε παραπάνω γίνεται αυτόματα.

wtd_reset()
Αυτή ίσως είναι η ποιο σημαντική από τις συναρτήσεις του wdt.h. Δημιουργεί ένα σήμα που επαναφέρει τον WachDog. Πρέπει να χρησιμοποιείτε περιοδικά πριν την λήξη του χρόνου και την δημιουργία του σήματος reset στον μικροελεγκτή από τον WatchDog.

Πίνακας με τις προκαθορισμένες τιμές time out για την wdt_enable.

Είναι εφικτό να δούμε αν ο μικροελεγκτής μας έχει επανέλθει μετά από την εντολή του WatchDog. Μπορούμε να εξετάσουμε το WDRF (WatchDog Reset Flag) στον καταχωρητή MCUCSR (σελίδα 41 της τεκμηρίωσης του ATmega8). Αυτό είναι πολύ χρήσιμο κατά την αποσφαλμάτωση. Μπορούμε να ανάβουμε ένα LED αν προέκυψε WachDog reset, να το γράφουμε στην EEPROM, να το στέλνουμε μέσω UART.

Στον παρακάτω κώδικα ενεργοποιούμε τον WatchDog με χρόνο 2 δευτερολέπτων. Αν μέσα σε δύο δευτερόλεπτα δεν επανεκκινήσουμε τον μετρητή ο WatchDog θα προκαλέσει μία κατάσταση Reset στον μικροελεγκτή, ενεργοποιώντας το WDRF bit που θα προκαλέσει ενεργοποίηση του LED κατά την επόμενη εκκίνηση του προγράμματος. Αν διορθώσουμε τον κώδικα μας (το uint8_t x; σε int8_t x;) ο WatchDog δεν θα επέμβει.

#include <avr/io.h>
#include <avr/wdt.h>
#include <util/delay.h>


/*Η παρακάτω δήλωση ελέγχει αν στον compiler έχουμε βάλει την παράμετρο F_CPU.
  Αν όχι, την περνά. */

#ifndef F_CPU
    #warning "H F_CPU den exei oristei 8a parei thn timh 4000000"
    #define F_CPU 4000000UL  // Use unsigned long (UL)
#endif


int main(void){

    wdt_enable(WDTO_2S);  // Ενεργοποίηση του WatchDog
                          // με χρόνο 2 δευτερόλεπτα.

    DDRB |= (1<<PB0);     // PB0 ως έξοδος.



    // Αν το WDRF bit στον MCUCSR είναι 1, που
    // σημαίνει επανεκκίνηση από τον WatchDog,
    // άναψε το LED στο pin PB0.
    if(bit_is_set(MCUCSR,WDRF)) PORTB |= (1<<PB0);

    /*
      Το bit WDRF για να επανέρθει σε λογικό 0 πρέπει
      το γράψουμε σε λογικό 0 ή αν διακοπεί και επανέρθει
      η τροφοδοσία του μικροελεγκτή (Power-On Reset).
      Απλό reset (λογικό μηδέν στο pin 1) δεν το επαναφέρει.

    */


    uint8_t x;

    x = 10;

    while (x >= 0){
      // Κάνουμε κάτι

      x--;
    };

    while(1){

        // Επανεκκίνηση του μετρητή του WatchDog.
        wdt_reset();

    };

    return 0;
}

Advertisements
This entry was posted in AVR, Electronics and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s