Vos premiers pas avec votre lecteur de carte microSD uPesy

Cette page va vous guider dans la prise en main du lecteur de carte SD d’uPesy. Il est compatible avec toutes les cartes : Arduino Uno, Arduino Nano, ESP8266, ESP32 et la Raspberry Pi Pico. Ce module utilise le bus SPI pour interfacer la carte microSD à votre microcontrôleur via les broches CS, MISO, MOSI et SCLK.

lecteur micro SD pour Arduino, ESP32 et Raspberry Pi Pico

Lecteur micro SD uPesy pour Arduino, ESP32, Raspberry Pi Pico …

Branchement du module

Le lecteur uPesy contient un convertisseur de niveau logique (de 5V à 3.3V) intégré pour être utilisé sur des cartes fonctionnant en 5V (Arduino) et en 3.3V (ESP et Pi Pico). On peut alimenter le lecteur uniquement en 5V sur l’Arduino et entre 3.3V et 5V sur l’ESP8266, l’ESP32 et la Pi Pico. Toutefois, il est recommandé d’alimenter le module en 5V pour éviter d’éventuels problèmes de stabilitée. C’est le régulateur linéaire intégré du lecteur qui se charge de convertir l’alimentation de 5V en 3.3V.

Contrairement aux autres lecteurs SD, il y a une broche supplémentaire EN qui permet d’éteindre entièrement le module pour économiser de l’énergie via un signal logique. Par défaut, si on n’utilise pas la broche, cette fonction est désactivée. Par contre, si on impose un état logique haut à cette broche (5V ou 3.3V en fonction du microcontrôleur), le module sera éteint et donc la carte micro SD aussi.

Voici les branchements à effectuer en fonction de votre carte :

Cablâge entre le module SD et les différentes cartes

Lecteur SD

Arduino Uno | Nano

ESP32

Pi Pico

CS | SS

D10

GPIO 5

GPIO 17

SCK | SCLK

D13

GPIO 18

GPIO 18

MOSI

D11

GPIO 23

GPIO 19

MISO

D12

GPIO 19

GPIO 16

5V

+5V

+5V ou +3.3V

+5V

GND

GND

GND

GND

Communiquer avec la carte micro SD

Une fois que les branchements sont faits, nous allons vérifier que l’on peut communiquer avec la carte microSD avec un simple croquis de test. Notez qu’il y a une multitude d’exemples inclus dans le logiciel Arduino IDE pour tester ce lecteur. Cependant, ce n’est pas forcément toujours la même broche CS qui est utilisée, c’est pourquoi je vous recommande dans un premier temps d’utiliser les codes ci-dessous pour vérifier que vous pouvez dialoguer avec la carte micro SD. Par la suite, si vous avez une erreur, vous saurez que cela ne vient pas du lecteur mais plutôt du code.

Si vous rencontrer des erreurs lors de code de test, je vous invite à consulter ce guide pas à pas pour résoudre votre problème avec les lecteur de cartes (micro) SD.

Test du lecteur microSD pour les Arduino Uno & Nano

/*
uPesy SD card test

    (Micro) SD card attached to SPI bus as follows:
** MOSI - pin 11 on Arduino Uno
** MISO - pin 12 on Arduino Uno
** CLK - pin 13 on Arduino Uno
** CS - pin 10 (can be changed)
** 5V - +5V of Arduino
*/

#include <SPI.h>
#include <SD.h>

Sd2Card card;
SdVolume volume;
SdFile root;

const int CS = 10;

void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
}

Serial.print("\nInitializing SD card...");

// we'll use the initialization code from the utility libraries
// since we're just testing if the card is working!
if (!card.init(SPI_HALF_SPEED, CS)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card inserted?");
    Serial.println("* is your wiring correct?");
    Serial.println("* did you change the CS pin to match your shield or module?");
    while (1);
} else {
    Serial.println("Wiring is correct and a card is present.");
}

// print the type of card
Serial.println();
Serial.print("Card type:         ");
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("Unknown");
}

// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
if (!volume.init(card)) {
    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
    while (1);
}

Serial.print("Clusters:          ");
Serial.println(volume.clusterCount());
Serial.print("Blocks x Cluster:  ");
Serial.println(volume.blocksPerCluster());

