Go Down

Topic: Uno + Ethernet Shield : comportement aléatoire (Read 5527 times) previous topic - next topic

bigben99

Bonjour,

Pour bien situer le contexte, je vais présenter mon projet en quelques mots. je souhaite équiper ma maison d'un réseau de modules remplissant différentes fonctions (relevé de température, relevé de compteur EDF, capteur d'ouverture de porte, ...). Au centre de ce reseau, je souhaite implémenter un "serveur" qui sera chargé de piloter les différents modules, de collecter des informations auprès des modules et de stocker ces informations sur Internet et sur carte SD.

Je travaille donc sur mon "serveur" qui se compose pour l'instant :
- d'un arduino Uno
- d'un Ethernet Shield
- d'une carte SD

Par la suite, le serveur se vera adjoindre un XBee Shield.

Au niveau code, je souhaite donc que mon serveur se connecte sur ma box pour ensuite faire une synchronisation de l'heure via NTP puis qu'il crée les fichiers nécessaires pour travailler :
- un fichier de log d'activité
- un fichier de traces applicatives (en cas d'erreur lors du traitement)
- un fichier de données (qui correspond aux données envoyées dans une BDD distante via HTTP & PHP)

J'ai donc procédé par étapes pour implémenter mon code :
1. Initialisation Ethernet : OK
2. Initialisation UDP : OK
3. Synchronisation NTP : OK

Ces 3 premières étapes se sont déroulées sans problème.
Les problèmes ont commencés lors de la 4ème étape d'initialisation de la carte SD.
a) lors de l'initialisation de la carte SD, elle n'est pas toujours reconnue
Code: [Select]
int CHIP_SELECT = 4;

Sd2Card card;

card.init(SPI_HALF_SPEED, CHIP_SELECT);

La fonction init me retourne aléatoirement true ou false

b) lorsque j'ajoute le code de création d'un fichier sur la carte SD, j'ai un comportement totalement aléatoire de l'ensemble de mon code !
- parfois, cela plante à l'initialisation Ethernet, l'adresse MAC est vide...
- parfois, lors de la synchronisation NTP, j'ai un statut à OK mais aucune date ni heure !
Code: [Select]
File logFile;

logFile = SD.open("log.txt", FILE_WRITE);


Ci-dessous le code complet de mon serveur
Code: [Select]
/*
* 1. Synchronisation NTP
* 2. Log sur carte SD
* 3. Reception de données sur port serie
* 4. Transmission de données HTTP
*/

#include <Ethernet.h>
#include <EthernetUdp.h>
#include <Time.h>
#include <SPI.h>
#include <SD.h>

byte ETHERNET_MAC_ADDRESS[] = { 0x90, 0xA2, 0xDA, 0x80, 0x0A, 0x4C};
int UDP_LISTEN_PORT = 8888;
int CHIP_SELECT = 4;
IPAddress NTP_SERVER_IP(134, 214, 100, 6);
const byte NTP_PACKET_SIZE = 48;
byte TIME_ZONE_OFFSET = 2;

EthernetUDP Udp;
Sd2Card card;
SdVolume volume;
SdFile root;
File logFile;
//File traceFile;
//File dataFile;

byte SyncDay;

void setup() {
  Serial.begin(115200);
  Serial.println("Demarrage...");
// Synchronisation NTP
  Serial.print("Initialisation Ethernet (MAC : ");
  Serial.print(macAddressToString());
  Serial.print(")...");
  while(Ethernet.begin(ETHERNET_MAC_ADDRESS) == 0) {
    delay(60000);
    Serial.print('.');
  }
  Serial.println(" OK");
  Serial.print("Adresse IP : ");
  Serial.println(Ethernet.localIP());
  Serial.print("Initialisation UDP...");
  Udp.begin(UDP_LISTEN_PORT);
  Serial.println(" OK");
  Serial.print("Synchronisation NTP (Port : ");
  Serial.print(UDP_LISTEN_PORT);
  Serial.print(")...");
  setSyncProvider(getNTPTime);
  SyncDay = day(now());
  while(timeStatus() == timeNotSet) {
    Serial.print('.');
  }
  Serial.println(" OK");
  Serial.print("Date Heure : ");
  Serial.println(DateTimeToString());

// Initialisation Carte SD
  Serial.print("Initialisation de la carte SD...");
  pinMode(10, OUTPUT);
  if(!card.init(SPI_HALF_SPEED, CHIP_SELECT)) {
    Serial.println(" KO");
  } else {
    Serial.println(" OK");
  }
  Serial.print("Type de carte : ");
  switch(card.type()) {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;
    case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;
    case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC");
      break;
    default:
      Serial.println("Inconnu");
  }
  if (!volume.init(card)) {
    Serial.println("Impossible de trouver une partition FAT16/FAT32.\nAssurez vous que la carte SD a ete formatee");
  }
  uint32_t volumesize;
  Serial.print("Volume de type : FAT");
  Serial.println(volume.fatType(), DEC);
  volumesize = volume.blocksPerCluster();
  volumesize *= volume.clusterCount();
  volumesize *= 512;
  Serial.print("Taille du volume (octets) : ");
  Serial.println(volumesize);
  Serial.println("Liste des fichiers presents sur la carte (nom, date et taille) :");
  root.ls(LS_R | LS_DATE | LS_SIZE);
  logFile = SD.open("log.txt", FILE_WRITE);
//  traceFile = SD.open("trace.txt", FILE_WRITE);
//  dataFile = SD.open("data.txt", FILE_WRITE);
  Serial.println("Initialisation terminee");
}

void loop() {
  if(SyncDay != day(now())) {
    Serial.print("Jour : ");
    Serial.print(SyncDay);
    Serial.print(" / Date Heure : ");
    Serial.println(DateTimeToString());
    Serial.println();
    SyncDay = day(now());
    setSyncProvider(getNTPTime);
  }
}

time_t getNTPTime() {
  /* Buffer contenant le paquet UDP NTP */
  byte buffer[NTP_PACKET_SIZE] = {0};

  /* Création de la requête NTP */
  buffer[0] = 0b11100011; // LI, Version, Mode
  buffer[1] = 0;          // Stratum, or type of clock
  buffer[2] = 6;          // Polling Interval
  buffer[3] = 0xEC;       // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  buffer[12] = 49;
  buffer[13] = 0x4E;
  buffer[14] = 49;
  buffer[15] = 52;

  /* Envoi d'une requete NTP au serveur spécifié */   
  Udp.beginPacket(NTP_SERVER_IP, 123);
  Udp.write(buffer, NTP_PACKET_SIZE);
  Udp.endPacket();
  delay(1000);
   
  /* Lecture de la réponse */
  if (Udp.parsePacket()) {
   
    /* Mise en buffer du paquet UDP */
    Udp.read(buffer, NTP_PACKET_SIZE);

    /* Lecture des données binaire */
    unsigned int highWord = word(buffer[40], buffer[41]);
    unsigned int lowWord = word(buffer[42], buffer[43]);
     
    /* Calcul du timestamp (nombre de secondes depuis 1 janvier 1900) */
    time_t timestamp = ((unsigned long) highWord << 16) | lowWord;
     
    /* Calcul du temps courant en fonction de la zone */
    time_t currentTime = timestamp - 2208988800UL + (TIME_ZONE_OFFSET * 3600L);
     
    /* Retourne le temps NTP courant */
    return currentTime;
  }
   
  /* Erreur */
  return 0;
}

String DateTimeToString() {
  String s;
  time_t t = now();
 
  if(day(t) < 10) {
    s = s + '0';
  }
  s = s + day(t) + '/';
  if(month(t) < 10) {
    s = s + '0';
  }
  s = s + month(t) + '/' + year(t) + ' ';
  if(hour(t) < 10) {
    s = s + '0';
  }
  s = s + hour(t) + ':';
  if(minute(t) < 10) {
    s = s + '0';
  }
  s = s + minute(t) + ':';
  if(second(t) < 10) {
    s = s + '0';
  }
  s = s + second(t);
 
  return s;
}

String macAddressToString() {
  String s;
 
  for(byte i = 0; i < 6; i++) {
    if(ETHERNET_MAC_ADDRESS[i] <= 16) {
      s = s + '0';
    }
    s = s + String(ETHERNET_MAC_ADDRESS[i], HEX);
    if(i < 5) {
      s = s + ":";
    }
  }
  s.toUpperCase();
  return s;
}


skizoh

Attention au conflit ethernet et SD et surtout attention tout cour ^^ l'ethernet shield est un peut chargé et il y a souvent des pins utilisé pour plusieurs chose à la fois donc fait bien attention à ne pas utilisé trop de chose simultanément genre connexion ethernet juste après la SD etc, j'ai déjà eu ce style de problème et si tu décompose bien ça passe.


( comme prévu je vois dans ton code des commandes udp et sd entre mêlé ! évite ;) )

Skizo !

bigben99

Dois-je en déduire que l'on ne peut pas faire de l'Ethernet et du SD ?

Comment puis-je stopper l'UDP une fois la synchronisation terminée pour pouvoir passer sur l'utilisation de la carte SD ?

bigben99

J'ai une piste pour mon problème mais si qqun peut la valider ca m'aiderait et ca pourrait surement servir à d'autres.

Donc en utilisation F("chaine de caractères") pour charger en mémoire flash toutes mes chaines, il semble que le problème disparaisse.

Dois-je en déduire que j'avais un problème de RAM ?

skizoh

Si tu à remplacer la SD par la RAM ouai tu à surement résolut les conflits, sinon il faut que tu stop le service udp à chaque écriture sur la carte SD ce qui n'est pas dramatique l'UDP est en non connecté donc aucun problème mis à part que tu peut louper quelque messages.

bigben99

Je n'ai pas remplacée la SD par la RAM. Si je ne dis pas de bétise j'ai simplement empéché le chargement en RAM de toutes mes chaines de caractères.

Comment puis-je stoper le service UDP, dans les méthodes UDP, il y a bien une méthodes begin() mais pas de stop.

skizoh

avec la pin ethernet directement, pour cette histoire de RAM j'ai pas bien compris du coup, mais si ça marche temps mieux.

Pour désactiver l'ethernet tu doit faire:

pinMode(4, OUTPUT);
pinMode(2, OUTPUT);//setup(){}

digitalWrite(2,HIGH);// activer SD
digitalWrite(4,LOW);// desactiver ethernet

digitalWrite(4,HIGH);// activer ethernet
digitalWrite(2,LOW);// desactiver SD

on ma dit que c'était bourrin mais avec ça tu évite les possibilités de conflit du moins pour moi ça fonctionnait niquel :)

Skizo!

bigben99

C'est pas pin10 pour Ethernet et pin4 pour SD ?

skizoh

si tout dépend de ta carte, tu adapte après.

Pac2Kro


Comment puis-je stoper le service UDP, dans les méthodes UDP, il y a bien une méthodes begin() mais pas de stop.


Si, si : http://forum.arduino.cc/index.php?topic=141161.msg1064530#msg1064530

bigben99

Merci pour l'info, mais comme indiqué dans ton autre sujet, la fonction stop n'est pas documentée... :)

Pac2Kro


Merci pour l'info, mais comme indiqué dans ton autre sujet, la fonction stop n'est pas documentée... :)


Ce n'est pas parce qu'elle n'est pas documentée, qu'elle n'existe pas et qu'elle ne fonction pas.

bigben99

Aucun soucis, je suis d'accord avec toi, ce n'est pas parce qu'elle n'est pas documentée qu'elle n'existe pas et qu'elle ne fonctionne pas, mais par contre, ça limite sa visibilité :)

Sinon, après une période d'amélioration mon code est de nouveau malade... et ce qui est le plus rageant, c'est le coté aléatoire des problèmes.

skizoh

Bien souvent le côté aléatoire des pannes est du à une multitude de pannes que tu ne vois que une par une à chaque fois ^^' bon courage !

bricoleau


J'ai une piste pour mon problème mais si qqun peut la valider ca m'aiderait et ca pourrait surement servir à d'autres.

Donc en utilisation F("chaine de caractères") pour charger en mémoire flash toutes mes chaines, il semble que le problème disparaisse.

Dois-je en déduire que j'avais un problème de RAM ?


Les symptômes décrits dans ton premier post me font effectivement complètement penser à un problème de débordement de capacité de RAM.

Cela m'est arrivé aussi lors de l'ajout de code avec trop de chaînes de caractères.

Pour affiner le diagnostic, tu peux utiliser la fonction freeRam() qui donne la quantité de RAM disponible. Par exemple insérer dans la fonction setup() un Serial.println(freeRam()).

Code: [Select]

int freeRam() {
  extern int __heap_start,*__brkval;
  int v;
  return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval); 
}



Tutoriels arduino : http://forum.arduino.cc/index.php?topic=398112.0

Go Up