[Résolu] Problème watchdog arduino mega

Bonjour

Le code ci-dessous, tout simple, fonctionne parfaitement avec une UNO

#include <avr/wdt.h>

void setup()
{
  wdt_disable();
  Serial.begin(9600);
  Serial.println("\nProgramme demo watchdog");

  Serial.print("Attente 10 secondes");
  for (uint8_t i=0; i<10; i++)
  {
    delay(1000);
    Serial.print('.');
  }
  Serial.println();

  Serial.println("Activation du watchdog");
  wdt_enable(WDTO_8S);

  Serial.print("Fonctionnement normal 10 secondes");
  for (uint8_t i=0; i<10; i++)
  {
    delay(1000);
    Serial.print('.');
    wdt_reset();
  }
  Serial.println();

  Serial.print("Declenchement watchdog");
  for (uint8_t i=0; i<10; i++)
  {
    delay(1000);
    Serial.print('.');
  }
  Serial.println();

  Serial.println("Ceci ne doit pas s'afficher");
}

void loop() {}

Mais sur une Mega, rien à faire.
Le premier reboot() se déclenche, puis la carte devient "muette" : impossible d'y téléverser un nouveau code. La fermeture / ouverture du terminal série de l'IDE ne la réinitialise pas.
Seule la mise hors tension permet de la réinitialiser.

Résolution

Si le programme ci-dessus fait planter votre arduino mega, c'est qu'elle vous a probablement été livrée avec un bootloader obsolète, incompatible avec le watchdog.

La solution consiste à remettre à niveau le bootloader de la carte.

Méthode proposée :

  1. prendre une carte UNO

  2. y téléverser le programme ArduinoISP qui se trouve dans les exemples de l'IDE

  3. débrancher la carte

  4. cabler la UNO -> MEGA comme suit :
    GND -> GND
    5V -> 5V
    10 -> RST
    11 -> 51
    12 -> 50
    13 -> 52

  5. Rebrancher la UNO au PC, puis dans l'IDE :
    changer le type de carte : arduino mega
    changer le graveur : Arduino as ISP
    graver la séquence d'initialisation

Le programme ci-dessus peut à présent être à nouveau téléversé dans la MEGA, et devrait fonctionner normalement

Bon j'ai trouvé une solution qui marche aussi bien sur uno que sur mega, mais suis quand même curieux de connaître vos avis.

Je recrée mon propre watchdog en utilisant l'interruption temporelle timer2

#include <MsTimer2.h>

const uint8_t watchdog_max = 8; //En secondes
volatile uint8_t watchdog_courant = 0;

void (* reboot) (void) = 0;

void razWatchdog()
{
  watchdog_courant = 0;
}

void gererWatchdog()
{
  watchdog_courant++;
  if (watchdog_courant >= watchdog_max)
  {
    MsTimer2::stop();
    reboot();
  }
}
void demarrerWatchdog()
{
  razWatchdog();
  MsTimer2::set(1000, gererWatchdog);
  MsTimer2::start();
}

void arreterWatchdog()
{
  MsTimer2::stop();
}

void setup()
{
  arreterWatchdog();
  Serial.begin(9600);
  Serial.println("\nProgramme demo watchdog");

  Serial.print("Attente 10 secondes");
  for (uint8_t i=0; i<10; i++)
  {
    delay(1000);
    Serial.print('.');
  }
  Serial.println();

  Serial.println("Activation du watchdog");
  demarrerWatchdog();

  Serial.print("Fonctionnement normal 10 secondes");
  for (uint8_t i=0; i<10; i++)
  {
    delay(1000);
    Serial.print('.');
    razWatchdog();
  }
  Serial.println();

  Serial.print("Declenchement watchdog");
  for (uint8_t i=0; i<10; i++)
  {
    delay(1000);
    Serial.print('.');
  }
  Serial.println();

  Serial.println("Ceci ne doit pas s'afficher");
}

void loop() {}

étrange, j'ai 2 mega (clones Chinois) qui tourne avec le watchdog et je ne constate pas ce pb

Et avec le tout premier programme ci-dessus, elles fonctionnent ?

bricoleau:
Et avec le tout premier programme ci-dessus, elles fonctionnent ?

