Pages: 1 ... 18 19 [20] 21 22 ... 31   Go Down
Author Topic: leOS - un semplice OS per schedulare piccoli task  (Read 39061 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Edison Member
*
Karma: 26
Posts: 1339
You do some programming to solve a problem, and some to solve it in a particular language. (CC2)
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Interrupt Service Routine, non Internet.

Forse in Arduino 3 o 4 ci sarà proprio una Internet service routine, nel senso che Internet sarà così pervasiva che le funzionalità di comunicazione di base relative ad Internet saranno gestite direttamente in hardware, un po' come i Timer adesso...  smiley-eek
Logged

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 333
Posts: 22938
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quest'ultimo caso è quello che ci interessa: creando una ISR (Internet Service Routine) che intercetta il reset, possiamo gestire lo scheduler dei processi da eseguire in automatico senza utilizzare timer del microcontrollore, evitando quindi che il nostro sketch vada in conflitto con altre librerie che anch'esse usano lo stesso timer.

Interrupt Service Routine, non Internet.  smiley-mr-green
Uh oh....  smiley-sweat smiley-sweat
Logged


Offline Offline
God Member
*****
Karma: 9
Posts: 550
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

leo,lo so che sto andando un po' OT,ma vedo che ti sei studiato la cosa...la mia domanda è: se l'esecuzione è piantata nel codice richiamato da un interrupt,c'è modo invocare cmq l'interrupt associato al watchdog?o l'unica cosa che posso fare è reset?
Logged

Cagliari, Italy
Offline Offline
Tesla Member
***
Karma: 114
Posts: 7183
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Non ho capito la domanda.
Comunque Leo ha scritto che, a parte l'ATmega8 (quelli che usa Testato per intenderci), in tutti gli altri micro è possibile associare al "Cane da Guardia" il reset del micro, un interrupt (quindi una TUA funzione) oppure tutti e due. (questa ultima possibilità mi lascia perplesso  smiley-roll-sweat)
Logged

Code fast. Code easy. Codebender --> http://codebender.cc/?referrer=PaoloP

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 333
Posts: 22938
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

@m_ri:
vediamo se ho capito.
Abbiamo leOS2 in esecuzione. Esso lancia un task, all'interno del quale un utente inavvertitamente ha messo un delay(10) e la CPU resta bloccata in eterno nella ISR perché il delay in un interrupt è bloccante (non sto a spiegare i motivi, li sappiamo).
Il WDT continuerà a girare perché il contatore è HW quindi non è bloccato dal SW però la sua segnalazione dell'interrupt cadrà nel vuoto, dato che il micro sta già eseguendo l'interrupt associato all'overflow del contatore del WDT.

@Paolo:
il datasheet riporta le modalità selezionabili per l'overflow del WDT:
Quote
Mode - Action
Stopped - None
Interrupt Mode - Interrupt
System Reset Mode - Reset
Interrupt and System Reset Mode - Interrupt, then go to System Reset Mode
System Reset Mode - Reset**
**questa è l'unica possibile quando è attivo il fuse WDTON. Se il fuse è disattivato, si possono impostare via software tutte le altre.
Logged


Offline Offline
God Member
*****
Karma: 9
Posts: 550
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

perfetto..in realtà no,perchè speravo di poter lanciare una routine prima di resettare il micro..grazie smiley
Logged

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 333
Posts: 22938
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

perfetto..in realtà no,perchè speravo di poter lanciare una routine prima di resettare il micro..grazie smiley
Secondo il datasheet...

Leggi:
Quote
Interrupt and System Reset Mode - Interrupt, then go to System Reset Mode
io leggo che si può: "Interrupt, e POI in reset"
Quindi lanci la routine e poi vai in reset. Non so però quanto può durare la routine, se cioè che un termine fissato entro il quale il chip viene resettato oppure se il WDT aspetta l'uscita dalla ISR e poi resetta.
Logged


Offline Offline
God Member
*****
Karma: 9
Posts: 550
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

aspe..ma se avessi larduino piantato dentro un interrupt,NON posso invocare altri interrupt prima del reset(o meglio,lo invoco,ma lui non lo esegue finchè non si esce dall'interrupt corrente,il quale è piantato)..giusto?
e il reset verrebbe eseguito al termine dell'interrupt?
Logged

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 333
Posts: 22938
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Per default, avr-gcc compila tutte le routine di reset "atomiche", quindi non possono essere interrotte

In questo caso non hai bisogno del leOS2, ma del watchdog puro.
Attivi il watchdog, se non resetti il suo contatore il watchdog ti resetta il micro.
Si può fare con il leOS1, puoi impostare il WatchDog in modo indipendente ad esempio per tempi lunghi (2/4/8 secondi) e poi metti un task che resetta il WDT un po' prima del reset.
Siccome il WDT è indipendente, se il suo contatore va in overflow esso resetta il micro indipendentemente da cosa il micro sta facendo (anche se è freezato in un loop infinito).

Questo sketch fa quel che dico e che mi pare stia dicendo tu:
Code:
#include <avr/wdt.h>
#include "leOS.h"

leOS myOS;
byte led1Status = 0;
const byte LED1 = 13;

//program setup
void setup() {
    wdt_disable();
    myOS.begin(); //initialize the scheduler
    pinMode(LED1, OUTPUT);
   
    //add the tasks at the scheduler
    myOS.addTask(flashLed1, 150);
    myOS.addTask(resetWdt, 3500);
    myOS.addTask(freeze, 3000);
    wdt_enable(WDTO_4S);
}


//main loop
void loop() {
}


//first task
void flashLed1() {
    led1Status^=1;
    digitalWrite(LED1, led1Status);
}


//second task
void resetWdt() {
    wdt_reset();
}


void freeze() {
    while(1) {}
}
Creo 3 task.
Il primo fa lampeggiare un LED, il secondo resetta il WDT ed il terzo freeza il micro.
Siccome il freeze arriva prima del reset del contatore del WDT, il WDT resetta il micro senza problemi.
Puoi verificare commentando la riga dove aggiungo il task che blocca tutto e vedere come il LED lampeggi senza interruzioni.
Logged


Offline Offline
God Member
*****
Karma: 9
Posts: 550
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

non ero tatno interessato al nuovo leoS,ma alle tue conoscenze nel campo   smiley..se imposto un wd con reset,questo mi resetta il micro anche se sono in un'istruzione atomica e fin qua son d'accordo...se però il wd è impostato sia x reset che x lanciare interrupt,cosa capita se il micro era freezato in un'istruzione atomica??mi fa cmq il reset,o aspetta l'esecuzione dell'interrupt invocato?
Logged

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 333
Posts: 22938
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Allora, la situazione è ingarbugliata ed ho studiato 1 oretta per capirci qualcosa  smiley-sweat

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

Code:
#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.
Logged


Offline Offline
God Member
*****
Karma: 9
Posts: 550
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

guardiamo se ho capito bene:
-se il micro è freezato,allora il wd scatena solo il reset(anche se era nella modalità interrupt+reset)
-altrimenti se non è freezato,e se ho impostato il wd per lanciare interrupt+reset,al primo watchdog viene invocato l'interrupt..se poi voglio resettarlo,invoco un altro watchdog..
Logged

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 333
Posts: 22938
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

guardiamo se ho capito bene:
-se il micro è freezato,allora il wd scatena solo il reset(anche se era nella modalità interrupt+reset)
Esattamente, perché una ISR non può interrompere un'altra ISR (a meno di non modificare le librerie Avr).

Quote
-altrimenti se non è freezato,e se ho impostato il wd per lanciare interrupt+reset,al primo watchdog viene invocato l'interrupt..se poi voglio resettarlo,invoco un altro watchdog..
Non esattamente. Il timer del WatchDog scorre sempre. La prima volta lui manda un segnale di interrupt: se il micro è freezato, ovviamente non può essere intercettato (caso precedente), altrimenti sì e quindi si può eseguire un compito. Poi il timer del WatchDog riparte, e la seconda volta spedisce un reset, e questo ovviamente funziona sempre  smiley-wink

Con interrupt+reset attivi, la sequenza è:
1) interrupt
2) reset
Se si reimposta nella ISR il bit WDIE, al prossimo timeout del contatore del WDT il micro non resetta ma riesegue prima l'interrupt. Solo se il bit WDIE non viene reimpostato, al successivo timeout il WDT resetta il micro.

