{"id":102290,"date":"2021-03-12T14:27:35","date_gmt":"2021-03-12T14:27:35","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=102290"},"modified":"2023-07-31T10:14:57","modified_gmt":"2023-07-31T10:14:57","slug":"esp32-microsd-card-arduino","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-microsd-card-arduino\/","title":{"rendered":"ESP32: Guide for MicroSD Card Module using Arduino IDE"},"content":{"rendered":"\n<p>This guide shows how to use a microSD card with the ESP32: you&#8217;ll learn how to read and write files to the microSD card. To interface the microSD card with the ESP32 board, we&#8217;ll use a microSD card module (SPI communication protocol). Using a microSD card with the ESP32 is especially useful for data logging or storing files that don&#8217;t fit in the filesystem (SPIFFS). The ESP32 will be programmed using the Arduino core.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"1200\" height=\"675\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/ESP32-Guide-microSD-Card-Module.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Guide for MicroSD Card Module using Arduino IDE\" class=\"wp-image-102346\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/ESP32-Guide-microSD-Card-Module.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/ESP32-Guide-microSD-Card-Module.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/ESP32-Guide-microSD-Card-Module.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/ESP32-Guide-microSD-Card-Module.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p>In this tutorial, we&#8217;ll cover the following topics:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"#intromicrosdcard\" title=\"#intromicrosdcard\">Introducing the MicroSD Card Module and Pinout<\/a><\/li>\n\n\n\n<li><a href=\"#interfacemicrosdcard\">Interface ESP32 with microSD Card Module<\/a><\/li>\n\n\n\n<li><a href=\"#handlefilesmicrosdcard\">Testing the microSD Card Module: read, write and handle files<\/a><\/li>\n\n\n\n<li><a href=\"#sdcardcustompins\">Use custom SPI pins with the microSD card<\/a><\/li>\n\n\n\n<li><a href=\"#datalogging\">ESP32 Data Logging to microSD Card (sensor readings)<\/a><\/li>\n\n\n\n<li><a href=\"#webserversdcard\">ESP32 Web Server with Files from microSD Card<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"intromicrosdcard\">MicroSD Card Module<\/h2>\n\n\n\n<p>There are different microSD card modules compatible with the ESP32. We&#8217;re using the microSD card module sown in the following figure &#8211; it communicates using SPI communication protocol. You can use any other microSD card module with an SPI interface.<\/p>\n\n\n<div class=\"wp-block-image is-style-default\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"421\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSD-card-module-ESP32-Arduino-ESP8266.jpg?resize=750%2C421&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"MicroSD card module for ESP32 ESP8266 Arduino SPI\" class=\"wp-image-102279\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSD-card-module-ESP32-Arduino-ESP8266.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSD-card-module-ESP32-Arduino-ESP8266.jpg?resize=300%2C168&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>This microSD card module is also compatible with other microcontrollers like the Arduino and the ESP8266 NodeMCU boards. To learn how to use the microSD card module with the Arduino, you can follow the next tutorial:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/guide-to-sd-card-module-with-arduino\/\">Guide to SD Card Module with Arduino<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Where to Buy?<\/h3>\n\n\n\n<p>You can click the link below to check different stores where you can get the microSD card module:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/sd-card-module\/\" target=\"_blank\" rel=\"noreferrer noopener\">MicroSD card module<\/a><\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/makeradvisor.com\/tools\/sd-card-module\/\" target=\"_blank\" rel=\"noopener\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"317\" height=\"288\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSD-card-module-ESP32-ESP8266-Arduino.png?resize=317%2C288&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"MicroSD card module for ESP32 ESP8266 Arduino SPI\" class=\"wp-image-102297\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSD-card-module-ESP32-ESP8266-Arduino.png?w=317&amp;quality=100&amp;strip=all&amp;ssl=1 317w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSD-card-module-ESP32-ESP8266-Arduino.png?resize=300%2C273&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 317px) 100vw, 317px\" \/><\/a><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"interfacemicrosdcard\">MicroSD Card Module Pinout &#8211; SPI<\/h3>\n\n\n\n<p>The microSD card module communicates using SPI communication protocol. You can connect it to the ESP32 using the default SPI pins.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>MicroSD card module<\/strong><\/td><td><strong>ESP32<\/strong><\/td><\/tr><tr><td>3V3<\/td><td><span class=\"rnthl rntcred\">3.3V<\/span><\/td><\/tr><tr><td>CS<\/td><td><span class=\"rnthl rntclblue\">GPIO 5<\/span><\/td><\/tr><tr><td>MOSI<\/td><td><span class=\"rnthl rntclblue\">GPIO 23<\/span><\/td><\/tr><tr><td>CLK<\/td><td><span class=\"rnthl rntclblue\">GPIO 18<\/span><\/td><\/tr><tr><td>MISO<\/td><td><span class=\"rnthl rntclblue\">GPIO 19<\/span><\/td><\/tr><tr><td>GND<\/td><td><span class=\"rnthl rntcblack\">GND<\/span><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Parts Required<\/h2>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"421\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/ESP32-microSD-card-module-wiring-breadboard.jpg?resize=750%2C421&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 microSD card module wiring breadboard diagram\" class=\"wp-image-102281\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/ESP32-microSD-card-module-wiring-breadboard.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/ESP32-microSD-card-module-wiring-breadboard.jpg?resize=300%2C168&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>For this tutorial, you need the following parts:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32 development board<\/a> (read: <a href=\"https:\/\/makeradvisor.com\/esp32-development-boards-review-comparison\/\" target=\"_blank\" rel=\"noreferrer noopener\">Best ESP32 development boards<\/a>)<\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/sd-card-module\/\" target=\"_blank\" rel=\"noreferrer noopener\">MicroSD Card Module<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/microsd-card-raspberry-pi-16gb-class-10\/\" target=\"_blank\" rel=\"noreferrer noopener\">MicroSD Card<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\" target=\"_blank\" rel=\"noreferrer noopener\">Jumper Wires<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/mb-102-solderless-breadboard-830-points\/\" target=\"_blank\" rel=\"noreferrer noopener\">Breadboard<\/a><\/li>\n<\/ul>\n\n\n<p>You can use the preceding links or go directly to <a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\">MakerAdvisor.com\/tools<\/a> to find all the parts for your projects at the best price!<\/p><p style=\"text-align:center;\"><a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2017\/10\/header-200.png?w=1200&#038;quality=100&#038;strip=all&#038;ssl=1\"><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">ESP32 with microSD Card Module &#8211; Schematic Diagram<\/h2>\n\n\n\n<p>To wire the microSD card module to the ESP32 board, you can follow the next schematic diagram (for the default ESP32 SPI pins):<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"742\" height=\"910\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/ESP32-microSD-Card-Wiring-Diagram.png?resize=742%2C910&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 microSD Card Module Wiring Diagram\" class=\"wp-image-102217\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/ESP32-microSD-Card-Wiring-Diagram.png?w=742&amp;quality=100&amp;strip=all&amp;ssl=1 742w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/ESP32-microSD-Card-Wiring-Diagram.png?resize=245%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 245w\" sizes=\"(max-width: 742px) 100vw, 742px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclblue\">Recommended reading: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-pinout-reference-gpios\/\">ESP32 Pinout Reference: Which GPIO pins should you use?<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Preparing the microSD Card<\/h2>\n\n\n\n<p>Before proceeding with the tutorial, make sure you <strong>format your microSD card as FAT32<\/strong>. Follow the next instructions to format your microSD card or use a software tool like <a href=\"https:\/\/www.sdcard.org\/downloads\/formatter\/\" target=\"_blank\" rel=\"noreferrer noopener\">SD Card Formater<\/a> (compatible with Windows and Mac OS).<\/p>\n\n\n\n<p><strong>1.<\/strong>&nbsp;Insert the microSD card into your computer. Go to&nbsp;<strong>My Computer<\/strong>&nbsp;and right-click on the SD card. Select&nbsp;<strong>Format&nbsp;<\/strong>as shown in the figure below.<\/p>\n\n\n<div class=\"wp-block-image is-style-default\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/rntlab.com\/wp-content\/uploads\/2018\/05\/format-SD-card-1.png?w=1200&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"MicroSD Card Module format sd card\" class=\"wp-image-11805\"\/><\/figure><\/div>\n\n\n<p><strong>2.&nbsp;<\/strong>A new window pops up. Select&nbsp;<strong>FAT32<\/strong>, press&nbsp;<strong>Start<\/strong>&nbsp;to initialize the formatting process and follow the onscreen instructions.<\/p>\n\n\n<div class=\"wp-block-image is-style-default\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/rntlab.com\/wp-content\/uploads\/2018\/05\/format-SD-card-2.png?w=1200&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"MicroSD Card Module format sd card\" class=\"wp-image-11806\"\/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Preparing Arduino IDE<\/h2>\n\n\n\n<p>We\u2019ll program the ESP32 board using Arduino IDE. So, make sure you have the ESP32 add-on installed. Follow the next tutorial:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/installing-the-esp32-board-in-arduino-ide-windows-instructions\/\">Install the ESP32 Board in Arduino IDE<\/a><\/li>\n<\/ul>\n\n\n\n<p>If you prefer using VSCode + PlatformIO, follow the next tutorial instead:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/vs-code-platformio-ide-esp32-esp8266-arduino\/\">Getting Started with VS Code and PlatformIO IDE for ESP32 and ESP8266<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"handlefilesmicrosdcard\">ESP32 Handling Files with a MicroSD Card Module<\/h2>\n\n\n\n<p>There are two different libraries for the ESP32 (included in the Arduino core for the ESP32): the <a href=\"https:\/\/github.com\/espressif\/arduino-esp32\/tree\/master\/libraries\/SD\" target=\"_blank\" rel=\"noreferrer noopener\">SD library<\/a> and the <a href=\"https:\/\/github.com\/espressif\/arduino-esp32\/tree\/master\/libraries\/SD_MMC\" target=\"_blank\" rel=\"noreferrer noopener\">SDD_MMC.h library<\/a>.<\/p>\n\n\n\n<p>If you use the SD library, you&#8217;re using the SPI controller. If you use the SDD_MMC library you&#8217;re using the ESP32 SD\/SDIO\/MMC controller. You can learn more about the <a href=\"https:\/\/docs.espressif.com\/projects\/esp-idf\/en\/latest\/esp32\/api-reference\/storage\/sdmmc.html\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32 SD\/SDIO\/MMC driver<\/a>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"269\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSD-car-ESP32-Example-Handle-Files-Read-Write_ESP32-microSD-card-read-write.png?resize=800%2C269&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Handle Files in microSD card Example Read and Write\" class=\"wp-image-102299\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSD-car-ESP32-Example-Handle-Files-Read-Write_ESP32-microSD-card-read-write.png?w=800&amp;quality=100&amp;strip=all&amp;ssl=1 800w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSD-car-ESP32-Example-Handle-Files-Read-Write_ESP32-microSD-card-read-write.png?resize=300%2C101&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSD-car-ESP32-Example-Handle-Files-Read-Write_ESP32-microSD-card-read-write.png?resize=768%2C258&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/figure><\/div>\n\n\n<p>There are several examples in Arduino IDE that show how to handle files on the microSD card using the ESP32. In the Arduino IDE, go to <strong>File <\/strong>&gt; <strong>Examples <\/strong>&gt; <strong>SD(esp32)<\/strong> &gt; <strong>SD_Test<\/strong>, or copy the following code. <\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n  Rui Santos\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-microsd-card-arduino\/\n  \n  This sketch can be found at: Examples &gt; SD(esp32) &gt; SD_Test\n*\/\n\n#include &quot;FS.h&quot;\n#include &quot;SD.h&quot;\n#include &quot;SPI.h&quot;\n\nvoid listDir(fs::FS &amp;fs, const char * dirname, uint8_t levels){\n  Serial.printf(&quot;Listing directory: %s\\n&quot;, dirname);\n\n  File root = fs.open(dirname);\n  if(!root){\n    Serial.println(&quot;Failed to open directory&quot;);\n    return;\n  }\n  if(!root.isDirectory()){\n    Serial.println(&quot;Not a directory&quot;);\n    return;\n  }\n\n  File file = root.openNextFile();\n  while(file){\n    if(file.isDirectory()){\n      Serial.print(&quot;  DIR : &quot;);\n      Serial.println(file.name());\n      if(levels){\n        listDir(fs, file.name(), levels -1);\n      }\n    } else {\n      Serial.print(&quot;  FILE: &quot;);\n      Serial.print(file.name());\n      Serial.print(&quot;  SIZE: &quot;);\n      Serial.println(file.size());\n    }\n    file = root.openNextFile();\n  }\n}\n\nvoid createDir(fs::FS &amp;fs, const char * path){\n  Serial.printf(&quot;Creating Dir: %s\\n&quot;, path);\n  if(fs.mkdir(path)){\n    Serial.println(&quot;Dir created&quot;);\n  } else {\n    Serial.println(&quot;mkdir failed&quot;);\n  }\n}\n\nvoid removeDir(fs::FS &amp;fs, const char * path){\n  Serial.printf(&quot;Removing Dir: %s\\n&quot;, path);\n  if(fs.rmdir(path)){\n    Serial.println(&quot;Dir removed&quot;);\n  } else {\n    Serial.println(&quot;rmdir failed&quot;);\n  }\n}\n\nvoid readFile(fs::FS &amp;fs, const char * path){\n  Serial.printf(&quot;Reading file: %s\\n&quot;, path);\n\n  File file = fs.open(path);\n  if(!file){\n    Serial.println(&quot;Failed to open file for reading&quot;);\n    return;\n  }\n\n  Serial.print(&quot;Read from file: &quot;);\n  while(file.available()){\n    Serial.write(file.read());\n  }\n  file.close();\n}\n\nvoid writeFile(fs::FS &amp;fs, const char * path, const char * message){\n  Serial.printf(&quot;Writing file: %s\\n&quot;, path);\n\n  File file = fs.open(path, FILE_WRITE);\n  if(!file){\n    Serial.println(&quot;Failed to open file for writing&quot;);\n    return;\n  }\n  if(file.print(message)){\n    Serial.println(&quot;File written&quot;);\n  } else {\n    Serial.println(&quot;Write failed&quot;);\n  }\n  file.close();\n}\n\nvoid appendFile(fs::FS &amp;fs, const char * path, const char * message){\n  Serial.printf(&quot;Appending to file: %s\\n&quot;, path);\n\n  File file = fs.open(path, FILE_APPEND);\n  if(!file){\n    Serial.println(&quot;Failed to open file for appending&quot;);\n    return;\n  }\n  if(file.print(message)){\n      Serial.println(&quot;Message appended&quot;);\n  } else {\n    Serial.println(&quot;Append failed&quot;);\n  }\n  file.close();\n}\n\nvoid renameFile(fs::FS &amp;fs, const char * path1, const char * path2){\n  Serial.printf(&quot;Renaming file %s to %s\\n&quot;, path1, path2);\n  if (fs.rename(path1, path2)) {\n    Serial.println(&quot;File renamed&quot;);\n  } else {\n    Serial.println(&quot;Rename failed&quot;);\n  }\n}\n\nvoid deleteFile(fs::FS &amp;fs, const char * path){\n  Serial.printf(&quot;Deleting file: %s\\n&quot;, path);\n  if(fs.remove(path)){\n    Serial.println(&quot;File deleted&quot;);\n  } else {\n    Serial.println(&quot;Delete failed&quot;);\n  }\n}\n\nvoid testFileIO(fs::FS &amp;fs, const char * path){\n  File file = fs.open(path);\n  static uint8_t buf[512];\n  size_t len = 0;\n  uint32_t start = millis();\n  uint32_t end = start;\n  if(file){\n    len = file.size();\n    size_t flen = len;\n    start = millis();\n    while(len){\n      size_t toRead = len;\n      if(toRead &gt; 512){\n        toRead = 512;\n      }\n      file.read(buf, toRead);\n      len -= toRead;\n    }\n    end = millis() - start;\n    Serial.printf(&quot;%u bytes read for %u ms\\n&quot;, flen, end);\n    file.close();\n  } else {\n    Serial.println(&quot;Failed to open file for reading&quot;);\n  }\n\n\n  file = fs.open(path, FILE_WRITE);\n  if(!file){\n    Serial.println(&quot;Failed to open file for writing&quot;);\n    return;\n  }\n\n  size_t i;\n  start = millis();\n  for(i=0; i&lt;2048; i++){\n    file.write(buf, 512);\n  }\n  end = millis() - start;\n  Serial.printf(&quot;%u bytes written for %u ms\\n&quot;, 2048 * 512, end);\n  file.close();\n}\n\nvoid setup(){\n  Serial.begin(115200);\n  if(!SD.begin(5)){\n    Serial.println(&quot;Card Mount Failed&quot;);\n    return;\n  }\n  uint8_t cardType = SD.cardType();\n\n  if(cardType == CARD_NONE){\n    Serial.println(&quot;No SD card attached&quot;);\n    return;\n  }\n\n  Serial.print(&quot;SD Card Type: &quot;);\n  if(cardType == CARD_MMC){\n    Serial.println(&quot;MMC&quot;);\n  } else if(cardType == CARD_SD){\n    Serial.println(&quot;SDSC&quot;);\n  } else if(cardType == CARD_SDHC){\n    Serial.println(&quot;SDHC&quot;);\n  } else {\n    Serial.println(&quot;UNKNOWN&quot;);\n  }\n\n  uint64_t cardSize = SD.cardSize() \/ (1024 * 1024);\n  Serial.printf(&quot;SD Card Size: %lluMB\\n&quot;, cardSize);\n\n  listDir(SD, &quot;\/&quot;, 0);\n  createDir(SD, &quot;\/mydir&quot;);\n  listDir(SD, &quot;\/&quot;, 0);\n  removeDir(SD, &quot;\/mydir&quot;);\n  listDir(SD, &quot;\/&quot;, 2);\n  writeFile(SD, &quot;\/hello.txt&quot;, &quot;Hello &quot;);\n  appendFile(SD, &quot;\/hello.txt&quot;, &quot;World!\\n&quot;);\n  readFile(SD, &quot;\/hello.txt&quot;);\n  deleteFile(SD, &quot;\/foo.txt&quot;);\n  renameFile(SD, &quot;\/hello.txt&quot;, &quot;\/foo.txt&quot;);\n  readFile(SD, &quot;\/foo.txt&quot;);\n  testFileIO(SD, &quot;\/test.txt&quot;);\n  Serial.printf(&quot;Total space: %lluMB\\n&quot;, SD.totalBytes() \/ (1024 * 1024));\n  Serial.printf(&quot;Used space: %lluMB\\n&quot;, SD.usedBytes() \/ (1024 * 1024));\n}\n\nvoid loop(){\n\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/MicroSD_Card\/ESP32_SD_Test.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>This example shows how to do almost any task you may need with the microSD card:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"#listDir\">List a directory<\/a>;<\/li>\n\n\n\n<li><a href=\"#createDir\">Create a directory<\/a>;<\/li>\n\n\n\n<li><a href=\"#removeDir\">Remove a directory<\/a>;<\/li>\n\n\n\n<li><a href=\"#readFile\">Read a file content<\/a>;<\/li>\n\n\n\n<li><a href=\"#writeFile\">Write content to a file<\/a>;<\/li>\n\n\n\n<li><a href=\"#appendFile\">Append content to file<\/a>;<\/li>\n\n\n\n<li><a href=\"#renameFile\">Rename a file<\/a>;<\/li>\n\n\n\n<li><a href=\"#deleteFile\">Delete a file<\/a>;<\/li>\n\n\n\n<li><a href=\"#initmicrosdcard\">Initialize microSD card<\/a>;<\/li>\n\n\n\n<li><a href=\"#microsdcardtype\">Get microSD card type<\/a>;<\/li>\n\n\n\n<li><a href=\"#microsdcardsize\">Get microSD card size<\/a>;<\/li>\n<\/ul>\n\n\n\n<p>Alternatively, you can use the <strong>SD_MMC<\/strong> examples &#8211; these are similar to the SD examples, but use the SDMMC driver. For the SDMMC driver, you need a compatible microSD card module. The module we&#8217;re using in this tutorial doesn&#8217;t support SDMMC.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How the Code Works<\/h3>\n\n\n\n<p>First, you need to include the following libraries: <span class=\"rnthl rntliteral\">FS.h<\/span> to handle files, <span class=\"rnthl rntliteral\">SD.h<\/span> to interface with the microSD card and <span class=\"rnthl rntliteral\">SPI.h<\/span> to use SPI communication protocol.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include \"FS.h\"\n#include \"SD.h\"\n#include \"SPI.h\"<\/code><\/pre>\n\n\n\n<p>The example provides several functions to handle files on the microSD card.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"listDir\">List a directory<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">listDir()<\/span> function lists the directories on the SD card. This function accepts as arguments the filesystem (<span class=\"rnthl rntliteral\">SD<\/span>), the main directory&#8217;s name, and the levels to go into the directory.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void listDir(fs::FS &amp;fs, const char * dirname, uint8_t levels){\n  Serial.printf(\"Listing directory: %s\\n\", dirname);\n\n  File root = fs.open(dirname);\n  if(!root){\n    Serial.println(\"Failed to open directory\");\n    return;\n  }\n  if(!root.isDirectory()){\n    Serial.println(\"Not a directory\");\n    return;\n  }\n\n  File file = root.openNextFile();\n  while(file){\n    if(file.isDirectory()){\n      Serial.print(\"  DIR : \");\n      Serial.println(file.name());\n      if(levels){\n        listDir(fs, file.name(), levels -1);\n      }\n    } else {\n      Serial.print(\"  FILE: \");\n      Serial.print(file.name());\n      Serial.print(\"  SIZE: \");\n      Serial.println(file.size());\n    }\n     file = root.openNextFile();\n  }\n}<\/code><\/pre>\n\n\n\n<p>Here&#8217;s an example of how to call this function. The <span class=\"rnthl rntliteral\">\/<\/span> corresponds to the microSD card root directory.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>listDir(SD, \"\/\", 0);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"createDir\">Create a Directory<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">createDir()<\/span> function creates a new directory. Pass as an argument the <span class=\"rnthl rntliteral\">SD<\/span> filesystem and the directory name path.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void createDir(fs::FS &amp;fs, const char * path){\n  Serial.printf(\"Creating Dir: %s\\n\", path);\n  if(fs.mkdir(path)){\n    Serial.println(\"Dir created\");\n  } else {\n    Serial.println(\"mkdir failed\");\n  }\n}<\/code><\/pre>\n\n\n\n<p>For example, the following command creates a new directory on the root called <span class=\"rnthl rntliteral\">mydir<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>createDir(SD, \"\/mydir\");<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"removeDir\">Remove a Directory<\/h4>\n\n\n\n<p>To remove a directory from the microSD card, use the <span class=\"rnthl rntliteral\">removeDir()<\/span> function and pass as an argument the SD filesystem and the directory name path.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void removeDir(fs::FS &amp;fs, const char * path){\n  Serial.printf(\"Removing Dir: %s\\n\", path);\n  if(fs.rmdir(path)){\n    Serial.println(\"Dir removed\");\n  } else {\n    Serial.println(\"rmdir failed\");\n  }\n}<\/code><\/pre>\n\n\n\n<p>Here is an example:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>removeDir(SD, \"\/mydir\");<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"readFile\">Read File Content<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">readFile()<\/span> function reads the content of a file and prints the content in the Serial Monitor. As with previous functions, pass as an argument the <span class=\"rnthl rntliteral\">SD<\/span> filesystem and the file path.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void readFile(fs::FS &amp;fs, const char * path){\n  Serial.printf(\"Reading file: %s\\n\", path);\n\n  File file = fs.open(path);\n  if(!file){\n    Serial.println(\"Failed to open file for reading\");\n    return;\n  }\n\n  Serial.print(\"Read from file: \");\n  while(file.available()){\n    Serial.write(file.read());\n  }\n  file.close();\n}<\/code><\/pre>\n\n\n\n<p>For example, the following line reads the content of the <span class=\"rnthl rntliteral\">hello.txt<\/span> file.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>readFile(SD, \"\/hello.txt\")<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"writeFile\">Write Content to a File<\/h4>\n\n\n\n<p>To write content to a file, you can use the <span class=\"rnthl rntliteral\">writeFile()<\/span> function. Pass as an argument, the <span class=\"rnthl rntliteral\">SD<\/span> filesystem, the file path and the message <\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void writeFile(fs::FS &amp;fs, const char * path, const char * message){\n  Serial.printf(\"Writing file: %s\\n\", path);\n\n  File file = fs.open(path, FILE_WRITE);\n  if(!file){\n    Serial.println(\"Failed to open file for writing\");\n    return;\n  }\n  if(file.print(message)){\n    Serial.println(\"File written\");\n  } else {\n    Serial.println(\"Write failed\");\n  }\n  file.close();\n}<\/code><\/pre>\n\n\n\n<p>The following line writes <span class=\"rnthl rntliteral\">Hello <\/span> in the <span class=\"rnthl rntliteral\">hello.txt<\/span> file.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>writeFile(SD, \"\/hello.txt\", \"Hello \");<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"appendFile\">Append Content to a File<\/h4>\n\n\n\n<p>Similarly, you can append content to a file (without overwriting previous content) using the <span class=\"rnthl rntliteral\">appendFile()<\/span> function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void appendFile(fs::FS &amp;fs, const char * path, const char * message){\n  Serial.printf(\"Appending to file: %s\\n\", path);\n\n  File file = fs.open(path, FILE_APPEND);\n  if(!file){\n    Serial.println(\"Failed to open file for appending\");\n    return;\n  }\n  if(file.print(message)){\n    Serial.println(\"Message appended\");\n  } else {\n    Serial.println(\"Append failed\");\n  }\n  file.close();\n}<\/code><\/pre>\n\n\n\n<p>The following line appends the message <span class=\"rnthl rntliteral\">World!\\n<\/span> in the <span class=\"rnthl rntliteral\">hello.txt<\/span> file. The <span class=\"rnthl rntliteral\">\\n<\/span> means that the next time you write something to the file, it will be written in a new line.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>appendFile(SD, \"\/hello.txt\", \"World!\\n\");<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"renameFile\">Rename a File<\/h4>\n\n\n\n<p>You can rename a file using the <span class=\"rnthl rntliteral\">renameFile()<\/span> function. Pass as arguments the SD filesystem, the original filename, and the new filename.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void renameFile(fs::FS &amp;fs, const char * path1, const char * path2){\n  Serial.printf(\"Renaming file %s to %s\\n\", path1, path2);\n  if (fs.rename(path1, path2)) {\n    Serial.println(\"File renamed\");\n  } else {\n    Serial.println(\"Rename failed\");\n  }\n}<\/code><\/pre>\n\n\n\n<p>The following line renames the <span class=\"rnthl rntliteral\">hello.txt<\/span> file to <span class=\"rnthl rntliteral\">foo.txt<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>renameFile(SD, \"\/hello.txt\", \"\/foo.txt\");<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"deleteFile\">Delete a File<\/h4>\n\n\n\n<p>Use the <span class=\"rnthl rntliteral\">deleteFile()<\/span> function to delete a file. Pass as an argument the <span class=\"rnthl rntliteral\">SD<\/span> filesystem and the file path of the file you want to delete.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void deleteFile(fs::FS &amp;fs, const char * path){\n  Serial.printf(\"Deleting file: %s\\n\", path);\n  if(fs.remove(path)){\n    Serial.println(\"File deleted\");\n  } else {\n    Serial.println(\"Delete failed\");\n  }\n}<\/code><\/pre>\n\n\n\n<p>The following line deletes the <span class=\"rnthl rntliteral\">foo.txt<\/span> file from the microSD card.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>deleteFile(SD, \"\/foo.txt\");<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"testFile\">Test a File<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">testFileIO()<\/span> functions shows how long it takes to read the content of a file.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void testFileIO(fs::FS &amp;fs, const char * path){\n  File file = fs.open(path);\n  static uint8_t buf&#091;512];\n  size_t len = 0;\n  uint32_t start = millis();\n  uint32_t end = start;\n  if(file){\n    len = file.size();\n    size_t flen = len;\n    start = millis();\n    while(len){\n      size_t toRead = len;\n      if(toRead &gt; 512){\n        toRead = 512;\n      }\n      file.read(buf, toRead);\n      len -= toRead;\n    }\n    end = millis() - start;\n    Serial.printf(\"%u bytes read for %u ms\\n\", flen, end);\n    file.close();\n  } \n  else {\n    Serial.println(\"Failed to open file for reading\");\n  }\n\n  file = fs.open(path, FILE_WRITE);\n  if(!file){\n    Serial.println(\"Failed to open file for writing\");\n    return;\n  }\n\n  size_t i;\n  start = millis();\n  for(i=0; i&lt;2048; i++){\n    file.write(buf, 512);\n  }\n  end = millis() - start;\n  Serial.printf(\"%u bytes written for %u ms\\n\", 2048 * 512, end);\n  file.close();\n}<\/code><\/pre>\n\n\n\n<p>The following function tests the <span class=\"rnthl rntliteral\">test.txt<\/span> file.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>testFileIO(SD, \"\/test.txt\");<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"initmicrosdcard\">Initialize the microSD Card<\/h4>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, the following lines initialize the microSD card with <span class=\"rnthl rntliteral\">SD.begin()<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.begin(115200);\nif(!SD.begin()){\n  Serial.println(\"Card Mount Failed\");\n  return;\n}\nuint8_t cardType = SD.cardType();\n\nif(cardType == CARD_NONE){\n  Serial.println(\"No SD card attached\");\n  return;\n}<\/code><\/pre>\n\n\n\n<p>If you don&#8217;t pass any argument to the <span class=\"rnthl rntliteral\">begin()<\/span> function, it will try to initialize SPI communication with the microSD card on the default chip select (CS) pin. If you want to use another CS pin, you can pass it as an argument to the <span class=\"rnthl rntliteral\">begin()<\/span> function. For example, if you wanted to use GPIO 17 as a CS pin, you should use the following lines of code:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.begin(115200);\nif(!SD.begin(17)){\n  Serial.println(\"Card Mount Failed\");\n  return;\n}\nuint8_t cardType = SD.cardType();<\/code><\/pre>\n\n\n\n<p>If you want to use custom SPI pins with the microSD card, <a href=\"#sdcardcustompins\">go to this section<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"microsdcardtype\">Get microSD Card Type<\/h4>\n\n\n\n<p>The following lines print the microSD card type on the Serial Monitor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.print(\"SD Card Type: \");\nif(cardType == CARD_MMC){\n  Serial.println(\"MMC\");\n} else if(cardType == CARD_SD){\n  Serial.println(\"SDSC\");\n} else if(cardType == CARD_SDHC){\n  Serial.println(\"SDHC\");\n} else {\n  Serial.println(\"UNKNOWN\");\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"microsdcardsize\">Get microSD Card Size<\/h4>\n\n\n\n<p>You can get the microSD card size by calling the <span class=\"rnthl rntliteral\">cardSize()<\/span> method:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>uint64_t cardSize = SD.cardSize() \/ (1024 * 1024);\nSerial.printf(\"SD Card Size: %lluMB\\n\", cardSize);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Testing MicroSD Card Functions<\/h4>\n\n\n\n<p>The following lines call the functions we&#8217;ve seen previously.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>listDir(SD, \"\/\", 0);\ncreateDir(SD, \"\/mydir\");\nlistDir(SD, \"\/\", 0);\nremoveDir(SD, \"\/mydir\");\nlistDir(SD, \"\/\", 2);\nwriteFile(SD, \"\/hello.txt\", \"Hello \");\nappendFile(SD, \"\/hello.txt\", \"World!\\n\");\nreadFile(SD, \"\/hello.txt\");\ndeleteFile(SD, \"\/foo.txt\");\nrenameFile(SD, \"\/hello.txt\", \"\/foo.txt\");\nreadFile(SD, \"\/foo.txt\");\ntestFileIO(SD, \"\/test.txt\");\nSerial.printf(\"Total space: %lluMB\\n\", SD.totalBytes() \/ (1024 * 1024));\nSerial.printf(\"Used space: %lluMB\\n\", SD.usedBytes() \/ (1024 * 1024));<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Demonstration<\/h3>\n\n\n\n<p>Upload the previous sketch to your ESP32 board. After that, open the Serial Monitor and press the ESP32 on-board RST button. If the initialization succeeds, you&#8217;ll get similar messages on the Serial Monitor.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"958\" height=\"761\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSDCard.-Serial-Monitor-Example-ESP32.png?resize=958%2C761&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 board MicroSD Card Module testing features: read write delete\" class=\"wp-image-102330\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSDCard.-Serial-Monitor-Example-ESP32.png?w=958&amp;quality=100&amp;strip=all&amp;ssl=1 958w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSDCard.-Serial-Monitor-Example-ESP32.png?resize=300%2C238&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSDCard.-Serial-Monitor-Example-ESP32.png?resize=768%2C610&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 958px) 100vw, 958px\" \/><\/figure><\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"958\" height=\"761\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSDCard.-Serial-Monitor-Example-ESP32-2.png?resize=958%2C761&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 board MicroSD Card Module testing features: read write delete\" class=\"wp-image-102331\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSDCard.-Serial-Monitor-Example-ESP32-2.png?w=958&amp;quality=100&amp;strip=all&amp;ssl=1 958w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSDCard.-Serial-Monitor-Example-ESP32-2.png?resize=300%2C238&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/microSDCard.-Serial-Monitor-Example-ESP32-2.png?resize=768%2C610&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 958px) 100vw, 958px\" \/><\/figure><\/div>\n\n\n<hr class=\"wp-block-separator has-css-opacity is-style-wide\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"sdcardcustompins\">Use Custom SPI Pins with the MicroSD Card<\/h2>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">SD.h<\/span> and <span class=\"rnthl rntliteral\">SD_MMC.h<\/span> libraries use the VSPI SPI pins (23, 19, 18, 5) by default. You can set other pins as SPI pins. The ESP32 features two SPI interfaces: HSPI and VSPI on the following pins:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>SPI<\/strong><\/td><td><strong>MOSI<\/strong><\/td><td><strong>MISO<\/strong><\/td><td><strong>CLK<\/strong><\/td><td><strong>CS<\/strong><\/td><\/tr><tr><td><strong>VSPI<\/strong><\/td><td>GPIO 23<\/td><td>GPIO 19<\/td><td>GPIO 18<\/td><td>GPIO 5<\/td><\/tr><tr><td><strong>HSPI<\/strong><\/td><td>GPIO 13<\/td><td>GPIO 12<\/td><td>GPIO 14<\/td><td>GPIO 15<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"rntbox rntclblue\">Recommended reading: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-pinout-reference-gpios\/\">ESP32 Pinout Reference: Which GPIO pins should you use?<\/a><\/p>\n\n\n\n<p>To use other SPI pins, you can proceed as follows:<\/p>\n\n\n\n<p>At the beginning of your code, declare the pins you want to use, for example:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define SCK  17\n#define MISO  19\n#define MOSI  23\n#define CS  5<\/code><\/pre>\n\n\n\n<p>Create a new SPI class on HSPI or VSPI. We&#8217;re using VSPI. Both will work fine.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>SPIClass spi = SPIClass(VSPI);<\/code><\/pre>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, initialize SPI communication protocol on the pins defined previously:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>spi.begin(SCK, MISO, MOSI, CS);<\/code><\/pre>\n\n\n\n<p>Finally, initialize the microSD card with the <span class=\"rnthl rntliteral\">begin()<\/span> method. Pass as argument the CS pin, the SPI instance you want to use, and the bus frequency.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (!SD.begin(CS,spi,80000000)) {\n  Serial.println(\"Card Mount Failed\");\n  return;\n}<\/code><\/pre>\n\n\n\n<p>Here is the sample code modified to use custom SPI pins:<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n  Rui Santos\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-microsd-card-arduino\/\n  \n  This sketch was mofidied from: Examples &gt; SD(esp32) &gt; SD_Test\n*\/\n\n#include &quot;FS.h&quot;\n#include &quot;SD.h&quot;\n#include &quot;SPI.h&quot;\n\n#define SCK  17\n#define MISO  19\n#define MOSI  23\n#define CS  5\n\nSPIClass spi = SPIClass(VSPI);\n\nvoid listDir(fs::FS &amp;fs, const char * dirname, uint8_t levels){\n  Serial.printf(&quot;Listing directory: %s\\n&quot;, dirname);\n\n  File root = fs.open(dirname);\n  if(!root){\n    Serial.println(&quot;Failed to open directory&quot;);\n    return;\n  }\n  if(!root.isDirectory()){\n    Serial.println(&quot;Not a directory&quot;);\n    return;\n  }\n\n  File file = root.openNextFile();\n  while(file){\n    if(file.isDirectory()){\n      Serial.print(&quot;  DIR : &quot;);\n      Serial.println(file.name());\n      if(levels){\n        listDir(fs, file.name(), levels -1);\n      }\n    } else {\n      Serial.print(&quot;  FILE: &quot;);\n      Serial.print(file.name());\n      Serial.print(&quot;  SIZE: &quot;);\n      Serial.println(file.size());\n    }\n    file = root.openNextFile();\n  }\n}\n\nvoid createDir(fs::FS &amp;fs, const char * path){\n  Serial.printf(&quot;Creating Dir: %s\\n&quot;, path);\n  if(fs.mkdir(path)){\n    Serial.println(&quot;Dir created&quot;);\n  } else {\n    Serial.println(&quot;mkdir failed&quot;);\n  }\n}\n\nvoid removeDir(fs::FS &amp;fs, const char * path){\n  Serial.printf(&quot;Removing Dir: %s\\n&quot;, path);\n  if(fs.rmdir(path)){\n    Serial.println(&quot;Dir removed&quot;);\n  } else {\n    Serial.println(&quot;rmdir failed&quot;);\n  }\n}\n\nvoid readFile(fs::FS &amp;fs, const char * path){\n  Serial.printf(&quot;Reading file: %s\\n&quot;, path);\n\n  File file = fs.open(path);\n  if(!file){\n    Serial.println(&quot;Failed to open file for reading&quot;);\n    return;\n  }\n\n  Serial.print(&quot;Read from file: &quot;);\n  while(file.available()){\n    Serial.write(file.read());\n  }\n  file.close();\n}\n\nvoid writeFile(fs::FS &amp;fs, const char * path, const char * message){\n  Serial.printf(&quot;Writing file: %s\\n&quot;, path);\n\n  File file = fs.open(path, FILE_WRITE);\n  if(!file){\n    Serial.println(&quot;Failed to open file for writing&quot;);\n    return;\n  }\n  if(file.print(message)){\n    Serial.println(&quot;File written&quot;);\n  } else {\n    Serial.println(&quot;Write failed&quot;);\n  }\n  file.close();\n}\n\nvoid appendFile(fs::FS &amp;fs, const char * path, const char * message){\n  Serial.printf(&quot;Appending to file: %s\\n&quot;, path);\n\n  File file = fs.open(path, FILE_APPEND);\n  if(!file){\n    Serial.println(&quot;Failed to open file for appending&quot;);\n    return;\n  }\n  if(file.print(message)){\n    Serial.println(&quot;Message appended&quot;);\n  } else {\n    Serial.println(&quot;Append failed&quot;);\n  }\n  file.close();\n}\n\nvoid renameFile(fs::FS &amp;fs, const char * path1, const char * path2){\n  Serial.printf(&quot;Renaming file %s to %s\\n&quot;, path1, path2);\n  if (fs.rename(path1, path2)) {\n    Serial.println(&quot;File renamed&quot;);\n  } else {\n    Serial.println(&quot;Rename failed&quot;);\n  }\n}\n\nvoid deleteFile(fs::FS &amp;fs, const char * path){\n  Serial.printf(&quot;Deleting file: %s\\n&quot;, path);\n  if(fs.remove(path)){\n    Serial.println(&quot;File deleted&quot;);\n  } else {\n    Serial.println(&quot;Delete failed&quot;);\n  }\n}\n\nvoid testFileIO(fs::FS &amp;fs, const char * path){\n  File file = fs.open(path);\n  static uint8_t buf[512];\n  size_t len = 0;\n  uint32_t start = millis();\n  uint32_t end = start;\n  if(file){\n    len = file.size();\n    size_t flen = len;\n    start = millis();\n    while(len){\n      size_t toRead = len;\n      if(toRead &gt; 512){\n        toRead = 512;\n      }\n      file.read(buf, toRead);\n      len -= toRead;\n    }\n    end = millis() - start;\n    Serial.printf(&quot;%u bytes read for %u ms\\n&quot;, flen, end);\n    file.close();\n  } else {\n    Serial.println(&quot;Failed to open file for reading&quot;);\n  }\n\n\n  file = fs.open(path, FILE_WRITE);\n  if(!file){\n    Serial.println(&quot;Failed to open file for writing&quot;);\n    return;\n  }\n\n  size_t i;\n  start = millis();\n  for(i=0; i&lt;2048; i++){\n    file.write(buf, 512);\n  }\n  end = millis() - start;\n  Serial.printf(&quot;%u bytes written for %u ms\\n&quot;, 2048 * 512, end);\n  file.close();\n}\n\nvoid setup(){\n  Serial.begin(115200);\n  spi.begin(SCK, MISO, MOSI, CS);\n\n  if (!SD.begin(CS,spi,80000000)) {\n    Serial.println(&quot;Card Mount Failed&quot;);\n    return;\n  }\n  uint8_t cardType = SD.cardType();\n\n  if(cardType == CARD_NONE){\n    Serial.println(&quot;No SD card attached&quot;);\n    return;\n  }\n\n  Serial.print(&quot;SD Card Type: &quot;);\n  if(cardType == CARD_MMC){\n    Serial.println(&quot;MMC&quot;);\n  } else if(cardType == CARD_SD){\n    Serial.println(&quot;SDSC&quot;);\n  } else if(cardType == CARD_SDHC){\n    Serial.println(&quot;SDHC&quot;);\n  } else {\n    Serial.println(&quot;UNKNOWN&quot;);\n  }\n\n  uint64_t cardSize = SD.cardSize() \/ (1024 * 1024);\n  Serial.printf(&quot;SD Card Size: %lluMB\\n&quot;, cardSize);\n\n  listDir(SD, &quot;\/&quot;, 0);\n  createDir(SD, &quot;\/mydir&quot;);\n  listDir(SD, &quot;\/&quot;, 0);\n  removeDir(SD, &quot;\/mydir&quot;);\n  listDir(SD, &quot;\/&quot;, 2);\n  writeFile(SD, &quot;\/hello.txt&quot;, &quot;Hello &quot;);\n  appendFile(SD, &quot;\/hello.txt&quot;, &quot;World!\\n&quot;);\n  readFile(SD, &quot;\/hello.txt&quot;);\n  deleteFile(SD, &quot;\/foo.txt&quot;);\n  renameFile(SD, &quot;\/hello.txt&quot;, &quot;\/foo.txt&quot;);\n  readFile(SD, &quot;\/foo.txt&quot;);\n  testFileIO(SD, &quot;\/test.txt&quot;);\n  Serial.printf(&quot;Total space: %lluMB\\n&quot;, SD.totalBytes() \/ (1024 * 1024));\n  Serial.printf(&quot;Used space: %lluMB\\n&quot;, SD.usedBytes() \/ (1024 * 1024));\n}\n\nvoid loop(){\n\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/MicroSD_Card\/ESP32_SD_Test_Pins.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity is-style-wide\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"datalogging\">Example: ESP32 Data Logging to microSD Card<\/h2>\n\n\n\n<p>Using a microSD card is especially useful for data logging projects. As an example, we&#8217;ll show you how to save sensor readings from a BME280 sensor with timestamps (<a href=\"https:\/\/randomnerdtutorials.com\/epoch-unix-time-esp32-arduino\/\">epoch time<\/a>).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"785\" height=\"355\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/03\/ESP32-datalogging-BME280-microSD-card-project-overview-datalogging.png?resize=785%2C355&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 datalogging BME280-microSD card project overview\" class=\"wp-image-102365\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/03\/ESP32-datalogging-BME280-microSD-card-project-overview-datalogging.png?w=785&amp;quality=100&amp;strip=all&amp;ssl=1 785w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/03\/ESP32-datalogging-BME280-microSD-card-project-overview-datalogging.png?resize=300%2C136&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/03\/ESP32-datalogging-BME280-microSD-card-project-overview-datalogging.png?resize=768%2C347&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 785px) 100vw, 785px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">Prerequisites<\/h3>\n\n\n\n<p>For this example, make sure you have the following libraries installed:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/adafruit\/Adafruit_BME280_Library\" target=\"_blank\" rel=\"noreferrer noopener\">Adafruit BME280 Library<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/adafruit\/Adafruit_Sensor\" target=\"_blank\" rel=\"noreferrer noopener\">Adafruit Unified Sensor Driver<\/a><\/li>\n<\/ul>\n\n\n\n<p>You can install these libraries using the Arduino library manager. In your Arduino IDE, go to <strong>Sketch <\/strong>&gt; <strong>Include Library<\/strong> &gt; <strong>Manage Libraries&#8230;<\/strong> Then, search for the library names and install them.<\/p>\n\n\n\n<p>If you\u2019re using VS Code with PlatformIO, copy the following lines to the&nbsp;<em>platformio.ini<\/em>&nbsp;file to include all the necessary libraries.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>lib_deps = adafruit\/Adafruit BME280 Library @ ^2.1.0\n  adafruit\/Adafruit Unified Sensor @ ^1.1.4<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Schematic Diagram<\/h4>\n\n\n\n<p>For this example, you need to wire the microSD card module and the BME280 sensor to the ESP32. Here&#8217;s a list of the parts required:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\" rel=\"noreferrer noopener\">ESP32 development board<\/a> (read: <a href=\"https:\/\/makeradvisor.com\/esp32-development-boards-review-comparison\/\" target=\"_blank\" rel=\"noreferrer noopener\">Best ESP32 development boards<\/a>)<\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/bme280-sensor-module\/\" target=\"_blank\" rel=\"noreferrer noopener\">BME280 sensor<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/sd-card-module\/\" target=\"_blank\" rel=\"noreferrer noopener\">MicroSD Card Module<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/microsd-card-raspberry-pi-16gb-class-10\/\" target=\"_blank\" rel=\"noreferrer noopener\">MicroSD Card<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\" target=\"_blank\" rel=\"noreferrer noopener\">Jumper Wires<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/mb-102-solderless-breadboard-830-points\/\" target=\"_blank\" rel=\"noreferrer noopener\">Breadboard<\/a><\/li>\n<\/ul>\n\n\n\n<p>Wire the circuit by following the next schematic diagram.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"860\" height=\"926\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/03\/ESP32-microSD-card-BME280-circuit-diagram.png?resize=860%2C926&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 microSD card BME280 circuit diagram schematic\" class=\"wp-image-102366\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/03\/ESP32-microSD-card-BME280-circuit-diagram.png?w=860&amp;quality=100&amp;strip=all&amp;ssl=1 860w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/03\/ESP32-microSD-card-BME280-circuit-diagram.png?resize=279%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 279w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/03\/ESP32-microSD-card-BME280-circuit-diagram.png?resize=768%2C827&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/figure><\/div>\n\n\n<p>You can also take a look at the following tables:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>BME280<\/strong><\/td><td><strong>ESP32<\/strong><\/td><\/tr><tr><td>VIN<\/td><td><span class=\"rnthl rntcred\">3V3<\/span><\/td><\/tr><tr><td>GND<\/td><td><span class=\"rnthl rntcblack\">GND<\/span><\/td><\/tr><tr><td>SCL<\/td><td><span class=\"rnthl rntcyellow\">GPIO 22<\/span><\/td><\/tr><tr><td>SDA<\/td><td><span class=\"rnthl rntcyellow\">GPIO 21<\/span><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>microSD card module<\/strong><\/td><td><strong>ESP32<\/strong><\/td><\/tr><tr><td>3V3<\/td><td><span class=\"rnthl rntcred\">3.3V<\/span><\/td><\/tr><tr><td>CS<\/td><td><span class=\"rnthl rntclblue\">GPIO 5<\/span><\/td><\/tr><tr><td>MOSI<\/td><td><span class=\"rnthl rntclblue\">GPIO 23<\/span><\/td><\/tr><tr><td>CLK<\/td><td><span class=\"rnthl rntclblue\">GPIO 18<\/span><\/td><\/tr><tr><td>MISO<\/td><td><span class=\"rnthl rntclblue\">GPIO 19<\/span><\/td><\/tr><tr><td>GND<\/td><td><span class=\"rnthl rntcblack\">GND<\/span><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Code<\/h3>\n\n\n\n<p>Copy the following code to your Arduino IDE. This sketch gets BME280 sensor readings (temperature, humidity, and pressure) and logs them in a file on the microSD card every 30 seconds. It also logs the timestamp (epoch time requested to an NTP server).<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n  Rui Santos\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-microsd-card-arduino\/\n  \n  Permission is hereby granted, free of charge, to any person obtaining a copy\n  of this software and associated documentation files.\n  \n  The above copyright notice and this permission notice shall be included in all\n  copies or substantial portions of the Software.\n*\/\n\n\/\/ Libraries for SD card\n#include &quot;FS.h&quot;\n#include &quot;SD.h&quot;\n#include &lt;SPI.h&gt;\n\n\/\/Libraries for BME280 sensor\n#include &lt;Adafruit_Sensor.h&gt;\n#include &lt;Adafruit_BME280.h&gt;\n\n\/\/ Libraries to get time from NTP Server\n#include &lt;WiFi.h&gt;\n#include &quot;time.h&quot;\n\n\/\/ Replace with your network credentials\nconst char* ssid     = &quot;REPLACE_WITH_YOUR_SSID&quot;;\nconst char* password = &quot;REPLACE_WITH_YOUR_PASSWORD&quot;;\n\n\/\/ Timer variables\nunsigned long lastTime = 0;\nunsigned long timerDelay = 30000;\n\n\/\/ BME280 I2C\nAdafruit_BME280 bme;\n\n\/\/ Variables to hold sensor readings\nfloat temp;\nfloat hum;\nfloat pres;\nString dataMessage;\n\n\/\/ NTP server to request epoch time\nconst char* ntpServer = &quot;pool.ntp.org&quot;;\n\n\/\/ Variable to save current epoch time\nunsigned long epochTime; \n\n\/\/ Function that gets current epoch time\nunsigned long getTime() {\n  time_t now;\n  struct tm timeinfo;\n  if (!getLocalTime(&amp;timeinfo)) {\n    \/\/Serial.println(&quot;Failed to obtain time&quot;);\n    return(0);\n  }\n  time(&amp;now);\n  return now;\n}\n\n\/\/ Initialize WiFi\nvoid initWiFi() {\n  WiFi.mode(WIFI_STA);\n  WiFi.begin(ssid, password);\n  Serial.print(&quot;Connecting to WiFi ..&quot;);\n  while (WiFi.status() != WL_CONNECTED) {\n    Serial.print('.');\n    delay(1000);\n  }\n  Serial.println(WiFi.localIP());\n}\n\n\/\/ Init BME280\nvoid initBME(){\n  if (!bme.begin(0x76)) {\n    Serial.println(&quot;Could not find a valid BME280 sensor, check wiring!&quot;);\n    while (1);\n  }\n}\n\n\/\/ Initialize SD card\nvoid initSDCard(){\n   if (!SD.begin()) {\n    Serial.println(&quot;Card Mount Failed&quot;);\n    return;\n  }\n  uint8_t cardType = SD.cardType();\n\n  if(cardType == CARD_NONE){\n    Serial.println(&quot;No SD card attached&quot;);\n    return;\n  }\n  Serial.print(&quot;SD Card Type: &quot;);\n  if(cardType == CARD_MMC){\n    Serial.println(&quot;MMC&quot;);\n  } else if(cardType == CARD_SD){\n    Serial.println(&quot;SDSC&quot;);\n  } else if(cardType == CARD_SDHC){\n    Serial.println(&quot;SDHC&quot;);\n  } else {\n    Serial.println(&quot;UNKNOWN&quot;);\n  }\n  uint64_t cardSize = SD.cardSize() \/ (1024 * 1024);\n  Serial.printf(&quot;SD Card Size: %lluMB\\n&quot;, cardSize);\n}\n\n\/\/ Write to the SD card\nvoid writeFile(fs::FS &amp;fs, const char * path, const char * message) {\n  Serial.printf(&quot;Writing file: %s\\n&quot;, path);\n\n  File file = fs.open(path, FILE_WRITE);\n  if(!file) {\n    Serial.println(&quot;Failed to open file for writing&quot;);\n    return;\n  }\n  if(file.print(message)) {\n    Serial.println(&quot;File written&quot;);\n  } else {\n    Serial.println(&quot;Write failed&quot;);\n  }\n  file.close();\n}\n\n\/\/ Append data to the SD card\nvoid appendFile(fs::FS &amp;fs, const char * path, const char * message) {\n  Serial.printf(&quot;Appending to file: %s\\n&quot;, path);\n\n  File file = fs.open(path, FILE_APPEND);\n  if(!file) {\n    Serial.println(&quot;Failed to open file for appending&quot;);\n    return;\n  }\n  if(file.print(message)) {\n    Serial.println(&quot;Message appended&quot;);\n  } else {\n    Serial.println(&quot;Append failed&quot;);\n  }\n  file.close();\n}\n\nvoid setup() {\n  Serial.begin(115200);\n  \n  initWiFi();\n  initBME();\n  initSDCard();\n  configTime(0, 0, ntpServer);\n  \n  \/\/ If the data.txt file doesn't exist\n  \/\/ Create a file on the SD card and write the data labels\n  File file = SD.open(&quot;\/data.txt&quot;);\n  if(!file) {\n    Serial.println(&quot;File doesn't exist&quot;);\n    Serial.println(&quot;Creating file...&quot;);\n    writeFile(SD, &quot;\/data.txt&quot;, &quot;Epoch Time, Temperature, Humidity, Pressure \\r\\n&quot;);\n  }\n  else {\n    Serial.println(&quot;File already exists&quot;);  \n  }\n  file.close();\n}\n\nvoid loop() {\n  if ((millis() - lastTime) &gt; timerDelay) {\n    \/\/Get epoch time\n    epochTime = getTime();\n    \n    \/\/Get sensor readings\n    temp = bme.readTemperature();\n    \/\/temp = 1.8*bme.readTemperature() + 32;\n    hum = bme.readHumidity();\n    pres = bme.readPressure()\/100.0F;\n\n    \/\/Concatenate all info separated by commas\n    dataMessage = String(epochTime) + &quot;,&quot; + String(temp) + &quot;,&quot; + String(hum) + &quot;,&quot; + String(pres)+ &quot;\\r\\n&quot;;\n    Serial.print(&quot;Saving data: &quot;);\n    Serial.println(dataMessage);\n\n    \/\/Append the data to file\n    appendFile(SD, &quot;\/data.txt&quot;, dataMessage.c_str());\n\n    lastTime = millis();\n  }\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/MicroSD_Card\/ESP32_SD_Data_Logging.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>Insert your network credentials in the following variables and the code will work straight away:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>const char* ssid     = \"REPLACE_WITH_YOUR_SSID\";\nconst char* password = \"REPLACE_WITH_YOUR_PASSWORD\";<\/code><\/pre>\n\n\n\n<p>This example uses the functions we&#8217;ve seen previously to write and append data to the microSD card (<span class=\"rnthl rntliteral\">writeFile()<\/span> and <span class=\"rnthl rntliteral\">appendFile()<\/span> functions).<\/p>\n\n\n\n<p>To better understand how this example works, we recommend taking a look at the following tutorials:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/epoch-unix-time-esp32-arduino\/\">Get Epoch\/Unix Time with the ESP32 (Arduino)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-bme280-arduino-ide-pressure-temperature-humidity\/\">ESP32 with BME280 Sensor using Arduino IDE (Pressure, Temperature, Humidity)<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Demonstration<\/h3>\n\n\n\n<p>Upload the code to your board. You can check on the Serial Monitor if everything is working as expected.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"803\" height=\"541\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/03\/ESP32-BME280-datalogging-microSD-card-Serial-Monitor.png?resize=803%2C541&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 BME280 Datalogging to microSD card Serial Monitor\" class=\"wp-image-102361\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/03\/ESP32-BME280-datalogging-microSD-card-Serial-Monitor.png?w=803&amp;quality=100&amp;strip=all&amp;ssl=1 803w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/03\/ESP32-BME280-datalogging-microSD-card-Serial-Monitor.png?resize=300%2C202&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/03\/ESP32-BME280-datalogging-microSD-card-Serial-Monitor.png?resize=768%2C517&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 803px) 100vw, 803px\" \/><\/figure><\/div>\n\n\n<p>Let the project run for a while to gather some readings. Then, insert the microSD card on your computer, and you should have a file called <span class=\"rnthl rntliteral\">data.txt<\/span> with the sensor readings.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"481\" height=\"525\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/03\/BME280-datalogging-ESP32-file-with-sensor-readings-microSD-card.png?resize=481%2C525&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 BME280 Datalogging to file on microSD card\" class=\"wp-image-102362\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/03\/BME280-datalogging-ESP32-file-with-sensor-readings-microSD-card.png?w=481&amp;quality=100&amp;strip=all&amp;ssl=1 481w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/03\/BME280-datalogging-ESP32-file-with-sensor-readings-microSD-card.png?resize=275%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 275w\" sizes=\"(max-width: 481px) 100vw, 481px\" \/><\/figure><\/div>\n\n\n<hr class=\"wp-block-separator has-css-opacity is-style-wide\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"webserversdcard\">Example: ESP32 Web Server with Files from microSD Card<\/h2>\n\n\n\n<p>You can save the files to build a web server with the ESP32 on a microSD card (HTML, CSS, JavaScript, and image files). This can be useful if the files are too big to fit on the ESP32 filesystem, or it can also be more convenient depending on your project.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/ESP32-microSD-Card-Web-Server-How-it-Works.png?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Web Server with Files from microSD Card How it Works\" class=\"wp-image-102263\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/ESP32-microSD-Card-Web-Server-How-it-Works.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/ESP32-microSD-Card-Web-Server-How-it-Works.png?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>To show you how to do this, we&#8217;ll create a simple web server that serves a HTML, a CSS and a PNG file to build a web page and display a favicon.<\/p>\n\n\n\n<p>Move the following files to your microSD card (click on the links to download the files):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/MicroSD_Card\/files\/index.zip\" target=\"_blank\" rel=\"noreferrer noopener\">HTML file<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/MicroSD_Card\/files\/style.zip\" target=\"_blank\" rel=\"noreferrer noopener\">CSS file<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/RuiSantosdotme\/build-web-servers-dl\/raw\/main\/favicon.zip\" target=\"_blank\" rel=\"noreferrer noopener\">PNG file<\/a><\/li>\n<\/ul>\n\n\n\n<p><strong>Note:<\/strong> move only the files to the microSD card, not the folders.<\/p>\n\n\n\n<p>Then, upload the following code to your Arduino IDE.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*\n  Rui Santos\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-web-server-microsd-card\/\n  \n  Permission is hereby granted, free of charge, to any person obtaining a copy\n  of this software and associated documentation files.\n  \n  The above copyright notice and this permission notice shall be included in all\n  copies or substantial portions of the Software.\n*\/\n\n#include &lt;Arduino.h&gt;\n#include &lt;WiFi.h&gt;\n#include &lt;AsyncTCP.h&gt;\n#include &lt;ESPAsyncWebServer.h&gt;\n#include &quot;FS.h&quot;\n#include &quot;SD.h&quot;\n#include &quot;SPI.h&quot;\n\n\/\/ Replace with your network credentials\nconst char* ssid = &quot;REPLACE_WITH_YOUR_SSID&quot;;\nconst char* password = &quot;REPLACE_WITH_YOUR_PASSWORD&quot;;\n\n\/\/ Create AsyncWebServer object on port 80\nAsyncWebServer server(80);\n\nvoid initSDCard(){\n  if(!SD.begin()){\n    Serial.println(&quot;Card Mount Failed&quot;);\n    return;\n  }\n  uint8_t cardType = SD.cardType();\n\n  if(cardType == CARD_NONE){\n    Serial.println(&quot;No SD card attached&quot;);\n    return;\n  }\n\n  Serial.print(&quot;SD Card Type: &quot;);\n  if(cardType == CARD_MMC){\n    Serial.println(&quot;MMC&quot;);\n  } else if(cardType == CARD_SD){\n    Serial.println(&quot;SDSC&quot;);\n  } else if(cardType == CARD_SDHC){\n    Serial.println(&quot;SDHC&quot;);\n  } else {\n    Serial.println(&quot;UNKNOWN&quot;);\n  }\n  uint64_t cardSize = SD.cardSize() \/ (1024 * 1024);\n  Serial.printf(&quot;SD Card Size: %lluMB\\n&quot;, cardSize);\n}\n\nvoid initWiFi() {\n  WiFi.mode(WIFI_STA);\n  WiFi.begin(ssid, password);\n  Serial.print(&quot;Connecting to WiFi ..&quot;);\n  while (WiFi.status() != WL_CONNECTED) {\n    Serial.print('.');\n    delay(1000);\n  }\n  Serial.println(WiFi.localIP());\n}\n\nvoid setup() {\n  Serial.begin(115200);\n  initWiFi();\n  initSDCard();\n\n  server.on(&quot;\/&quot;, HTTP_GET, [](AsyncWebServerRequest *request){\n    request-&gt;send(SD, &quot;\/index.html&quot;, &quot;text\/html&quot;);\n  });\n\n  server.serveStatic(&quot;\/&quot;, SD, &quot;\/&quot;);\n\n  server.begin();\n}\n\nvoid loop() {\n  \n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/MicroSD_Card\/ESP32_Web_Server_MicroSD_Card.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>Insert your network credentials in the following variables, and the code should work straight away:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>\/\/ Replace with your network credentials\nconst char* ssid = \"REPLACE_WITH_YOUR_SSID\";\nconst char* password = \"REPLACE_WITH_YOUR_PASSWORD\";<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Demonstration<\/h2>\n\n\n\n<p>After uploading the files to the microSD card and the sketch to your ESP32 board, open the Serial Monitor at a baud rate of 115200. Press the ESP32 on-board RST button. The ESP32 IP address will be displayed on the Serial Monitor.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"761\" height=\"541\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/web-server-microsd-card-serial-monitor-ip-address.png?resize=761%2C541&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Web Server with Files from microSD card Arduino IDE Serial Monitor Demonstration\" class=\"wp-image-102218\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/web-server-microsd-card-serial-monitor-ip-address.png?w=761&amp;quality=100&amp;strip=all&amp;ssl=1 761w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/web-server-microsd-card-serial-monitor-ip-address.png?resize=300%2C213&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 761px) 100vw, 761px\" \/><\/figure><\/div>\n\n\n<p>On your local network, open a web browser and type the ESP32 IP address. You should get access to the following web page built with the files stored on the microSD card.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"731\" height=\"418\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/Web-Server-MicroSD-Card-Example.png?resize=731%2C418&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Web Server with Files from microSD card\" class=\"wp-image-102219\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/Web-Server-MicroSD-Card-Example.png?w=731&amp;quality=100&amp;strip=all&amp;ssl=1 731w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/Web-Server-MicroSD-Card-Example.png?resize=300%2C172&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 731px) 100vw, 731px\" \/><\/figure><\/div>\n\n\n<p>For a detailed explanation of this project, refer to the following tutorial:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-web-server-microsd-card\/\">ESP32 Web Server with Files from microSD Card<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>In this tutorial, you&#8217;ve learned how to interface a microSD card with the ESP32 and read and write files. You&#8217;ve also learned how to use it for data logging projects or storing files to serve in your web server projects.<\/p>\n\n\n\n<p>For more in-depth projects with the microSD card, we recommend taking a look at the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-data-logging-temperature-to-microsd-card\/\">ESP32 Data Logging Temperature to MicroSD Card<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-web-server-microsd-card\/\">ESP32 Web Server with Files from microSD Card<\/a><\/li>\n<\/ul>\n\n\n\n<p>We hope you&#8217;ve found this tutorial useful. Learn more about the ESP32 with our resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/learn-esp32-with-arduino-ide\/\">Learn ESP32 with Arduino IDE<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/build-web-servers-esp32-esp8266-ebook\/\">Build Web Servers with ESP32 and ESP8266<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp32\/\">More ESP32 Projects and Tutorials\u2026<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>This guide shows how to use a microSD card with the ESP32: you&#8217;ll learn how to read and write files to the microSD card. To interface the microSD card with &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32: Guide for MicroSD Card Module using Arduino IDE\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-microsd-card-arduino\/#more-102290\" aria-label=\"Read more about ESP32: Guide for MicroSD Card Module using Arduino IDE\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":1,"featured_media":102346,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[281,276,277,299,264],"tags":[],"class_list":["post-102290","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32-project","category-esp32","category-esp32-arduino-ide","category-0-esp32","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2021\/02\/ESP32-Guide-microSD-Card-Module.jpg?fit=1280%2C720&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/102290","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=102290"}],"version-history":[{"count":3,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/102290\/revisions"}],"predecessor-version":[{"id":164168,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/102290\/revisions\/164168"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/102346"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=102290"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=102290"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=102290"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}