Every serious Arduino data logging project eventually needs a place to store measurements permanently. Keeping data in RAM loses it when power is cut. Sending data over serial only works when a computer is connected. The Arduino’s internal EEPROM holds only 1KB and has a limited write cycle life. The solution that checks all the boxes is a microSD card module — cheap, widely available, holds gigabytes of data, and retains everything without power.
The Arduino SD library (built into the Arduino IDE) provides a clean interface for reading and writing files on FAT16 and FAT32 formatted SD cards. Combined with a simple SPI SD card breakout module, you can log temperature readings, GPS coordinates, sensor arrays, or any other data to timestamped CSV files that open directly in Excel or Google Sheets.
This guide covers everything: choosing the right SD card module, correct wiring (including the critical 3.3V level shifting), file operations with the SD library, practical data logging sketches, and debugging techniques for when the SD card refuses to initialise.
SD Card Modules: Types and Selection
Several types of SD card adapters exist for Arduino projects. Here is what to know before buying:
SPI SD Card Breakout Modules
The most common type is a small PCB with a microSD card slot, an SPI interface, and a built-in 3.3V voltage regulator and level-shifting circuit. These modules accept 5V from Arduino Uno while safely delivering 3.3V to the SD card (SD cards are 3.3V devices that are NOT 5V tolerant). This is the module type recommended for Arduino Uno/Nano projects.
Bare SD Card Adapters (No Level Shifting)
Some breakout modules (particularly very cheap ones) have no level shifting and connect the SD card SPI lines directly at 5V. These work unreliably at 5V and risk damaging the SD card over time. Always check your module’s datasheet or description for level-shifting or 3.3V operation.
Shields with Onboard SD
Many Arduino shields include an onboard SD card slot — the Arduino Ethernet Shield, various data logging shields, and display shields. These typically use SPI with CS on pin 4 or pin 10 and include proper level shifting. Check the documentation for your specific shield.
For new builds, a dedicated SPI SD breakout module with onboard level shifting (the kind with 6 pins: VCC, GND, MISO, MOSI, SCK, CS) is the most flexible and reliable option.
Wiring the SD Card Module to Arduino
SD cards communicate over SPI. The Arduino Uno’s hardware SPI pins are:
- MISO: Pin 12 (Master In, Slave Out — data from SD card)
- MOSI: Pin 11 (Master Out, Slave In — data to SD card)
- SCK: Pin 13 (SPI clock)
- CS: Pin 4 or 10 (Chip Select — choose any digital pin)
| SD Module Pin | Arduino Uno Pin | Notes |
|---|---|---|
| VCC | 5V | Module regulates to 3.3V internally |
| GND | GND | Common ground |
| MISO | Pin 12 | Hardware SPI MISO |
| MOSI | Pin 11 | Hardware SPI MOSI |
| SCK | Pin 13 | Hardware SPI clock |
| CS | Pin 10 | Chip Select (configurable) |
Important: if you use Pin 10 as CS but you are not using it as the hardware SS pin for the SPI bus, you must still configure it as OUTPUT in your sketch. The Arduino SPI library requires Pin 10 to be an OUTPUT, even if you are using a different pin as CS for the SD card.
3.3V Arduino Boards (Nano 33 IoT, etc.)
If using a 3.3V Arduino, supply the SD module’s VCC from the 3.3V pin. Some SD modules with 5V-only regulators will not work from 3.3V — check your module’s voltage range. For bare microSD adapters with no regulation, direct 3.3V operation works and no level shifting is needed since the Arduino SPI pins are already at 3.3V logic.
Formatting the SD Card Correctly
The Arduino SD library supports FAT16 and FAT32 file systems. For maximum compatibility:
- Cards 2GB and under: Format as FAT16 (or FAT32 both work)
- Cards 4GB–32GB: Format as FAT32
- Cards over 32GB: NOT supported by the standard SD library (exFAT requires the SdFat library)
Use the SD Association’s SD Memory Card Formatter tool (free download from sdcard.org) rather than Windows’ built-in formatter. The official tool writes the correct partition table layout that SD cards expect. Windows can create FAT32 partitions that technically work but have suboptimal cluster sizes that slow down SD card performance.
After formatting, the SD card should appear empty and have no hidden partitions or recovery data. A 32GB card formatted FAT32 with the official tool will initialise reliably with the Arduino SD library.
Basic File Operations with the SD Library
The Arduino SD library (included with the IDE) provides a simple file I/O interface. Here are the core operations:
Initialise the SD Card
#include <SPI.h>
#include <SD.h>
const int chipSelect = 10;
void setup() {
Serial.begin(9600);
Serial.print("Initialising SD card...");
if (!SD.begin(chipSelect)) {
Serial.println("FAILED! Check wiring and card.");
while (true); // halt
}
Serial.println("SD card ready.");
}
Write to a File
void writeData(String data) {
File dataFile = SD.open("data.txt", FILE_WRITE);
if (dataFile) {
dataFile.println(data);
dataFile.close(); // Always close the file!
} else {
Serial.println("Error opening file");
}
}
Read from a File
void readFile(const char* filename) {
File dataFile = SD.open(filename);
if (dataFile) {
while (dataFile.available()) {
Serial.write(dataFile.read());
}
dataFile.close();
} else {
Serial.println("Error opening file");
}
}
Check File Existence and Delete
// Check if file exists
if (SD.exists("config.txt")) {
Serial.println("Config file found");
}
// Delete a file
if (SD.remove("old_data.txt")) {
Serial.println("File deleted");
}
// Create a directory
SD.mkdir("logs");
// Open file in subdirectory
File f = SD.open("logs/sensor.csv", FILE_WRITE);
Critical rule: Always call dataFile.close() after writing. The SD library buffers writes in RAM. If you do not close the file, those buffered bytes may not be flushed to the card. In event of power loss with an unclosed file, data will be lost or the file will be corrupted.
Building a Data Logger
Here is a complete, production-ready data logger that reads temperature from a DHT11 sensor and logs it to a CSV file on the SD card every 30 seconds:
#include <SPI.h>
#include <SD.h>
#include <DHT.h>
#define DHTPIN 7
#define DHTTYPE DHT11
#define CS_PIN 10
#define LOG_INTERVAL 30000 // 30 seconds in ms
DHT dht(DHTPIN, DHTTYPE);
const char* LOGFILE = "SENSOR.CSV";
unsigned long lastLog = 0;
void setup() {
Serial.begin(9600);
dht.begin();
if (!SD.begin(CS_PIN)) {
Serial.println("SD init failed!");
while (true);
}
// Write CSV header if file doesn't exist
if (!SD.exists(LOGFILE)) {
File f = SD.open(LOGFILE, FILE_WRITE);
if (f) {
f.println("Millis,Temp_C,Humidity_%");
f.close();
}
}
Serial.println("Logger ready.");
}
void loop() {
unsigned long now = millis();
if (now - lastLog >= LOG_INTERVAL) {
lastLog = now;
float temp = dht.readTemperature();
float hum = dht.readHumidity();
if (!isnan(temp) && !isnan(hum)) {
File f = SD.open(LOGFILE, FILE_WRITE);
if (f) {
f.print(now);
f.print(',');
f.print(temp, 1);
f.print(',');
f.println(hum, 1);
f.close();
Serial.print("Logged: ");
Serial.print(temp);
Serial.println(" C");
}
} else {
Serial.println("Sensor read error");
}
}
}
Advanced Techniques: Timestamps and Multiple Files
Adding Real-Time Timestamps with DS3231
The millis() counter resets to zero every time the Arduino powers on, making it useless for timestamps spanning multiple sessions. Pair your SD logger with a DS3231 RTC module (I2C, uses A4/A5 on Uno) to get real date-time stamps:
#include <RTClib.h>
RTC_DS3231 rtc;
// In loop(), get timestamp:
DateTime now = rtc.now();
char buf[20];
snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d",
now.year(), now.month(), now.day(),
now.hour(), now.minute(), now.second());
f.print(buf);
Daily Log Files
For long-running loggers, create a new file each day named by date. This keeps individual files manageable in size:
char filename[13];
snprintf(filename, sizeof(filename), "%02d%02d%02d.CSV",
now.year() % 100, now.month(), now.day());
// Produces filenames like: 260311.CSV
Using the SdFat Library for Better Performance
The built-in SD library is convenient but limited. The SdFat library by William Greiman offers significantly better performance (faster write speeds), support for exFAT and large SD cards, and more advanced features. Swap #include <SD.h> for #include <SdFat.h> and adjust method names slightly.
Troubleshooting SD Card Initialisation
“SD card initialisation failed” is the most common error message in SD card projects. Here is a systematic approach to fixing it:
Check Power
SD cards can draw 100–150 mA during write operations. If powering the SD module from the Arduino’s 3.3V or 5V pins while also running other peripherals, the power rail may droop during SD writes, causing initialisation failures. Add a 100 µF electrolytic capacitor across VCC and GND on the SD module.
Check CS Pin
Make sure the CS pin you specify in SD.begin(chipSelect) matches the physical wiring. The chip cannot initialise if the wrong pin is pulled LOW for selection.
Check SPI Conflicts
If you have other SPI devices (TFT display, Ethernet, etc.), ensure only one CS pin is LOW at a time. All other SPI devices must have their CS pins HIGH when initialising or communicating with the SD card.
Check Card Format
Cards over 32GB formatted as exFAT will fail with the standard SD library. Reformat as FAT32 using the official SD formatter tool.
Check Card Speed
Some SDXC cards and modern high-speed cards may not reliably initialise at the SD library’s default clock speed. The SdFat library has a SD_SCK_MHZ(4) option to reduce the SPI clock, which helps with problematic cards.
Minimal Test Sketch
When debugging, reduce to the absolute minimum: just SD.begin() with Serial output. Remove all other libraries and hardware. Confirm the card initialises in isolation before adding more complexity.
Frequently Asked Questions
What is the maximum SD card size the Arduino SD library supports?
The standard SD library (Arduino IDE built-in) supports FAT16 cards up to 2GB and FAT32 cards up to 32GB. Cards larger than 32GB use exFAT and require the SdFat library with exFAT support enabled. For most data logging applications, a 4GB or 8GB FAT32 card holds years of CSV data.
Can I use the SD card and SPI display at the same time?
Yes. Both SPI devices share the MISO, MOSI, and SCK lines but each has its own dedicated CS pin. Only one device’s CS should be LOW at any time. Make sure to set the display’s CS HIGH before starting SD operations, and vice versa. The SPI bus is shared but access is arbitrated by the CS signals.
Why does my file always start from the beginning instead of appending?
Using SD.open(filename, FILE_WRITE) opens in append mode by default in the Arduino SD library — it does NOT overwrite. If your file appears to restart, check that you are not calling SD.remove() before writing, or that the filename is correct and a previous file did not get corrupted.
How fast can the Arduino write to the SD card?
Writing short lines of text every 30–60 seconds has no speed constraints at all. For continuous logging (like audio sampling or accelerometer data), the SPI SD write speed is typically 200–500 KB/s in practical Arduino sketches. Audio at 8-bit/8 kHz (8 KB/s) is easily achievable; high-resolution audio requires the SdFat library and tight timing.
The SD card works fine at first, then stops mid-session. Why?
This usually means the file was not properly closed after a previous write session. Power loss without a file.close() call corrupts the FAT directory entry. The card appears unreadable until the next SD.begin() re-reads the directory. Use the SdFat library’s sync() function to flush data without closing the file, providing crash protection for continuous logging applications.
Conclusion
The Arduino SD card module, paired with the FAT SD library, is the most practical solution for persistent data storage in embedded projects. With correct wiring (always using a module with 3.3V level shifting), proper FAT32 formatting, and disciplined file management (always close files after writing), you can build reliable data loggers that capture months of sensor data to files that open directly in Excel.
Ready to build your data logging project? Find all the Arduino boards, sensors, and modules you need at Zbotic’s Arduino & Microcontrollers store — quality electronics delivered across India at competitive prices.
Add comment