« SE3 2025/2026 EC4 » : différence entre les versions

De wiki-se.plil.fr
Aller à la navigation Aller à la recherche
Ligne 126 : Ligne 126 :
Il reste donc à adapter le programme pour respecter exactement le cahier des charges final, c’est-à-dire effectuer une copie brute bloc par bloc de la première carte vers la seconde, ajouter l’indication par la LED Arduino après chaque bloc copié avec succès. Peut être prévoir un code d’erreur par LED en cas de problème si j'ai encore du temps.
Il reste donc à adapter le programme pour respecter exactement le cahier des charges final, c’est-à-dire effectuer une copie brute bloc par bloc de la première carte vers la seconde, ajouter l’indication par la LED Arduino après chaque bloc copié avec succès. Peut être prévoir un code d’erreur par LED en cas de problème si j'ai encore du temps.


 
===== Problèmes rencontrés : =====
 
Pendant l'écriture du programme, j’ai rencontré quelques problèmes techniques liés principalement aux contraintes matérielles et à la gestion des fichiers.
Pendant l'écriture du programme, j’ai rencontré quelques problèmes techniques liés principalement aux contraintes matérielles et à la gestion des fichiers.


Le premier problème important concernait la gestion de la mémoire de l’Arduino. Au départ, j’avais défini un buffer de copie assez grand pour améliorer la vitesse de transfert. Cependant, lors de la compilation, j’obtenais une erreur indiquant que la mémoire disponible était dépassée (“data section exceeds available space in board”).
Le premier problème important concernait la gestion de la mémoire de l’Arduino. Au départ, j’avais défini un buffer de copie assez grand pour améliorer la vitesse de transfert. Cependant, lors de la compilation, j’obtenais une erreur indiquant que la mémoire disponible était dépassée (“data section exceeds available space in board”).

Version du 28 avril 2026 à 10:25

Objectifs

Réaliser, en C, un copieur de carte micro-SD avec un Arduino Nano :

  • commencez par concevoir une carte électronique pour connecter deux connecteurs de carte micro-SD à l'Arduino ;
  • les deux connecteurs de cartes micro-SD doivent être connectées sur le bus SPI avec deux CS différents ;
  • réalisez la carte, i.e. soudez les connecteurs pour l'Arduino Nano et les connecteurs micro-SD ;
  • écrivez un programme pour effectuer la copie complète de la première micro-SD sur la seconde :
    • lisez un bloc de la première carte en mémoire ;
    • écrivez le bloc sur la second carte ;
    • indiquez avec la LED de l'Arduino qu'un bloc a été copié avec succès ;
    • passez au bloc suivant ;
    • en cas d'erreur indiquez sa nature avec la LED de l'Arduino.

Matériel nécessaire

  • Arduino Nano avec adaptateur USB/série et câble USB ;
  • connecteurs femelles pour PCB ;
  • 2 connecteurs pour carte micro-SD ;
  • 2 carte micro-SD pour les tests.

Un programme C pour la gestion d'une carte micro-SD avec un ATmega328p est donné : Fichier:2025-EC4-SD.zip.

Travail réalisé

Etapes clés du projet :

HARDWARE : -Identification des composants nécessaires -Schéma élec Kicad (trouver les bonnes empreintes + branchements) -Routage Kicad -Impression de la carte -Soudure des composants

SOFTWARE : -Faire fonctionner UNE seule carte (initialisation / lire un seul bloc / afficher via UART pour debug) -Gestion des deux cartes simultanément (lecture simultanée) -Copier un bloc (lire sur carte A / écrire sur carte B) -Vérifier la copie -avertir utilisateur via LED -Copier plusieurs bloc.

.

Informations en vrac :

Arduino Nano : 5V Carte SD : 3.3V donc probablement besoin d'un diviseur de tension.

Informations trouvées sur la lecture de carte SD

https://passionelectronique.fr/carte-sd-arduino/#branchement-et-cablage-dune-micro-sd-card-a-un-arduino-uno-nano-ou-mega-port-spi

CS inactif = HIGH

un seul CS LOW à la fois

côté câblage : prévoir pull-up léger sur CS (ex 47k ou 10k) pour éviter une sélection aléatoire au reset.

Photo1.png

.

HARDWARE :

06/03/26:

- Ebauche du schéma électrique

  • ajout des symboles des principaux composants (Arduino Nano, Lecteurs micro SD)
  • étiquettes des liaisons principales.

- Création d'un Git sur Gitea pour futur dépot de l'avancement du projet

V1 schéma électrique
15/03 -> 18/03