Secondo me è una caratteristica mooolto interessante, perché dà modo appunto di usare il watchdog normalmente ma anche di resettarlo se qualcosa lo pianta. Anzi, nella prox versione del leOS2 la implemento  smiley-wink

EDIT:
no, perché il WDT nel leOS2 è impostato per girare su un tempo di 16 ms. Può capitare che un task possa durare più di 16 ms, ed avrei il reset al successivo timeout del WDT.
« Last Edit: November 14, 2012, 04:09:26 am by leo72 » Logged


Offline Offline
Edison Member
*
Karma: 26
Posts: 1339
You do some programming to solve a problem, and some to solve it in a particular language. (CC2)
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Leo, quindi nella modalità ISR+RESET è la ISR stessa a decidere se al "prossimo giro"(*) il micro verrà resettato o se verrà lanciata di nuovo la ISR, giusto ?

Se è così, allora sarebbe possibile usare la ISR per salvare informazioni di stato in caso di freeze anche se tale salvataggio comportasse un tempo "lungo" (ad esempio salvare su eeprom una serie di variabili o un array). Tipo:

wdt_isr():
    if l'operazione di salvataggio non è ancora stata avviata
        lancia l'operazione di salvataggio dati
        reimposta il bit WDIE
    else
        if il salvataggio dati NON è completo
            reimposta il bit WDIE
        else
            // il salvataggio è completo, non facciamo nulla e lasciamo scadere il wdt provocando il reset del micro
        endif
    endif


(*) cioè al prossimo scadere del wdt
Logged

0
Offline Offline
Shannon Member
****
Karma: 132
Posts: 10498
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

no leo, vorrei analizzare meglio la situazione.

Se il watchdog lancia una funzione, che retta il watchdog e poi fa qualcosa. se dura più del prossimo interrupt watchdog, che non si resetta, mi aspetto che la funzione venga lanciata di nuovo, bloccando temporaneamente le prima esecuzione. Ovviamente se ci sono variabili globali (e se usi librerie tipo Serial, Wire, etc..) in uso nasce un casino della madonna, perchè potresti usare valori temporanei.
In oltre ogni richiamo è una chiamata a funzione in stack, il che può causare uno stack overflow. Notare che comunque la seconda chiama riazzera il watchdog, quindi nessun problema di restet

il problema sussiste se invece il secondo interrupt viene ignorato perchè la ISR è già in esecuzione. In tal caso hai ragione a eliminare il reset, ma sinceramente cercherei una soluzione migliore, per esempio forzare il richiamo della ISR, ma una variabile ti avvisa se c'è qualche funzione pendente in esecuzione. In tal caso resetti il timer ma NON lanci l'esecuzione del nuovo codice. Potresti usare un puntatore a funzione al posto della variabile, se è NULL allora fai partire la funzione richiesta, se non è null e la funzione schedulata è differente da quella in esecuzione (e in modalità DEBUG), allora lanci un alert per avvisare l'utente del ritardi di esecuzione del task a causa della sua funzione precedente troppo pesante, o perchè ha schedulato due task per avvenire assieme.

Seguendo questo principio della modalità DEBUG, puoi avvisare l'utente quando stai effettivamente lanciando una sua funzione, calcolando anche l'errore rispetto all'orario impostato.

bhe direi che per ora ti ho rotto le balle abbastanza  smiley-mr-green
Logged

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Pages: 1 ... 18 19 [20] 21 22 ... 31   Go Up
Jump to: