[Résolu] Mise en veille et réveil par interruption

Bonjour,

J'aimerai implémenter un bout de code pour mettre mon microcontrôleur ATmega328 en mode sommeil (Power Down) après x minutes et le réveiller ensuite par une interruption externe sur un port PCINT.

J'ai trouvé différents documents pour m'aider à ceci, notamment sur le site Arduino mais aussi via Google, et j'ai réussi (je crois) à faire ce que je voulais. J'ai cependant une question afin d'optimiser.

Pour le mode veille, voici le lien que j'ai utilisé : http://www.arduino.cc/playground/Learning/ArduinoSleepCode
Il n'y a pas vraiment eu besoin de modifier le code pour mon programme, j'ai juste du rajouter la ligne "detachInterrupt(0)" dans la méthode "void sleepNow()" car sinon cette interruption réveillait le uC sans que je le veuille. (J'avais mal lu le datasheet du uC mais c'est clairement dit que chaque interruption autorisée peut faire sortir du mode veille).

Pour le réveil, je voulais utiliser le code ici : Arduino Playground - HomePage mais je ne comprends pas comment ajouter les librairies #include <PinChangeInt.h> et #include <PinChangeIntConfig.h>.... Alors j'ai utilisé le code trouvé ici : http://www.me.ucsb.edu/~me170c/Code/How_to_Enable_Interrupts_on_ANY_pin.pdf

Voici le code que j'ai tapé (interruption avec PCINT21 (PD5)) :

PCICR |= (1<<PCIE2);
PCMSK2 |= (1<<PCINT21);
MCUCR = (1<<ISC01)|(1<<ISC00);
pinMode(PIN_INTERRUPT, INPUT);
digitalWrite(PIN_INTERRUPT,HIGH);
interrupts();

(…)

ISR(PCINT21_vec){
wakeUpNow();
}

(PIN_INTERRUPT est défini au début, #define PIN_INTERRUPT 5)

Donc, chaque interruption sur PCINT21 réveille le uC.

Ca fonctionne mais j’aimerai quand même si possible utiliser le code de l’exemple d’Arduino car ça me parait plus propre pour faire des attachInterrupt et detachInterrupt pour PCINT… comment faire pour utiliser la librairie PinChangeInt.h ? je dois l’inclure manuellement dans mon programme ?

Sinon, je ne suis pas sûr de bien comprendre comment faire l’équivalent de attachInterrupt et detachInterrupt sur PCINT21, pourriez-vous m’expliquer svp ?

Pour info, je compile mon code avec Arduino 0022 car il y a un grosse partie du code qui a été écrite avant les nouvelles versions et il y a trop de changement à faire dans le code pour rendre la compilation possible…

Merci !

Bonjour,
Je me suis aussi inspiré d'un code existant pour le même besoin.
J'endors l'AVR et il se réveille soit tout seul à l'expiration du timer du watchdog (8s maxi), soit sur une interruption matérielle (détection de mouvement dans mon cas).

la fonction gotoSleep() est appelée dans loop() selon certaines conditions.

//includes pour sleep mode
#include <avr/interrupt.h>
#include <avr/power.h>
#include <avr/sleep.h>
#include <avr/wdt.h>

...
...

/*
* Endort l'AVR
*/
void goToSleep(){
	// clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset
  WDTCSR = _BV (WDCE) | _BV (WDE);
  // set interrupt mode and an interval 
  WDTCSR = _BV (WDIE) | _BV (WDP3) | _BV (WDP0);    // set WDIE, and 8 seconds delay
  wdt_reset();  // pat the dog

  // disable ADC
  //ADCSRA = 0;  

	// Choose our preferred sleep mode:
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 
    // Set sleep enable (SE) bit:
    sleep_enable();
 
    // Put the device to sleep:
    sleep_cpu();
 
    // Upon waking up, sketch continues from this point.
    sleep_disable();
}

// watchdog interrupt
ISR (WDT_vect) 
{
  wdt_disable();  // disable watchdog
  //enable ADC
 // ADCSRA |= (1<<ADEN);
}

Bonjour à tous !

Shain:
J'ai cependant une question afin d'optimiser.

Ca fonctionne mais j’aimerai quand même si possible utiliser le code de l’exemple d’Arduino car ça me parait plus propre pour faire des attachInterrupt et detachInterrupt pour PCINT… comment faire pour utiliser la librairie PinChangeInt.h ? je dois l’inclure manuellement dans mon programme ?

Sinon, je ne suis pas sûr de bien comprendre comment faire l’équivalent de attachInterrupt et detachInterrupt sur PCINT21, pourriez-vous m’expliquer svp ?

Pour moi, optimiser le code passe par se débarrasser des librairies (voir ma signature)

Je suis passé par le même problème que toi avec les attachinterrupt... je pense que si tu lit la datasheet, il vaut mieux utiliser les registres directement pour une meilleure maitrise et un code final (compilé) plus léger.

Voila un mémo que je me suis fait pour les interruptions, il faut avoir déjà compris le fonctionnement de celles-ci :

MemoTimer (PDF)

patg_:
J'endors l'AVR et il se réveille soit tout seul à l'expiration du timer du watchdog (8s maxi), soit sur une interruption matérielle (détection de mouvement dans mon cas).

Même en changeant le parametrage du prescaler ?

Sev

Tu peux t'inspirer de la librairie optimisée TinyIrqHandler qui se trouve dans "projet finis". Je n'y ai pas mis le detach interrupt mais c'est facile à faire.

TinyIrqHandler.h

Gère entièrement l'interruption PCINT0. Elle ne comprend qu'une seule fonction pour installer ses routines d'interruptions et une variable. Rien d'autre à gérer.

IRQvecteur(byte irq, void (*adresse)())

exemple:

void MaRoutinePin1()
{
   // Mon code ici
}

void MaRoutinePin2()
{
   // Mon code ici
}

void MaRoutinePin3()
{
   // Mon code ici
}

etc...

void setup
{
   IRQvecteur(1, MaRoutinePin1);
   IRQvecteur(2, MaRoutinePin2);
   IRQvecteur(3, MaRoutinePin3);
}

Voici l'interrupt handler proprement dit :

#include <Arduino.h>

#ifndef TinyIrqHandler_h
#define TinyIrqHandler_h

volatile unsigned long IRQmicros;
void (*IRQvecteurs[5])();
byte IRQpinb = 0xFF;
byte IRQmask = 0;
byte IRQbit;
byte IRQvec;

void IRQvecteur(byte irq, void (*adresse)())
{
  if (IRQpinb == 0xFF)
  {
    IRQpinb = PINB;
  }
  IRQvecteurs[irq] = adresse;
  IRQmask |= 1 << irq;
  PCMSK |= 1 << irq;          // Enable source on pin change interrupt
  GIMSK |= B00100000;         // Enable pin change interrupt
}

ISR(PCINT0_vect)
{
  IRQmicros = micros();
  
  IRQbit = 1;
  for (IRQvec = 0; IRQvec < 5; IRQvec++)
  {
    if (IRQmask & IRQbit)
    {
      if ((PINB & IRQbit) != (IRQpinb & IRQbit))
      {
        IRQpinb &= (255 - IRQbit);
        IRQpinb |= (PINB & IRQbit);
        IRQvecteurs[IRQvec]();
        break;
      }
    }
    IRQbit = IRQbit << 1;
  }
}

#endif

La librairie fournie la valeur de micros() en entrée d'interruption. Elle est disponible par la variable IRQmicros. Il est intéressant de rétablir les interruptions au début de votre routine par la fonction Arduino interrupts() mais si vous devez utiliser la valeur IRQmicros faite le avant de rétablir les interruptions sinon cette valeur risque de changer. La demo fournie fait ainsi afin de toujours laisser la routine timer s'éxécuter le plus vite possible afin de ne pas désynchroniser la transmission série.

JLB

Merci pour vos réactions :slight_smile:

J'ai bien lu vous réponse et en fait je me rends compte que j'ai fait des copier-coller des exemples sans tout comprendre... j’aimerai repartir de 0 pour reformuler mes questions.. Aussi, comme conseillé par UniseV je ne vais pas utiliser de librairies supplémentaires.. je n'ai qu'un pin à manipuler, ça devrait être plus clair avec les manipulations de registres.

Pour résumer : dans la Loop(), si le temps d'exécution du programme dépasse x minutes la méthode sleepNow() est appelée. Un bouton est connecté sur PCINT21 pour réveiller le uC

Le code utile (pour la fonction veille) est le suivant :

void wakeUpNow() {}
void sleepNow() {
// Mise en veille et restart par PCINT ///////////////////////////////////////////
PCICR |= (1<<PCIE2); // A modifier si autre pin !!!
PCMSK2 |= (1<<PCINT21); // A modifier si autre pin !!!
MCUCR = (1<<ISC01)|(1<<ISC00); // Interruption pour flan descendant
pinMode(PIN_INTERRUPT, INPUT); // Bouton en entrée du uC
digitalWrite(PIN_INTERRUPT,HIGH); // Activation de la pull-up interne => 3V3
interrupts(); // Autorise toutes les interruptions

delay(1000); // wait...

set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable(); // Préparation à la mise en veille
sleep_mode(); // Mode veille activé
// Le code est stoppé ici et reprendra là à la mise en route !
sleep_disable(); // Désactivation du mode sommeil
// PCICR &= 0b11111011; //
// PCMSK2 &= 0b11011111; //
noInterrupts(); // Désactive les interruptions dues aux pressions sur PCINTxx ??
setup(); // Reboot du uC
}
ISR(PCINT21_vec){
wakeUpNow();
}

Voici mes questions :

  1. dans l’exemple que j’avais trouvé il y avait la ligne interrupts() .. est-ce que cette ligne est indispensable ? Si j’ai bien compris, l’interruption sur PCINT est active dès que PCICR, PCMSK2 et MCUCR sont configurés pour non ?
  2. A propos, pourquoi dans l’exemple c’est MCUCR qui est configuré ? d’après le datasheet du uC et le mémo UniseV ISC01 et ISC00 appartiennent au registre EICRA…
  3. J’ai lu que la commande sleep_mode() pouvait générer un « race conditions » dans certains cas. Qu’est ce que ça signifie ? Comment savoir si c’est critique dans mon cas aussi ?
  4. Je veux désactiver l’interruption par PCINT à la fin de sleepNow(). Au début j’avais écrit noInterrupts() mais ça ne fonctionne pas. Puis j’ai voulu manipuler les bits mais ça ne fonctionne pas non plus… pourquoi ?
  5. Si après l’exécution de sleepNow() j’appuie a nouveau sur PCINT21, la méthode wakeUpNow est lancée et le setup() aussi ! Je ne comprends pas pourquoi…. Pouvez-vous m’éclairer sur ce point svp ?

Merci !

Mon code n'est pas réellement une librairie. Il est si petit que tu peux le mettre dans ton .ino

A ma connaissance je ne vois rien de plus concis pour gérer le PCINT sans soucis. Tu peux faire autrement mais il faut aiguiller vers la bonne fonction selon la pin qui a changé. Mon code minuscule le fait très bien et il n'est mis en librairie c (pas en librairie C++ trop couteuse) que pour en faciliter l'usage.

JLB

Bonjour,

Shain:

  1. dans l’exemple que j’avais trouvé il y avait la ligne interrupts() .. est-ce que cette ligne est indispensable ? Si j’ai bien compris, l’interruption sur PCINT est active dès que PCICR, PCMSK2 et MCUCR sont configurés pour non ?

Non.
Pour exécuter une interruption il faut qu'elle soit activé dans le registre qui lui est dédié ET que le bit I ("interrupts enable") du registre SREG ("status register") du cpu soit activé.

Pour cela il faut appeler l'instruction "sei" (ou "cli" pour désactiver), instructions présentent en C/C++ sous la forme de macro :

sei(); ou cli();

Les fonctions arduino interrupts() et noInterrupts() ne sont rien d'autre que des alias de sei() et cli().

Shain:
2. A propos, pourquoi dans l’exemple c’est MCUCR qui est configuré ? d’après le datasheet du uC et le mémo UniseV ISC01 et ISC00 appartiennent au registre EICRA…

Regarde à la fin du datasheet dans le chapitre "Registers summary" : tu auras la liste des registres / bit / adresse / n° de page de doc :wink:

Shain:
3. J’ai lu que la commande sleep_mode() pouvait générer un « race conditions » dans certains cas. Qu’est ce que ça signifie ? Comment savoir si c’est critique dans mon cas aussi ?

cf avr-libc: <avr/sleep.h>: Power Management and Sleep Modes
Cela signifie qu'une interruption peut venir se caler entre la condition du sleep et l'activation du sleep.
Comme la mise en sommeil n'est pas atomique (= une seule instruction cpu) il faut gérer ce cas.

Shain:
4. Je veux désactiver l’interruption par PCINT à la fin de sleepNow(). Au début j’avais écrit noInterrupts() mais ça ne fonctionne pas. Puis j’ai voulu manipuler les bits mais ça ne fonctionne pas non plus… pourquoi ?

Si tu veut désactiver les interruptions PCINT d'un port I/O il suffit d'effacer le bit qui lui est associé dans le registre PCICR.
Exemple pour PCINT2 :

PCICR &= ~(1 << PCIE2);

Shain:
5. Si après l’exécution de sleepNow() j’appuie a nouveau sur PCINT21, la méthode wakeUpNow est lancée et le setup() aussi ! Je ne comprends pas pourquoi….

cf avr-libc: <avr/interrupt.h>: Interrupts
Ton nom d'ISR est erroné, c'est PCINT2_vect et non PCINT21_vec !
(sécurité interne de avr-gcc : si une interruption sans vecteur ISR valide est appelée -> BOOM reset)

Je ne critique pas ton code JLB :slight_smile: c'est juste que je voulais comprendre mon code d'abord..

Skywood, merci d'avoir pris le temps de répondre à tout !

  1. Ok, donc interrupts() est indispensable alors..

  2. justement, je ne comprends pas... si j'écris MCUCR = (1<<ISC01)|(1<<ISC00); comme dans l'exemple alors on met les bits IVSEL et IVCE à 1.. mais alors pourquoi ne pas écrire plutôt MCUCR = (1<<IVSEL)|(1<<IVCE); ? ou bien EICRA = (1<<ISC01)|(1<<ISC00)...
    Quelque chose m'échappe encore là..

  3. ok, donc je dois bel et bien suivre le conseil du lien pour l'implémentation..

00081 Example:
00082 \code
00083 #include <avr/interrupt.h>
00084 #include <avr/sleep.h>
00085
00086 ...
00087 set_sleep_mode();
00088 cli();
00089 if (some_condition)
00090 {
00091 sleep_enable();
00092 sei();
00093 sleep_cpu();
00094 sleep_disable();
00095 }
00096 sei();
00097 \endcode

  1. J'avais écrit PCICR &= 0b11111101, ce qui est équivalent non ? et ça n'a pas fonctionné... MAIS : voir point 5.

  2. Je comprends maintenant pourquoi le code précédent (point 4.) ne fonctionnait pas !!! :wink:
    Merci de m'avoir montré cette faute de frappe !!!

Shain:
2. justement, je ne comprends pas... si j'écris MCUCR = (1<<ISC01)|(1<<ISC00); comme dans l'exemple alors on met les bits IVSEL et IVCE à 1.. mais alors pourquoi ne pas écrire plutôt MCUCR = (1<<IVSEL)|(1<<IVCE); ? ou bien EICRA = (1<<ISC01)|(1<<ISC00)...
Quelque chose m'échappe encore là..

Aprés relecture de la tables des registres il y a effectivement une incohérence !
C'est bien :

MCUCR |= (1 << IVSEL) | (1 << IVCE);

et

EICRA |= (1 << ISC01) | (1 << ISC00)

Astuces concernant la manipulation de registres :

  1. toujours utiliser :
  • REGISTER |= BITMASK pour "set" un bit (ou plusieurs)
  • REGISTER &= ~(BITMASK) pour "clear" un bit (ou plusieurs)
    En faisant cela tu conserve les autres bits inchangé (au lieu de les forcer à 0 ce qui pourrait causer des problémes).
  1. Si tu en a marre de faire (1 << BITNAME) pour faire tes bitmask tu peut utiliser la macro _BV (-> "bit value") :
    Syntaxe : _BV(LE_NOM_DU_BIT)
    Exemple : _BV(ISC01)
    Autre exemple :
MCUCR |= _BV(IVSEL) | _BV(IVCE);

Shain:
4. J'avais écrit PCICR &= 0b11111101, ce qui est équivalent non ? et ça n'a pas fonctionné... MAIS : voir point 5.

  1. Je comprends maintenant pourquoi le code précédent (point 4.) ne fonctionnait pas !!! :wink:
    Merci de m'avoir montré cette faute de frappe !!!

Avr-gcc affiche toujours un warning dans ce genre de cas ... mais l'ide arduino fait tout pour pourrir la vie aux développeurs en ne les affichant pas ...

Ok ! c'est bien plus clair maintenant ! merci encore :slight_smile:

(j'aurai peut-être encore des questions demain alors je ne marque pas le sujet en résolu pour le moment)

Super ça marche !

C'était donc ce ISR(PCINT21_vec) qui posait problème. après correction c'est ok.

Je me demandais autre chose.

J'aimerai forcer le RESET après le réveil (à la place de la ligne setup():wink: afin de réinitialiser le uC.
J'ai essayé en forçant un bit du registe WDTCSR à 1 mais ça n'a pas marché.. puis en forçant PC6 à 1 mais pareil..
Y a t-il une méthode propre pour faire un RESET ?

J'ai trouvé différent sujet sur le forum :
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235780325/all
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1273155873
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1246541553
Mais apparemment ça à l'air risqué de manipuler le WDT..

Sinon voici mon code modifié :

/* -------------- */
/* mise en veille */ ///////////////////////////////////////////
/* -------------- */
void wakeUpNow() {}
void sleepNow() {
  
  clear_screen();                     // Ecran noir
  
  // Configuration du pin utilisé pour interruption externe
  PCICR |= (1<<PCIE2);                // A modifier si autre pin !!!
  PCMSK2 |= (1<<PCINT21);             // A modifier si autre pin !!!
  pinMode(PIN_INTERRUPT, INPUT);      // Bouton en entrée du uC
  digitalWrite(PIN_INTERRUPT,HIGH);   // Activation de la pull-up interne => 3V3

  EICRA |= (1<<ISC01) | (1<<ISC00);   // Détection au flanc montant

/*
  // Désactivation de BOD
  MCUCR |= (1<<BODS) | (1<<BODSE);
  MCUCR |= (1<<BODS) & ~(1<<BODSE);
*/

/* 
  // Désactivation ADC
  ACSR |= (1<<ACD);                   // Désactive le comparateur ADC
  ADCSRA &= (0<<ADEN);                // Désactive le convertisseur ADC
  DIDR0 |= 0x3F;                      // Désactive toutes les entrées A/D (ADC0-ADC5)
  DIDR1 |= 0x03;                      // Désactive AIN0 et AIN1
*/

/*
  // Désactivation du WDT
  WDTCSR &= (0<<WDE) | (0<<WDIE);     
*/

  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 
  noInterrupts();                     // Désactivation des interruptions
  sleep_enable();                     // Préparation à la mise en veille
  interrupts();                       // Autorise toutes les interruptions
  detachInterrupt(0);                 // Désactive l'interruption due à Vsync sinon le uC sera réveillé
  sleep_cpu();                        // Mode veille activé
                                      // Le code est stoppé ici et reprendra là à la mise en route !
  sleep_disable();                    // Désactivation du mode sommeil
  
  // Désactivation de l'interruption par PCINT  
  PCICR &= ~(1<<PCIE2);                // A modifier si autre pin !!!
  PCMSK2 &= ~(1<<PCINT21);             // A modifier si autre pin !!!
  EICRA &= (1<<ISC01) | (1<<ISC00);

//  MCUCR &= (1<<BODS) | (1<<BODSE); blablabla...
// Réactivation ADC
// Réactivation du WDT
  
   setup();                            // Reboot du uC
}
ISR(PCINT2_vect){
  wakeUpNow();
} ///////////////////////////////////////////

Pour l’instant j’hésite à désactiver le BOD parce que je me demande s’il y a un risque pour le uC… c’est marqué dans le datasheet qu’il sert de protection pour le uC en cas de sous-alimentation. C’est peut-être dangereux de le désactiver non ?
Même question pour le WDT.

Après, s’il c’est ok de désactiver le BOD je ne suis pas sûr d’avoir compris la procédure pour le faire.
D’après le datasheet il faut que le mode sommeil soit activé avant 4 cycles de clock après avoir mis BODS à 1. Par conséquent le code doit être écrit juste avant sleep_cpu() ?

Merci

Shain:
Y a t-il une méthode propre pour faire un RESET ?

Pas propre mais utilisez partout :

asm volatile("jmp 0x00");

--> Problème : la mémoire RAM et les registres ne seront pas réinitialisé, il faut donc faire le ménage avant

Autre technique, propre cette fois ci :

  • activer le watch-dog en software
  • le configurer pour un timeout trés court
  • lancer une boucle infini

Shain:
Mais apparemment ça à l'air risqué de manipuler le WDT..

Si tu ne l'active pas en hardware il n'y as pas réellement de risque (?).
Je ne vois pas ce qui rendrai dangereux de manipuler le watch-dog ?

Shain:
Pour l’instant j’hésite à désactiver le BOD parce que je me demande s’il y a un risque pour le uC… c’est marqué dans le datasheet qu’il sert de protection pour le uC en cas de sous-alimentation. C’est peut-être dangereux de le désactiver non ?
Même question pour le WDT.

Le BOD ? "Brown-out detect" ?
Quel intéret aurait tu as désactiver le BOD ?
Il est là pour détecter une baisse de tension sur l'alimentation et garder le µc en reset jusqu'à ce que l'alimentation revienne à la normal.
Tu peut le désactiver mais ça ne te sera d'aucune utilité, si ce n'est gagner quelques µA pendant le sleep()

Keep the AVR RESET active (low) during periods of insufficient power supply voltage. This can
be done by enabling the internal Brown-out Detector (BOD).
...
When the Brown-out Detector (BOD) is enabled by BODLEVEL fuses (see Table 19-4 on page
160), the BOD is actively monitoring the supply voltage during a sleep period. In some devices it
is possible to save power by disabling the BOD by software in Power-Down and Stand-By sleep
modes. The sleep mode power consumption will then be at the same level as when BOD is globally
disabled by fuses.

Shain:
Après, s’il c’est ok de désactiver le BOD je ne suis pas sûr d’avoir compris la procédure pour le faire.
D’après le datasheet il faut que le mode sommeil soit activé avant 4 cycles de clock après avoir mis BODS à 1. Par conséquent le code doit être écrit juste avant sleep_cpu() ?

Pour désactiver en hardware le BOD il faut un programmateur ICSP pour AVR.
Ensuite il faut aller modifier les "fusibles" du µc pour mettre le BOD à la valeur "disable".
http://www.engbedded.com/fusecalc/

Sinon en software (pas possible avec tout le ATmega) :

sleep_bod_disable();

cf avr-libc: <avr/sleep.h>: Power Management and Sleep Modes

Merci skywodd !

skywodd:
Autre technique, propre cette fois ci :

  • activer le watch-dog en software
  • le configurer pour un timeout trés court
  • lancer une boucle infini

Shain:
Mais apparemment ça à l'air risqué de manipuler le WDT..

Si tu ne l'active pas en hardware il n'y as pas réellement de risque (?).
Je ne vois pas ce qui rendrai dangereux de manipuler le watch-dog ?

C'est d'après le post ici : http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1235780325/all
La manipulation est par le soft mais retrolefty disait qu'il fallait faire attention. J'ai peut-être mal compris..

Je préfère éviter asm volatile("jmp 0x00"); car le but est justement de ne pas reconfigurer tous les registres :wink:

Concernant le BOD c'est en effet pour gagner en consommation !
C'était d'après le datasheet, je regardais tous ce qui pouvait être désactivé pour consommer moins.
Ahaha, merci pour l'instruction sleep_bod_disable(); je l'avais oubliée ! Mais finalement je ne vais pas y toucher.

Bonjour,

skywodd:
Autre technique, propre cette fois ci :

  • activer le watch-dog en software
  • le configurer pour un timeout trés court
  • lancer une boucle infini

J'ai essayé quelque chose mais ce n'est pas convaincant..

wdt_enable(WDTO_30MS); 
while(1){}

Est-ce que tu pensais à autre chose skywodd ?
Comment faire sinon ?

encore une chose.

J'ai mesuré la consommation de courant de mon circuit et je suis assez étonné de constater que le mode sommeil ne fait pas baisser la consommation...
Pourtant, d'après la documentation, je devrai gagner entre 9 et 1.2mA... (alimentation 3V3, oscillateur externe 8MHz)..
Le uC a pourtant bien l'air d'être "endormi".. comment être sûr que mon code fonctionne sinon ?

Merci :slight_smile:

Shain:
J'ai essayé quelque chose mais ce n'est pas convaincant..

wdt_enable(WDTO_30MS); 

while(1){}


Est-ce que tu pensais à autre chose skywodd ?
Comment faire sinon ?

Heu ... je pensai effectivement à cà ...

#include <avr/wdt.h>

void reboot() {
  wdt_disable();  
  wdt_enable(WDTO_15MS);
  while(1);
}

Ça ne marche pas ? (hoho ?)

Shain:
J'ai mesuré la consommation de courant de mon circuit et je suis assez étonné de constater que le mode sommeil ne fait pas baisser la consommation...
Pourtant, d'après la documentation, je devrai gagner entre 9 et 1.2mA... (alimentation 3V3, oscillateur externe 8MHz)..
Le uC a pourtant bien l'air d'être "endormi".. comment être sûr que mon code fonctionne sinon ?

Mettre en veille ne suffit pas il faut aussi eteindre les périphériques qui ne servent pas :wink:
http://www.nongnu.org/avr-libc/user-manual/group__avr__power.html
http://jeelabs.org/2009/05/16/power-consumption-more-savings/

Ca à l'air de marcher finalement, je ne sais plus quel était le comportement ce matin quand j'ai testé. Peut-être que j'avais oublié d'écrire "interrupts();" avant ces lignes.

Merci :slight_smile:

skywodd:
Mettre en veille ne suffit pas il faut aussi eteindre les périphériques qui ne servent pas :wink:
avr-libc: <avr/power.h>: Power Reduction Management
http://jeelabs.org/2009/05/16/power-consumption-more-savings/

C'est pour ça que je pensais désactiver le BOD et WDT etc. !
J'avais lu la doc sur www.nongnu.org aussi mais j'avais oublié.. Merci du rappel !!!

Bon ben on peut dire que le sujet est résolu alors :slight_smile:
Merci encore pour ton aide skywodd :slight_smile:

Ah, encore juste une chose..

Est-ce que la ligne suivante est vraiment utile dans mon code ?

EICRA |= (1<<ISC01) | (1<<ISC00);   // Détection au flanc montant

Je détecte l'interruption sur PCINT21.
D'après la doc de l'ATmega328, EICRA permet de configurer le mode de détection pour INT0 et INT1.. comme mon cas ne correspond ni à l'un ni à l'autre interruption est ce que le registre EICRA m'est utile ?

Sinon, comment paramètrer le mode de détection sur PCINT21, ou un autre svp ?

Merci

Shain:
Je détecte l'interruption sur PCINT21.
D'après la doc de l'ATmega328, EICRA permet de configurer le mode de détection pour INT0 et INT1.. comme mon cas ne correspond ni à l'un ni à l'autre interruption est ce que le registre EICRA m'est utile ?

Non tu peut la virer effectivement :wink:

Shain:
Sinon, comment paramètrer le mode de détection sur PCINT21, ou un autre svp ?

C'est pas possible en hardware, les PCINT (port change interrupts) sont de type CHANGE obligatoirement (d'ou leurs noms).
Pour faire du FALLING / RISING il faut stocker l'état précédant de la broche et lire l'état courant puis déterminer le type de front en software.

Tu peut prendre exemple (voir directement utiliser le code) de la librairie PCint :
http://arduino.cc/playground/Main/PcInt

D'accord ! merci encore skywodd :slight_smile: