Skip to content

uPesy now ships to the entire European Union

Livraison à partir de seulement 2.50€ !

Contents Menu Expand Light mode Dark mode Auto light/dark mode

Your first steps with your uPesy MicroSD card reader

(Updated at 08/24/2022)

This page will show you how to use the uPesy SD card reader, which is compatible with all boards: Arduino Uno, Arduino Nano, ESP8266, ESP32 and the Raspberry Pi Pico. This module uses the SPI bus to interface the microSD board to your microcontroller via the CS, MISO, MOSI and SCLK pins.

micro SD reader for Arduino, ESP32 and Raspberry Pi Pico

uPesy micro SD reader for Arduino, ESP32, Raspberry Pi Pico

Connecting the module

The uPesy reader contains an integrated logic level converter (from 5V to 3.3V) to be used on boards operating in 5V (Arduino) and 3.3V (ESP and Pi Pico). The card reader can only be powered with 5V on the Arduino and between 3.3V to 5V on the ESP8266, the ESP32 and the Pi Pico. However, we recommend you supply the module with 5V to avoid any stability problems. It is the integrated linear regulator of the player that converts the 5V supply to 3.3V.

Unlike other SD drives, an additional EN pin allows the module to be turned off completely to save power via a logic signal. By default, if the pin is not used, this function is disabled. However, if we impose a high logic state to this pin (5V or 3.3V depending on the microcontroller), the module will be turned off, and so will the micro SD board.

Here are the connections to make according to your board:

µSD Reader

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

Communicate with the micro SD module

Once the connections are set up, we must verify that we can communicate appropriately with the microSD board with a simple test sketch. There are plenty of examples in the Arduino IDE software to test this reader. However, it is not always the same CS pin used, so I recommend you first use the codes below to verify that you can talk to the micro SD board. Then, if you have an error, you will know that it is not the reader but the code.

If you encounter any errors during the test code, I invite you to consult this step-by-step guide to solve your problem with (micro) SD card readers.

Test of the microSD reader for the 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 of the microSD reader for ESP32 boards

/*
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 of the microSD reader for the Raspberry Pi Pico board

/*
    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();
}
}

Using the power-saving mode

The low power mode is handy to extend the battery’s autonomy. It is even more convenient with ESP8266/ESP32 boards which already have a saving mode (Deep Sleep): you can combine the 2 to have an exceedingly power-efficient datalogger.

I invite you to read the technical documentation of the uPesy microSD reader for more information on its consumption, its included protections and the recommendations for use .