Bibliothèque légère pour lire une carte SD grâce à une carte arduino

Dans cet article, je vais vous expliquer comment lire une carte mémoire SD grâce à un Arduino sans utiliser la librairie SD.h la plus commune, mais aussi très (trop) lourde.

A quoi ça sert ?

A créer des projets sous Arduino qui nécessitent la lecture ou l'écriture sur une carte mémoire SD (par exemple, un data logger ou bien un écran LCD qui doit afficher des données enregistrées sur une carte).

Matériel nécessaire

Un arduino

Une carte Arduino Uno ou une compatible Arduino.

Par exemple, cette carte Uno compatible sur le net à 9€

Un lecteur de carte SD

N'importe quelle marque fera normalement l'affaire. Généralement, elles sont alimentée en 5V (parfois en 3V).

Par exemple, j'ai trouvé un lot de deux modules SD pour moins de 8€

Les liens vers les produits ci-dessus sont des liens affiliés et me permettent de toucher une commission si vous achetez par le biais de ces liens, une façon de me remercier pour cet article si vous le trouvez utile.

Vous pouvez trouver du matériel électronique sur différents sites. J'ai l'habitude de commander sur Amazon lorsque je suis assez pressé de recevoir le matériel. Sinon, pour du matériel de qualité vous avez le site français GoTronic.fr. Et pour du moins cher (avec de bonnes et de mauvaises surprises parfois...), vous pouvez acheter directement en chine sur AliExpress mais il faut bien analyser chaque produit et c'est un peu la surprise.

Fonctionnement

Quelque soit la marque du module SD, le fonctionnement est toujours le même protocole de communication SPI (Serial Peripheral Interface).

Le bus SPI utilise quatre signaux logiques :

SCLKSerial Clock, Horloge
MOSIMaster Output, Slave Input
MISOMaster Input, Slave Output
SSSlave Select, souvent noté CS

A ces cablages, vont se rajouter les traditionnels :

VCC — Volts Conventional Current- Alimentation
GNDGround, Masse.

Selon les fabricants, les notations peuvent différer légèrement. Egalement, attention à l'alimentation du module qui bien que la plupart du temps soit à 5V, peut être de 3.3V. Il est donc nécessaire bien vérifier avant le branchement).

1) Comment cabler le module SD à l'Arduino ?

Voici un exemple de cablage réalisé avec Fritzing :

arduino-sd

Tableau d'équivalence des pins du module SD et de l'Arduino UNO

(Les pins peuvent varier selon le modèle de votre arduino)

Module carte SDArduino Uno
CS10 (possibilité de mettre sur un autre pin)
MOSI11
MISO12
CLK13
VCC3.3V ou 5V (vérifiez la tension acceptée par le module SD)
GNDGND

2) Formater la carte SD en FAT16 ou FAT32

Avant de pouvoir utiliser une carte SD, il faut la formater dans un format que l'on va pouvoir lire avec l'Arduino, à savoir FAT16 ou FAT32.

A cette fin, il vous faudra un lecteur de carte SD pour votre ordinateur et procéder à quelques manipulation qui différent selon votre système d'exploitation.

Je vous laisse regarder sur votre moteur de recherche favori si vous ne savez pas comment procéder.

3) Utilisation de la bibliothèque PetitFS / Petit FAT

On trouve facilement des tutoriels pour l'utilisation de la classique bibliothèque SD.h, mais en l'utilisant, elle remplissait pas loin de 50% de l'espace du programme, qui sur Arduino, vous le savez, est déjà limitée.

Après pas mal de recherche, j'ai trouvé la bibliothèque PetitFS à télécharger sur le GitHub de Bill Greiman https://github.com/greiman/PetitFS. Elle est basée sur la bibliothèque Petit FAT.  Avec elle, l'empreinte sur la mémoire n'est plus que de 13% (dans mon cas, en utilisant uniquement la lecture sur la carte).

Téléchargement de la bibliothèque

Rendez-vous donc sur https://github.com/greiman/PetitFS où vous allez pouvoir télécharger le dépôt et y copier le dossier src/. Ensuite, deux solutions, inclure les fichiers dans votre projet, ou dans le dossier global des librairies Arduino, comme j'ai pu le faire :

arborescence-bibliothque

Montage de la carte SD et ouverture d'un fichier

Montage du volume

Avant d'effectuer une opération sur la carte SD, il est nécessaire d'appeler pf_mount() qui va "monter" le volume et le préparer pour utilisation.

if (pf_mount(&fs)) {Serial.println("Erreur de montage du volume");}