et bien non, même pb que toi >:(
j'ai l'impression que si le watchdog pète pendant une com sur le port série ça le plante sérieusement (j'ai du changer de port pour ne pas redemarrer mon pc)
il faudrait essayer en supprimant les Serial.print dans la boucle de déclenchement

Merci pour le test

J'y crois moyen au conflit avec la liaison série.
D'abord parce que je n'envoie qu'un caractère '.' par seconde au moment du déclenchement du watchdog, donc la probabilité du reset pendant la milliseconde de sollicitation de la liaison série me semble très faible.

Ensuite ça fonctionne très bien sur une uno. Il devrait y avoir le même conflit.

La vérité est ailleurs....

Apparemment, l'explication (un peu étonnante) serait :

Lorsque le watchdog se déclenche :

  1. la réinitialisation des registres de l'atmega induit une réinit du délai associé au watchdog, qui passe à 15 ms
  2. le bootloader ne désactive pas le watchdog, et n'a pas le temps de terminer son traitement avant expiration du délai de 15 ms et nouveau déclenchement du watchdog.

La mega passe alors son temps à se réinitialiser toutes les 15 ms, sans jamais atteindre la fonction setup()
La solution propre serait de flasher un nouveau bootloader, à partir d'une version alternative compatible watchdog (optiboot).

Si c'est bien ça, cela veut dire qu'il est impossible d'uploader un programme utilisant le watchdog sur une mega "sortie d'usine", sans un minimum de manips préalables.

Ce qui ne m'arrange pas du tout, notamment pour ma bibliothèque ordonnanceur.h qui devient alors nettement moins facile à mettre en œuvre avec une mega.

Du coup, je pense me rabattre sur la solution de contournement qui utilise le timer2.

ça parait très étonnant car je l'utilise sur ma ruche de 2 manières :

  • en automatique sur blocage de je ne sais quoi de temps en temps (2 ou 3 jours) ...
  • en manuel par une commande spécifique passée par le moniteur série ou même a distance par le serveur web, je le fait rentrer dans une boucle while(1) et le watchdog déclenche
    il est déclaré en fin de setup et la raz est faite dans la loop

par contre je me suis fait avoir sur le DUE, le fait de déclarer le watchdog (void watchdogSetup(void)) le met en fonction avec un temps de 16s (sans faire de watchdogEnable(...)) si la raz est faite uniquement dans la loop et si le setup dure plus de 16s et bien le DUE redémarre sans arrêt

Voilà qui est intéressant.

Tu utilises bien les mêmes primitives wdt_disable(), wdt_enable() et wdt_reset() que dans mon programme initial ?

Quelle valeur passes-tu à wdt_enable() ?

Et évidemment tu as bien une arduino mega pour ta ruche, sans avoir bidouillé le bootloader?

Quelle version de l'IDE ?

Je me demande comment peut-on vérifier la version de bootloader installée sur une carte arduino.
C'est peut-être la mienne qui m'a été fournie avec un bootloader ante-diluvien.

J'imagine qu'il faudrait passer par l'ICSP pour extraire le contenu intégral de la flash, bootloader inclus.
Ca risque d'être pénible.

Ou alors, avec du bol, peut-être qu'un dump du contenu de la flash sur le terminal Série ferait apparaître une signature. Je vais essayer ça.

oui tout comme toi :

déclarations :
...
#include <avr/wdt.h> // watchdog
fin du setup ():
...
wdt_enable(WDTO_8S); // watchdog 8s 
début de loop ():
wdt_reset(); // watchdog démarré on le raz a chaque passage sinon reboot 
...

c'est bien 3 méga (clones Chinois achetés en 3 fois dans des boutiques différentes) non modifiés
j'utilise l'IDE 1.0.6 pour les méga
et ton code me plante le méga qui me sert pour le développement

Et est-ce que le watchdog de ton programme fonctionne bien sur ta carte mega de développement ?

Problème résolu

L'hypothèse était la bonne : le problème venait bien du bootloader préinstallé sur ma mega, incompatible avec le watchdog.

J'ai regravé le bootloader via l'IDE et une carte uno (arduino as ISP), et le watchdog fonctionne à présent normalement.

Comme quoi, avec les imports chinois, il vaut mieux commencer par remettre le bootloader à niveau avant de jouer.
Je suppose que ta carte de dev souffre du même problème.
Merci pour le coup de main.

[Edit : premier post mis à jour]

bricoleau:
Je suppose que ta carte de dev souffre du même problème.

je te confirme ma troisième carte (la dernière livrée) à le même pb les 2 autres ne l'ont pas
merci de l'info je vais remédier à ça

PS : J'ai ajouté un mode op dans le tout premier post pour remettre à niveau le bootloader