Problème cohabitation de deux bibliothèques associées à deux capteurs

Bonjour,

Je cherche à réaliser un programme simple pour un Arduino Nano me permettant d'inscrire des données d'un capteur 9DOF de référence ICM20480 produit par Adafruit sur une carte micro-SD grâce à un lecteur de carte, le tout en continu pendant toute la durée de prise de mesures.

Pour cela, j'ai cherché à utiliser la bibliothèque <SD.h> fournie par défaut sur Arduino IDE, et particulièrement l'exemple "NonBlockingWrite" :

#include <SD.h>

// file name to use for writing
const char filename[] = "demo.txt";

// File object to represent file
File txtFile;

// string to buffer output
String buffer;

unsigned long lastMillis = 0;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // reserve 1kB for String used as a buffer
  buffer.reserve(1024);

  // set LED pin to output, used to blink when writing
  pinMode(LED_BUILTIN, OUTPUT);

  // init the SD card
  if (!SD.begin()) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    while (1);
  }

  // If you want to start from an empty file,
  // uncomment the next line:
  // SD.remove(filename);

  // try to open the file for writing
  txtFile = SD.open(filename, FILE_WRITE);
  if (!txtFile) {
    Serial.print("error opening ");
    Serial.println(filename);
    while (1);
  }

  // add some new lines to start
  txtFile.println();
  txtFile.println("Hello World!");
}

void loop() {
  // check if it's been over 10 ms since the last line added
  unsigned long now = millis();
  if ((now - lastMillis) >= 10) {
    // add a new line to the buffer
    buffer += "Hello ";
    buffer += now;
    buffer += "\r\n";

    lastMillis = now;
  }

  // check if the SD card is available to write data without blocking
  // and if the buffered data is enough for the full chunk size
  unsigned int chunkSize = txtFile.availableForWrite();
  if (chunkSize && buffer.length() >= chunkSize) {
    // write to file and blink LED
    digitalWrite(LED_BUILTIN, HIGH);
    txtFile.write(buffer.c_str(), chunkSize);
    digitalWrite(LED_BUILTIN, LOW);

    // remove written data from buffer
    buffer.remove(0, chunkSize);
  }
}

Celui-ci fonctionne à merveille et réponds parfaitement à mon besoin.

Cependant, dès que j'inclus les bibliothèques associée à mon capteur, <Adafruit_ICM20X.h> et <Adafruit_ICM20948.h>, que je définis une variable associée à ces bibliothèques, seule la partie du code incluse dans le void setup s'exécute et s'inscrit sur la carte SD tandis que la partie contenue dans le void loop ne semble pas être exécutée et n'inscrit rien de plus sur la carte.

Ci-joint une représentation du montage avec un autre accéléromètre+gyroscope afin de visualiser les branchements:

Pour précision, le lecteur de carte utilise le protocole SPI pour communiquer avec l'Arduino tandis que le ICM utilise le protocole I2C, cela pourrait-il être la cause du disfonctionnement ?

Je m'excuse d'avance pour les imprécisions et erreurs de langage, je débute en programmation sur Arduino.

1 Like

c'est un joli premier post bien expliqué et avec les balises de code. bravo

il ne manque que votre code pour le programme qui ne fonctionne pas
(a priori pas de souci entre I2C et SPI - peut -être un souci de place mémoire ?)

oubli de ma part, voici le code, très peu différent de celui inclus dans le post mais qui ne fonctionne pas:

#include <SD.h>
#include <Adafruit_ICM20X.h>
#include <Adafruit_ICM20948.h>

Adafruit_ICM20948 icm;

// file name to use for writing
const char filename[] = "demo.txt";

// File object to represent file
File txtFile;

// string to buffer output
String buffer;

unsigned long lastMillis = 0;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // reserve 1kB for String used as a buffer
  buffer.reserve(1024);

  // set LED pin to output, used to blink when writing
  pinMode(LED_BUILTIN, OUTPUT);

  // init the SD card
  if (!SD.begin()) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    while (1);
  }

  // If you want to start from an empty file,
  // uncomment the next line:
  // SD.remove(filename);

  // try to open the file for writing
  txtFile = SD.open(filename, FILE_WRITE);
  if (!txtFile) {
    Serial.print("error opening ");
    Serial.println(filename);
    while (1);
  }

  // add some new lines to start
  txtFile.println();
  txtFile.println("Hello World!");
}

void loop() {
  // check if it's been over 10 ms since the last line added
  unsigned long now = millis();
  if ((now - lastMillis) >= 10) {
    // add a new line to the buffer
    buffer += "Hello ";
    buffer += now;
    buffer += "\r\n";

    lastMillis = now;
  }

  // check if the SD card is available to write data without blocking
  // and if the buffered data is enough for the full chunk size
  unsigned int chunkSize = txtFile.availableForWrite();
  if (chunkSize && buffer.length() >= chunkSize) {
    // write to file and blink LED
    digitalWrite(LED_BUILTIN, HIGH);
    txtFile.write(buffer.c_str(), chunkSize);
    digitalWrite(LED_BUILTIN, LOW);

    // remove written data from buffer
    buffer.remove(0, chunkSize);
  }
}

quand vous compilez il vous dit à la fin un truc du genre

Les variables globales utilisent 1405 octets (68%) de mémoire dynamique, ce qui laisse 643 octets pour les variables locales. Le maximum est de 2048 octets.

vous avez combien de RAM dispo?

parce que là par exemple vous en demandez 1024 (et le code ne dit pas si ça fonctionne ou pas.. il faudrait tester si ça retourne 1 c'est que c'est OK)

D'après les infos constructeur il n'y a que 2 kilo de ram, le problème peut donc provenir de là...

Réduire la taille de la ram allouée au buffer pourrait régler le problème ?

Comment puis je tester et voir si le programme retourne effectivement 1 comme vous dites ?

essayez

#include <SD.h>
#include <Adafruit_ICM20X.h>
#include <Adafruit_ICM20948.h>

Adafruit_ICM20948 icm;

// file name to use for writing
const char filename[] = "demo.txt";

// File object to represent file
File txtFile;

// string to buffer output
String buffer;

unsigned long lastMillis = 0;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // reserve 1kB for String used as a buffer
  if (buffer.reserve(256) == 0) {
    Serial.println(F("problème mémoire"));
    while(true);
  }

  // set LED pin to output, used to blink when writing
  pinMode(LED_BUILTIN, OUTPUT);

  // init the SD card
  if (!SD.begin()) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    while (1);
  }

  // If you want to start from an empty file,
  // uncomment the next line:
  // SD.remove(filename);

  // try to open the file for writing
  txtFile = SD.open(filename, FILE_WRITE);
  if (!txtFile) {
    Serial.print("error opening ");
    Serial.println(filename);
    while (1);
  }

  // add some new lines to start
  txtFile.println();
  txtFile.println("Hello World!");
}

void loop() {
  // check if it's been over 10 ms since the last line added
  unsigned long now = millis();
  if ((now - lastMillis) >= 50) {
    // add a new line to the buffer
    buffer += "Hello ";
    buffer += now;
    buffer += "\r\n";

    lastMillis = now;
  }

  // check if the SD card is available to write data without blocking
  // and if the buffered data is enough for the full chunk size
  unsigned int chunkSize = txtFile.availableForWrite();
  if (chunkSize && buffer.length() >= chunkSize) {
    // write to file and blink LED
    digitalWrite(LED_BUILTIN, HIGH);
    txtFile.write(buffer.c_str(), chunkSize);
    digitalWrite(LED_BUILTIN, LOW);

    // remove written data from buffer
    buffer.remove(0, chunkSize);
  }
}

j'ai réduit à 256 octets le buffer, rajouté le test de succès de la réservation et augmenté le temps à 50ms entre 2 écritures dans le buffer

Je viens de tester votre proposition, malheureusement j'ai toujours le même problème qui se produit, à savoir le seul élément écrit sur la carte SD étant le "hello world" du void loop.

Il n'y a pas non plus de message comme quoi le problème mémoire se produit.

J'ai pourtant réessayé avec le programme de base en changeant juste l'espace alloué au buffer, qui reste fonctionnel, le problème ne semble donc pas venir de là même si ce n'est pas une mauvaise chose d'avoir vu ce qui aurait pu devenir un potentiel problème à l'avenir.

Je vais continuer mes recherches, mais si vous avez une autre idée sur la source du problème je suis preneur :slight_smile:

Conbien de mémoire dispo?

Cette opération

Nécessite de la ram aussi

D’autre part la chaîne va grandir de toutes façons jusqu’à 512 octets car c’est la taille du buffet SD

Il faudrait modifier le test
if (chunkSize && buffer.length() >= chunkSize) {

Pour faire l’écriture avant - à la taille du reserve()

Bonjour

txtFile = SD.open(filename, FILE_WRITE);

Ok le fichier est ouvert ,
mais il me semble qu'il manque, quelque part,
une ligne qui fermerait le fichier :

txtFile.close(filename);

extrait de : arduino -> Reference > Libraries > Sd > Close


SD - close()
Close the file, and ensure that any data written to it is physically saved to the SD card.

Oui - c'est un code d'exemple qui ne prévoit pas que le programme s'arrête un jour (pas réaliste).

L'objectif de ce code est de chercher à optimiser le moment où le transfert du buffer de 512 octets est effectué entre l'arduino et la carte SD. le code tel qu'il fonctionne remplit un buffer annexe qui sert de double tampon. Quand le double tampon dépasse les 512 octets alors on dump 512 octets via l'API, ce qui remplit le buffer de la bibliothèque SD ce qui déclenche l'écriture et on conserve ce qu'il y avait en trop dans le double tampon.

il faudrait normalement prévoir un moyen de dire qu'on a fini d'enregistrer pour que le dernier buffer soit écrit sur la carte.

je pense que c'est un vieux code qui ne comprend pas trop comment la bibliothèque SD (ou mieux prendre sdFat) gère son buffer interne... Personnellement je ne vois pas d'intérêt à cette approche hyper gourmande en mémoire

Je te remercie pour ton message très clair, car je n'avais pas bien compris le but recherché.

En utilisant SD.h, je ne vois pas comment forcer le transfert effectif du contenu du tampon sur la carte SD autrement qu'en demandant la fermeture du fichier.

il y a la fonction flush() qui fait cela.
(flush() est aussi appelé quand on fait close() effectivement pour s'assurer que le buffer est bien sauvegardé en entier)

1 Like

Oui, je viens tout juste de la trouver : flush() :slight_smile:

bravo :slight_smile:

Merci, mais bon, j'aurais du prendre le temps d'aller lire la doc avant de poster :woozy_face:

:slight_smile: pas grave

flush() s'applique à tout flux (Stream), par exemple si vous voulez vous assurer que tous les octets d'un Serial.print("coucou"); sont bien partis avant de passer aux instructions suivantes, vous pouvez faire un Serial.flush(); juste ensuite

ça peut être utile quand on fait du debug par exemple, pour être sûr que ce que l'on voit à l'écran comme trace correspond bien à la progression du code

Bonjour,
Je ne comprend pas ces interventions sur cette partie du soft s'il fonctionne à merveille.

Pourquoi la démarche n'est pas de rechercher ce problème?
Quelque chose m'échappe ?

Bonjour,

Je me suis mal exprimé, le code est parfait pour mon besoin qui est d'écrire en continu sur la SD des mesures à une fréquence élevée. Je rencontre des difficultés à l'adapter pour justement faire les mesures.

Je cherche effectivement à résoudre ce problème mais l'hypothèse de la surcharge de la RAM, qui aurait pu expliquer l'absence d'exécution du code dans le void loop, ne semble pas être la bonne.

Si vous avez une autre idée pour réaliser un autre moyen d'insérer à fréquences élevées des données sur une carte SD je suis preneur.

Bonjour

J'ai pioché ce code dans les exemples de la bibliothèque SD.h, il fonctionne même en l'absence de ligne fermant le fichier.

C'est à l'ajout de la nouvelle bibliothèque que cela se complique

Donc ca revient à chercher quel est le paramètre qui est modifié dans cette librairie que la librairie SD.h utilise également.