Juste à noter que la bibliothèque fonctionne avec un comportement que je ne trouve pas commun. La fonction pf_mount() renvoie une valeur s'il y a une erreur et non pas lorsque tout va bien. La logique me semble inversée par rapport à d'autres blibliothèques.

Ouverture d'un fichier

if (pf_open("DOSSIER/FICHIER.CSV")){Serial.println("Erreur de lecture du fichier");}

De la même façon, pour l'ouverture, on a une erreur lorsque la fonction renvoie une donnée (code d'erreur).

ATTENTION : Le système FAT étant assez basique, on en oublie parfois l'essentiel. Les noms des fichiers sont interprétés en majuscule. J'ai passé pas mal de temps à comprendre qu'il fallait indiquer le nom du fichier en majuscule, même si sur la carte le fichier est écrit en minuscule. Il me semble qu'il y a une option dans la bibliothèque PETIT FS pour changer ce comportement, mais je n'ai pas essayé.

Exemple de code

La bibliothèque est livrée avec un exemple qui permet de lire un fichier et de l'afficher dans l'interface du moniteur série grâce à Serial.write().

J'avais pour ma part besoin de parser les données d'un fichier CSV qui comporte en première colonne une date/heure et en deuxième une valeur.

Il fallut par conséquent mettre en place un "buffer" qui stocke les données temporairement jusqu'à trouver une virgule ou une fin de ligne.

Ci-dessous, voici mon code créé en prenant la base sur l'exemple fourni :

// Petit FS test.   
// For minimum flash use edit pffconfig.h and only enable
// _USE_READ and either _FS_FAT16 or _FS_FAT32

#include "PetitFS.h"


boolean stopped = false;

// The SD chip select pin is currently defined as 10
// in pffArduino.h.  Edit pffArduino.h to change the CS pin.

FATFS fs;     /* File system object */
//------------------------------------------------------------------------------
void errorHalt(const char* msg) {
  Serial.print("Error: ");
  Serial.println(msg);
  while(1);
}



//------------------------------------------------------------------------------
void test() {
  uint8_t buf[32];
  char buffer[25];
  unsigned int pos =0;
    
  // Initialize SD and file system.
  if (pf_mount(&fs)) errorHalt("Erreur_montage");
  
  // Open test file.
  if (pf_open("DOSSIER/01.CSV")) errorHalt("Erreur_ouverture");
  
  // J'ai rajouté une variable booléenne stopped si je décide selon certaines conditions d'interrompre la boocle.
  while (1 && !stopped) {
    UINT nr;
    //On lit le buffer byte par byte (en mettant 1 en deuxième paramètre)
    if (pf_read(buf, 1, &nr)) errorHalt("Erreur_lecture");
    if (nr == 0) break;

    //Pour des raison de lecture, j'ai préféré stocker dans la variable carac
    char carac = (char)buf[0];

    //Si on est sur une virgule ou à la fin d'une ligne, on considère qu'on est à la vin de la chaîne à retrouver
    if(carac==',' || carac=='\n' ){
      //On doit donc rajouter le caractère de fin " \0 " pour marquer la fin de chaîne
      buffer[pos] = '\0';
      //Et on reinitialise la position à 0 pour qu'au prochain tour, on recommence à zéro
      pos = 0;

      //Si c'est une virgule, alors la chaine avant était la date
      if(carac == ','){
         Serial.println("- DATE -");
         Serial.println(buffer);
      }
      //Si c'est une fin de ligne, alors, la chaîne avant était la valeur
      else{
        Serial.println("- VALEUR -");
         Serial.println(buffer);
      }
      
     
      
    }
    else{
      //Si on ne rentre pas dans les condition ci-dessus, on continue à remplir notre buffer à chaque position
      buffer[pos] = (char)buf[0];
      pos++;
    }
     
  
 
  
 
  }
 
}
//------------------------------------------------------------------------------
void setup() {
  Serial.begin(115200);
  test();
  Serial.println("\nEND OF PROGRAM!");
}
void loop() {}
Lecture carte SD
 

Voici donc un petit programme de base qui permet de parser un CSV à deux colonnes pour quelques octets (et qui laisse donc de la place sur l'Arduino pour un "vrai" programme ou l'utilisation d'autres bibliothèques).

Un piste d'amélioration serait de pouvoir pour parser des CSV avec plus de colonnes en adaptant l'interprétation du buffer en fonction du nombre de virgules rencontrée, peut-être dans un futur article.

N'hésitez pas à poser vos questions ou remarques en commentaires.

Laissez un commentaire





Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.