Deep sleep avec LowPower sur NANO

Bonjour,
Je travaille sur un projet qui sera au final sur Pro mini, mais où j'utilise une NANO pour développer. Le projet allant être sur batterie je compte utiliser le deep sleep, qui s'activera au bout de quelques secondes d'inactivité (le watchdog fonctionnera pour ça j'imagine), sur une période indéfiniment longue jusqu'au réveil par interruption sur une pin (j'ai des petite capteur TOR qui détecte des inclinaisons avec une bille qui vient faire contact à l'intérieur, il faudra donc secouer l'objet pour le "réveiller")

Je pensais qu'il fallait utiliser les fonctions des fichiers du répertoire avr, par rapport à cet exemple de programme :

Puis grâce à cet excellent article d'@hbachetti (que je salue au passage!) j'ai découvert l’existence d'une bibliothèque, LowPower, qui simplifie la basse consommation sur les AVR et évite de manipuler les registres (ce que je crois nécessaire d'après l'exemple sans bibliothèque).

Je compte l'utiliser mais ici et au chapitre 8 de l'article il est indiqué que le processeur de la Pro mini ne sait pas dormir plus de 8s et qu'il faut donc le "rendormir" en boucle - d'où mes questions :

  • est-ce que c'est la même chose pour la NANO (j'imagine que oui si c'est le même processeur) ?
  • et si on ne peut pas l'endormir indéfiniment pourquoi existe t-il un exemple de LowPower qui montre l'utilisation de la ligne
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); 

C'est bien qu'on peut activer le deep sleep indéfiniment non ?

En vous souhaitant à tous de bonnes fêtes avec un peu de retard!
Cordialement,
Pandaroux007

oui, en renonçant à un auto-réveil temporisé via le chien de garde

est-ce que c'est la même chose pour la NANO (j'imagine que oui si c'est le même processeur)

Oui , et la limite des 8s de ‘temps de sommeil élémentaire maximal’’ est une contrainte du chien de garde de l’ATMega328, utilisé pour un réveil temporisé.

Bonjour @al1fch !
D'accord, merci pour l'info - donc si je fais un réveil par interruption sur une pin, je peux utiliser SLEEP_FOREVER si je comprends bien ?

Et est-ce que mon idée d'utiliser le watchdog pour faire entrer en deep sleep la carte au bout d'un certain temps d'inactivité (donc en utilisant une interruption) est viable ou doit-je utiliser un autre système sans interruption plus adapté ?

Par curiosité, savez-vous pourquoi 8s max pour le réveil temporisé ?

Bonsoir,

Cf. Watchdog ATmega328P
avec notamment le tableau après la phrase "Pour être plus explicite, voici au bout de combien de temps se déclencherait le watchdog, une fois lancé , selon le rapport de division de fréquence choisi :"

La fonction première d’un chien de garde (‘watchdog) c’est de resetter un microcontrolleur ou microprocesseur qui n’exécute plus correctement son programme.

8 secondes de ‘divagation’ c’est très long !!

Le choix de conception d’Atmel pour cette fonction est rationnel et bien souvent quand on utilse un ‘watchdog’ pour sa fonction première on préfère un temps de réaction court.

Pour info les pages 43 et 44 de la Data Sheet des ATMega328 décrivent la fonction

Bonjour,

Cela n'est pas tout à fait exact car, sauf erreur de ma part, on peut lire dans la datashhet (page 40):

10.2 Reset Sources
The Atmel ATmega328P has four sources of reset:
...
● Watchdog system reset. The MCU is reset when the watchdog timer period expires and the watchdog system reset mode is enabled.

C'est la raison pour laquelle, un vecteur d'interruption est dédié à l'expiration du watchdog et qui permet d'exécuter une séquence de code qui ne fait pas de reset (et heureusement ;-) (Cf. page 49 - § 11.1 Interrupt Vectors in ATmega328P) :

7    0x000C    WDT     Watchdog time-out interrupt

A suivre...

oui, et cela permet heureusement de différencier le traitement selon la source de … reset :wink:

Vu le comportement d’un code ATMega328 avec deepsleep il est probable (je n’ai pas vérifié le contenu du registre WDTCSR concerné) que l’expiration du watchdog se fait sans engendrer de reset. (c’est optionnel)

donc oui, un watchdog d’ATMega328 ne resette pas systématiquement , cela dépend de la configuration

Bonsoir (la nuit tombe vite en ce moment :smiley:) à tous les deux et merci pour vos réponses

C'est ce que j'avais cru comprendre, merci pour la confirmation et les liens!
C'est tout ce dont j'avais besoin pour mon projet, je pense pouvoir me débrouiller avec les exemples de LowPower à partir de ce que vous m'avez dit. Merci :+1:

Bonne année ! :partying_face:
Amitiés,
Pandaroux007

Re-bonjour :slight_smile:
Je retourne sur le projet après un petit moment, avec une question subsidiaire. Dans l'exemple pour réveiller la carte avec une interruption sur une pin avec LowPower, on attache l’interruption sur la pin 0, or wakeUpPin est définie à 2 ? Comment cela peut-il fonctionner ?

Bonjour,
C'est expliqué ici au chapitre "Interrupt Numbers"
https://docs.arduino.cc/language-reference/en/functions/external-interrupts/attachInterrupt/

Merci pour le lien :+1:
Si je comprends bien ce n'est pas la même chose de définir un int comme premier paramètre que de faire un digitalPinToInterrupt ? Je ne comprends pas la différence entre

interrupt : the number of the interrupt. Allowed data types: int

et

pin : the Arduino pin number.

Lorsque tu passes un int comme paramètre tu peux mettre n'importe quelle valeur.
Lorsque tu passes digitalPinToInterrupt(pin) en argument il y a un traitement sur le n° de pin en fonction de la cible. En particulier, un test sur le fait que la pin proposée génère bien une interruption.

Okay, donc le 0 serait le résultat de digitalPinToInterrupt(2) ?
EDIT : Yep c'est bien ça, testé avec

Serial.println(digitalPinToInterrupt(WAKEUP_PIN));

et effectivement ça renvoie bien 0!


Par ailleurs autre petite question à propos du watchdog, je sais qu'il existe deux-trois fonctions utiles pour le contrôler dans avr/wdt.h, mais je ne sais pas comment le configurer pour lever une interruption au lieu de reset la carte via celles-ci, je crois que pour configurer une interruption il faut passer par les noms barbares des timers, je me trompe ?

hello

INT0 est sur D2

INT1 est sur D3

que signifie “lever une interruption”?

Bonjour!
Je voulais dire lever une interruption logicielle au lieu de reset la carte lorsque le watchdog arrive à la fin du temps configuré - il me semble que pour ça on est obligé de passer par la manipulation des timers, avr/wdt.h est inutile dans ce cas, c'est bien ça ?

En tout cas c'est ce que j'ai cru comprendre à la lecture de cet article.

Je vois ce que vous voulez dire, j'utilise effectivement les interruptions matérielles de l'ATmega328P mais pas pour les mêmes raisons (pour le sortir du deep sleep plus précisément).

Quant au watchdog je comptais l'utiliser pour mettre en veille mon système après 8s d'inactivité de la part de l'utilisateur, en lui faisant lever une interruption pour le mettre en veille, mais je crois que je peux faire plus simplement avec millis(). Cela dit je maintiens ma question, ça reste intéressant de le savoir pour d'autres situations :wink:

avec le watchdog, il ne faut pas entendre interruption dans le sens “un événement sur en entrée interruption”.

il faut comprendre que le watchdog va travailler en deux passes ( si une “interruption” est demandée

une interruption demandée déclenchera l’exécution de la routine d’interruption” ISR(WDT_vect) “.

donc le watchdog, arrivé à la fin de son compte exécute la routine d’interruption, puis repasse à zéro et recommence à compter. arrivé à la fin de ce deuxième compte, il exécute un reset.

si tu as demandé ce type de fonctionnement du watchdog, lors de l’appel de l’interruption tu peux mettre tes périphériques en sécurité.

regarde le prog que je te passe, et active le moniteur et le chrono-datage. tu verras ce que je viens de t’expliquer.

le deepsleep, oui, tu peux le réveiller avec un événement extérieur sur une pin interruptible par exemple avec la sortie d’une ds3132 (si tu as bien programmée cette sortie dans l’horloge)

#include <avr/wdt.h>

void setup()
{
  Serial.begin(115200); uint8_t mcusr = MCUSR;
  MCUSR = 0;           // effacer flags reset
  wdt_disable();      // impératif au boot
  WDTCSR = (1 << WDCE) | (1 << WDE);
  WDTCSR = (1 << WDIE) | (1 << WDE) | (1 << WDP3) | (0 << WDP2) | (0 << WDP1) | (1 << WDP0);
  Serial.println("fin du setup "); Serial.flush();
  Serial.println("watchdog armé pour 8 secondes "); Serial.flush();
  sei();
}
ISR(WDT_vect)
{
  Serial.println("pré alarme, c'est reparti pour 8 secondes "); Serial.flush();

  Serial.println("on peut mettre la machine en securité "); Serial.flush();
  // 1. Mettre les sorties en sécurité
  PORTB = 0x00;
  PORTC = 0x00;
  PORTD = 0x00;

  // 2. Optionnel : journaliser l’erreur
  // ex: incrémenter un compteur en EEPROM

  // 3. Décision :
  // - soit tenter une récupération
  // - soit laisser le reset arriver


  // sinon → reset volontaire

}

void loop() {
  {
    //le watchdog compte le temps
  }
}



Bonjour @dfgh,
Désolé pour le temps de réponse :woozy_face: J'ai réussi à faire ce que je voulais sans toucher au timer, uniquement avec millis. Je préfère réserver le watchdog à ce pourquoi il a été conçu à l'origine à savoir sortir d'un crash... Merci en tout cas pour votre réponse détaillée vraiment intéressante, je teste votre exemple de suite! :+1:

Cordialement,
Pandaroux007