- Schema électrique

  • Ajout des résistances et des capacités nécessaires.
  • Adaptation des alimentations en 3V3 des composants.
  • Vérification et correction de la première version

- démarrage du routage PCB et ajout des empreintes sur les composants.

version 2 Schéma Electrique

.

- Schéma électrique Final :

(insérer capture d'écran)

.

- PCB Final :
  • Minimisation des dimensions de la carte. Carte la plus compacte possible.
  • Masse GND en double face
  • Double face, passage de certaines pistes en dessous en utilisant des via.
  • Passage du 3V3 en couche inférieure (recommandé par M. Redon).
  • Piste 3V3 plus épaisse que les pistes classique (4mm)
  • Ajout de plusieurs Via sur le plan de masse afin de bien connecter les deux couches.

Difficultés rencontrées :

  • Connecter les deux lecteurs micro SD ensemble était compliqué, car les pin étaient inversée les unes par rapport aux autres (en miroir). Donc toutes les pistes se croisaient.
  • Réussir à connecter le GND partout était difficile, en raison de zones isolées qui se créaient (solutionné par le passage en couche inférieur du 3V3).
Capture d’écran ec4.png

Carte envoyée en impression en même temps que les projets PSE (13/04).

.

SOFTWARE :

(13/04 -> 18/04)

Actuellement, mon programme ne réalise pas encore la copie complète bloc par bloc de toute la micro-SD comme demandé dans l’objectif final.

Pour l’instant, j’ai développé une première version qui fonctionne au niveau du système de fichiers : le programme initialise deux cartes micro-SD sur le même bus SPI avec deux broches CS différentes, puis parcourt la carte source afin de copier les dossiers et les fichiers vers la carte destination.

La copie se fait fichier par fichier, en lisant une petite quantité de données en mémoire grâce à un buffer, puis en l’écrivant sur la deuxième carte. Cette version m’a surtout permis de mettre en place la logique générale du projet. C'est à dire :

- initialisation des deux cartes

- distinction entre la source et la destination

- parcours récursif des dossiers, reconstruction des chemins de fichiers

- gestion des erreurs d’ouverture, de lecture et d’écriture

- affichage d’informations avec Serial.print() pour préparer le débogage.

Il reste donc à adapter le programme pour respecter exactement le cahier des charges final, c’est-à-dire effectuer une copie brute bloc par bloc de la première carte vers la seconde, ajouter l’indication par la LED Arduino après chaque bloc copié avec succès. Peut être prévoir un code d’erreur par LED en cas de problème si j'ai encore du temps.

Problèmes rencontrés :

Pendant l'écriture du programme, j’ai rencontré quelques problèmes techniques liés principalement aux contraintes matérielles et à la gestion des fichiers.

Le premier problème important concernait la gestion de la mémoire de l’Arduino. Au départ, j’avais défini un buffer de copie assez grand pour améliorer la vitesse de transfert. Cependant, lors de la compilation, j’obtenais une erreur indiquant que la mémoire disponible était dépassée (“data section exceeds available space in board”).

Grâce à mes recherches, j’ai compris que la combinaison de la bibliothèque SdFat, des variables globales et du buffer dépassait la RAM disponibles sur l’arduino. Du coup, j’ai progressivement réduit la taille du buffer (jusqu’à 32 octets), ce qui a permis de faire rentrer le programme en mémoire, au prix d’une vitesse de copie plus faible.

J’ai eu un problème de gestion des chemins de fichiers lors de la copie. En effet, pour parcourir récursivement les dossiers, il était nécessaire de reconstruire correctement les chemins complets. La fonction joinPath a permit d'eviter les erreurs liées à la taille des buffers. J’ai intégré des vérifications supplémentaires pour gérer les cas d’erreur potentiels (échec d’ouverture de fichier, chemin trop long, erreur de lecture/écriture), afin d'être plus sur du programme même avant le test sur matériel.


Comme je ne peux pas encore tester physiquement les cartes, j’ai ajouté des messages Serial.print() pour que, lors du premier test matériel, je puisse identifier rapidement où le programme bloque.


Enfin, j’ai rencontré des obstacles liées à la limitation matérielle de l’Arduino, notamment en termes de mémoire et de gestion simultanée de deux cartes SD sur le même bus SPI. Cela m’a obligé à optimiser le code et à bien comprendre l'utilisation de deux broches CS distinctes.


Vous trouverez la version actuelle de mon programme dans les Documents Rendus et sur le Git.

Documents Rendus

Git : https://gitea.plil.fr/lkachour/EC4.git

#include <SPI.h>
#include <SdFat.h>


const uint8_t SRC_CS = 10;   // CS carte source
const uint8_t DST_CS = 9;    // CS carte destination

const size_t COPY_BUFFER_SIZE = 32;
uint8_t copyBuffer[COPY_BUFFER_SIZE];


SdFs sdSrc;
SdFs sdDst;


bool joinPath(const char* parent, const char* name, char* out, size_t outSize) {
  int written;

  if (strcmp(parent, "/") == 0) {
    written = snprintf(out, outSize, "/%s", name);
  } else {
    written = snprintf(out, outSize, "%s/%s", parent, name);
  }

  return (written > 0 && (size_t)written < outSize);
}

bool copyFile(const char* path) {
  FsFile srcFile = sdSrc.open(path, O_RDONLY);
  if (!srcFile) {
    Serial.print("Erreur ouverture source : ");
    Serial.println(path);
    return false;
  }

  FsFile dstFile = sdDst.open(path, O_WRONLY | O_CREAT | O_TRUNC);
  if (!dstFile) {
    Serial.print("Erreur ouverture destination : ");
    Serial.println(path);
    srcFile.close();
    return false;
  }

  Serial.print("Copie fichier : ");
  Serial.println(path);

  while (true) {
    int32_t n = srcFile.read(copyBuffer, sizeof(copyBuffer));

    if (n < 0) {
      Serial.print("Erreur lecture : ");
      Serial.println(path);
      srcFile.close();
      dstFile.close();
      return false;
    }

    if (n == 0) {
      break; // fin du fichier
    }

    if (dstFile.write(copyBuffer, n) != n) {
      Serial.print("Erreur ecriture : ");
      Serial.println(path);
      srcFile.close();
      dstFile.close();
      return false;
    }
  }

  srcFile.close();
  dstFile.close();
  return true;
}

bool copyDirectory(const char* path) {
  FsFile dir = sdSrc.open(path, O_RDONLY);
  if (!dir || !dir.isDir()) {
    Serial.print("Erreur ouverture dossier source : ");
    Serial.println(path);
    dir.close();
    return false;
  }

  if (strcmp(path, "/") != 0) {
    if (!sdDst.exists(path)) {
      if (!sdDst.mkdir(path, true)) {
        Serial.print("Erreur creation dossier destination : ");
        Serial.println(path);
        dir.close();
        return false;
      }
    }
  }

  FsFile entry;

  while (entry.openNext(&dir, O_RDONLY)) {
    char name[64];
    char childPath[128];

    if (!entry.getName(name, sizeof(name))) {
      Serial.println("Nom de fichier trop long ou erreur getName");
      entry.close();
      dir.close();
      return false;
    }

    if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
      entry.close();
      continue;
    }

    if (!joinPath(path, name, childPath, sizeof(childPath))) {
      Serial.print("Chemin trop long, ignore : ");
      Serial.println(name);
      entry.close();
      continue;
    }

    bool isDir = entry.isDir();
    entry.close();

    if (isDir) {
      Serial.print("Entre dans dossier : ");
      Serial.println(childPath);

      if (!copyDirectory(childPath)) {
        dir.close();
        return false;
      }
    } else {
      if (!copyFile(childPath)) {
        dir.close();
        return false;
      }
    }
  }

  dir.close();
  return true;
}

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    ;
  }

  Serial.println();
  Serial.println("=== Debut copie SD -> SD ===");

  //Met les 2 à l'état haut par défaut
  pinMode(SRC_CS, OUTPUT);
  pinMode(DST_CS, OUTPUT);
  digitalWrite(SRC_CS, HIGH);
  digitalWrite(DST_CS, HIGH);

  // Initialisation de la carte source
  if (!sdSrc.begin(SdSpiConfig(SRC_CS, SHARED_SPI, SD_SCK_MHZ(8)))) {
    Serial.println("Echec init carte SOURCE");
    return;
  }
  Serial.println("Carte SOURCE OK");

  // Initialisation de la carte destination
  if (!sdDst.begin(SdSpiConfig(DST_CS, SHARED_SPI, SD_SCK_MHZ(8)))) {
    Serial.println("Echec init carte DESTINATION");
    return;
  }
  Serial.println("Carte DESTINATION OK");

  Serial.println("Lancement de la copie...");

  if (copyDirectory("/")) {
    Serial.println("=== Copie terminee avec succes ===");
  } else {
    Serial.println("=== Copie arretee sur erreur ===");
  }
}

void loop() {
  
}

Bibliographie

https://www.circuitstate.com/tutorials/interfacing-catalex-micro-sd-card-module-with-arduino/

https://www.electronicwings.com/arduino/microsd-card-interfacing-with-arduino

https://randomnerdtutorials.com/guide-to-sd-card-module-with-arduino/