Serial.print("Total Blocks:      ");
Serial.println(volume.blocksPerCluster() * volume.clusterCount());
Serial.println();

// print the type and size of the first FAT-type volume
uint32_t volumesize;
Serial.print("Volume type is:    FAT");
Serial.println(volume.fatType(), DEC);

volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
volumesize *= volume.clusterCount();       // we'll have a lot of clusters
volumesize /= 2;                           // SD card blocks are always 512 bytes (2 blocks are 1KB)
Serial.print("Volume size (Kb):  ");
Serial.println(volumesize);
Serial.print("Volume size (Mb):  ");
volumesize /= 1024;
Serial.println(volumesize);
Serial.print("Volume size (Gb):  ");
Serial.println((float)volumesize / 1024.0);

Serial.println("\nFiles found on the card (name, date and size in bytes): ");
root.openRoot(volume);

// list all files in the card with date and size
root.ls(LS_R | LS_DATE | LS_SIZE);
}

void loop(void) {
}

Test du lecteur microSD pour les cartes ESP32

/*
uPesy SD card test

(Micro) SD card attached to SPI bus as follows:
** MOSI - pin 18 on ESP32
** MISO - pin 19 on ESP32
** CLK - pin 23 on ESP32
** CS - pin 5
** 5V - +5V of ESP32
*/

#include "FS.h"
#include "SD.h"
#include "SPI.h"

void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
    Serial.printf("Listing directory: %s\n", dirname);

    File root = fs.open(dirname);
    if(!root){
        Serial.println("Failed to open directory");
        return;
    }
    if(!root.isDirectory()){
        Serial.println("Not a directory");
        return;
    }

    File file = root.openNextFile();
    while(file){
        if(file.isDirectory()){
            Serial.print("  DIR : ");
            Serial.println(file.name());
            if(levels){
                listDir(fs, file.name(), levels -1);
            }
        } else {
            Serial.print("  FILE: ");
            Serial.print(file.name());
            Serial.print("  SIZE: ");
            Serial.println(file.size());
        }
        file = root.openNextFile();
    }
}

void createDir(fs::FS &fs, const char * path){
    Serial.printf("Creating Dir: %s\n", path);
    if(fs.mkdir(path)){
        Serial.println("Dir created");
    } else {
        Serial.println("mkdir failed");
    }
}

void removeDir(fs::FS &fs, const char * path){
    Serial.printf("Removing Dir: %s\n", path);
    if(fs.rmdir(path)){
        Serial.println("Dir removed");
    } else {
        Serial.println("rmdir failed");
    }
}

void readFile(fs::FS &fs, const char * path){
    Serial.printf("Reading file: %s\n", path);

    File file = fs.open(path);
    if(!file){
        Serial.println("Failed to open file for reading");
        return;
    }

    Serial.print("Read from file: ");
    while(file.available()){
        Serial.write(file.read());
    }
    file.close();
}

void writeFile(fs::FS &fs, const char * path, const char * message){
    Serial.printf("Writing file: %s\n", path);

    File file = fs.open(path, FILE_WRITE);
    if(!file){
        Serial.println("Failed to open file for writing");
        return;
    }
    if(file.print(message)){
        Serial.println("File written");
    } else {
        Serial.println("Write failed");
    }
    file.close();
}

void appendFile(fs::FS &fs, const char * path, const char * message){
    Serial.printf("Appending to file: %s\n", path);

    File file = fs.open(path, FILE_APPEND);
    if(!file){
        Serial.println("Failed to open file for appending");
        return;
    }
    if(file.print(message)){
        Serial.println("Message appended");
    } else {
        Serial.println("Append failed");
    }
    file.close();
}

void renameFile(fs::FS &fs, const char * path1, const char * path2){
    Serial.printf("Renaming file %s to %s\n", path1, path2);
    if (fs.rename(path1, path2)) {
        Serial.println("File renamed");
    } else {
        Serial.println("Rename failed");
    }
}

void deleteFile(fs::FS &fs, const char * path){
    Serial.printf("Deleting file: %s\n", path);
    if(fs.remove(path)){
        Serial.println("File deleted");
    } else {
        Serial.println("Delete failed");
    }
}

