leOS - un semplice OS per schedulare piccoli task

Allora, la situazione è ingarbugliata ed ho studiato 1 oretta per capirci qualcosa :sweat_smile:

Prendi questo codice e caricatelo sull'Arduino, mettendo 3 led sui pin D7, D8 e D9:

#include <avr/wdt.h>
#include "leOS.h"
leOS myOS;

const byte LED1 = 7;
byte statusLed1 = 1;
const byte LED2 = 8;
const byte LED3 = 9;

void setup() {
    //per sicurezza, SEMPRE disattivare il WDT appena avviato lo sketch
    MCUSR = 0;
    wdt_disable();
    myOS.begin();
    pinMode(LED1, OUTPUT);
    pinMode(LED2, OUTPUT);
    pinMode(LED3, OUTPUT);
    //avviso che sono partito
    for (byte i=0; i<2; i++) {
        digitalWrite(LED3, HIGH);
        delay(100);
        digitalWrite(LED3, LOW);
        delay(100);
    }
    myOS.addTask(resetWdt, 3500); //resetto il WDT
    myOS.addTask(blinkLed1, 250); //lampeggio un LED
    myOS.addTask(freezeMcu, 4500); //congelo l'MCU
    setWDT(); //imposto il WDT
}

void loop() {}

void resetWdt() {
    wdt_reset();
}

void blinkLed1() {
    digitalWrite(LED1, statusLed1);
    statusLed1 ^=1;
}

void freezeMcu() {
    //inverti i commenti sulle 2 righe sottostanti
    //while(1) {};
    myOS.pauseTask(resetWdt);
}

void setWDT() {
    //fermo il WDT
    MCUSR = 0; 
    wdt_disable();
   //disabilito gli interrupt 
    SREG &= ~(1<<SREG_I);
    WDTCSR |= ((1<<WDCE) | (1<<WDE));
    WDTCSR = ((1<<WDE) | (1<<WDP3) | (1<<WDIE));
    SREG |= (1<<SREG_I); 
}

ISR(WDT_vect){
    digitalWrite(LED2, HIGH);
    delayMicroseconds(50000);
    digitalWrite(LED2, LOW);
    //WDTCSR |= (1<<WDIE); //decommenta e commenta
}

Questo codice attiva 3 task: un lampeggio di un LED, un reset del WDT ed un freeze.
Se freezo il micro con un ciclo infinito in un task, sia che reimposti il bit WDIE (quello che attiva l'interrupt sul WDT) sia che non lo faccia, il micro freezato non esegue l'ISR del WDT ma si resetta al timeout del watchdog.

Se invece blocco il reset del WDT, quindi non un freeze, se ho il bit WDIE reimpostato nella ISR, il micro esegue la ISR del WDT ma non resetta nulla. Se invece disattivo la reimpostazione del bit WDIE, accade una cosa buffa:

  1. al timeout preimpostato, viene eseguita la ISR ma non viene resettato il micro
  2. al successivo timeout NON viene eseguita la ISR ma viene subito resettato il micro.

Quest'ultima modalità, sul datasheet, è riportata come voluta ad esempio per far salvare la configurazione del microcontrollore se una routine ha freezato la CPU: eseguendo la ISR si può salvare dei dati prima del riavvio.