void testFileIO(fs::FS &fs, const char * path){
    File file = fs.open(path);
    static uint8_t buf[512];
    size_t len = 0;
    uint32_t start = millis();
    uint32_t end = start;
    if(file){
        len = file.size();
        size_t flen = len;
        start = millis();
        while(len){
            size_t toRead = len;
            if(toRead > 512){
                toRead = 512;
            }
            file.read(buf, toRead);
            len -= toRead;
        }
        end = millis() - start;
        Serial.printf("%u bytes read for %u ms\n", flen, end);
        file.close();
    } else {
        Serial.println("Failed to open file for reading");
    }


    file = fs.open(path, FILE_WRITE);
    if(!file){
        Serial.println("Failed to open file for writing");
        return;
    }

    size_t i;
    start = millis();
    for(i=0; i<2048; i++){
        file.write(buf, 512);
    }
    end = millis() - start;
    Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
    file.close();
}

void setup(){
    Serial.begin(115200);
    if(!SD.begin()){
        Serial.println("Card Mount Failed");
        return;
    }
    uint8_t cardType = SD.cardType();

    if(cardType == CARD_NONE){
        Serial.println("No SD card attached");
        return;
    }

    Serial.print("SD Card Type: ");
    if(cardType == CARD_MMC){
        Serial.println("MMC");
    } else if(cardType == CARD_SD){
        Serial.println("SDSC");
    } else if(cardType == CARD_SDHC){
        Serial.println("SDHC");
    } else {
        Serial.println("UNKNOWN");
    }

    uint64_t cardSize = SD.cardSize() / (1024 * 1024);
    Serial.printf("SD Card Size: %lluMB\n", cardSize);

    listDir(SD, "/", 0);
    createDir(SD, "/mydir");
    listDir(SD, "/", 0);
    removeDir(SD, "/mydir");
    listDir(SD, "/", 2);
    writeFile(SD, "/hello.txt", "Hello ");
    appendFile(SD, "/hello.txt", "World!\n");
    readFile(SD, "/hello.txt");
    deleteFile(SD, "/foo.txt");
    renameFile(SD, "/hello.txt", "/foo.txt");
    readFile(SD, "/foo.txt");
    testFileIO(SD, "/test.txt");
    Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
    Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
}

void loop(){

}

Test du lecteur microSD pour la carte Raspberry Pi Pico

/*
    uPesy SD card test

    (Micro) SD card attached to SPI bus as follows:
    ** MOSI - pin 19 on Pi Pico
    ** MISO - pin 16 on Pi Pico
    ** CLK - pin 18 on Pi Pico
    ** CS - pin 17 on Pi Pico
    ** 5V - +5V of Pi Pico
*/

#include <SPI.h>
#include <SD.h>

File root;

void setup() {
    delay(5000);
    // Open serial communications and wait for port to open:
    Serial.begin(115200);

    Serial.print("Initializing SD card...");

    if (!SD.begin(SS)) {
        Serial.println("initialization failed!");
        return;
    }
    Serial.println("initialization done.");

    root = SD.open("/");

    printDirectory(root, 0);

    Serial.println("done!");
}

void loop() {
// nothing happens after setup finishes.
}

void printDirectory(File dir, int numTabs) {
while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
    // no more files
    break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
    Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
    Serial.println("/");
    printDirectory(entry, numTabs + 1);
    } else {
    // files have sizes, directories do not
    Serial.print("\t\t");
    Serial.print(entry.size(), DEC);
    time_t cr = entry.getCreationTime();
    time_t lw = entry.getLastWrite();
    struct tm * tmstruct = localtime(&cr);
    Serial.printf("\tCREATION: %d-%02d-%02d %02d:%02d:%02d", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec);
    tmstruct = localtime(&lw);
    Serial.printf("\tLAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec);
    }
    entry.close();
}
}

Utilisation du mode économie d’énergie

Le mode basse consommation est très utile pour économiser une batterie. Il est d’autant plus intéressant avec les cartes ESP8266/ESP32 qui possèdent déjà un mode d’économie (Deep Sleep) : on peut combiner les 2 pour avoir un datalogger très économe.

Je vous invite à consulter la documentation technique du lecteur microSD uPesy pour avoir plus d’informations sur sa consommation, ses protections incluses et les recommandations d’usage .