Logging sensor data, storing configuration files, or buffering audio requires reliable non-volatile storage. The micro SD card module for Arduino connects via the SPI bus to provide gigabytes of FAT32 storage for a few dollars. However, the most common point of failure in these builds isn't the code—it's the hardware interface. Mixing 5V logic from an Arduino Uno with the 3.3V requirements of an SD card without proper level shifting will silently corrupt data or permanently brick your card.
This guide targets the Arduino Uno R3 (ATmega328P) using the standard SD.h library. We will cover exact hardware specs, provide a complete compilable datalogging sketch with error handling, and break down the exact error strings you will encounter when things go wrong.
Hardware Specs & SPI Pin Mapping
Not all SD modules are created equal. The generic blue modules found in starter kits often lack proper logic level shifting, while premium breakouts handle voltage translation onboard. Here is the data-dense breakdown of the most common modules on the bench in 2026.
| Module Variant | VCC Input | Logic Level Shifting | Max SPI Speed | Best Use Case |
|---|---|---|---|---|
| Generic Blue (LC Studio) | 5V (via AMS1117 LDO) | None (Direct 5V to 3.3V pins) | ~12 MHz | 3.3V boards only (ESP32/Teensy) or use external level shifter |
| Adafruit 254 Breakout | 3.3V to 5V | Yes (MOSFET-based) | 24 MHz | 5V boards (Uno/Mega) without extra wiring |
| SparkFun DEV-15107 | 3.3V to 6V | Yes (TXB0104 transceiver) | 24 MHz | High-speed datalogging on mixed-voltage systems |
Note: If you are using the generic blue module with a 5V Arduino Uno, you must wire the SPI data lines through a 4-channel logic level converter (like a BSS138 bi-directional board, ~$1.50) to step the 5V signals down to 3.3V.
SPI Pin Mapping by Board
The SPI bus uses four shared lines, but the Chip Select (CS) pin can be any digital pin, provided you define it in your code. Below is the standard hardware SPI mapping.
| Signal | Arduino Uno R3 | Arduino Mega 2560 | ESP32 DevKit V1 |
|---|---|---|---|
| VCC | 5V (or 3.3V depending on module) | 5V (or 3.3V depending on module) | 3.3V |
| GND | GND | GND | GND |
| MISO (DO) | Pin 12 | Pin 50 | Pin 19 (GPIO 19) |
| MOSI (DI) | Pin 11 | Pin 51 | Pin 23 (GPIO 23) |
| SCK (CLK) | Pin 13 | Pin 52 | Pin 18 (GPIO 18) |
| CS (SS) | Pin 10 (Default) | Pin 53 (Default) | Pin 5 (GPIO 5, Default) |
Parts List & Wiring Steps
Crucial Prep: Format your SD card to FAT32 with an MBR (Master Boot Record) partition scheme using the official SD Memory Card Formatter. Standard
SD.h does not support exFAT (64GB+ SDXC cards) or GPT partitions.
Required Components
- Microcontroller: Arduino Uno R3 (or compatible clone)
- SD Module: Adafruit MicroSD Breakout Board (Part #254) - ~$7.50 (Recommended for 5V safety)
- SD Card: SanDisk Ultra 16GB or 32GB microSDHC (Class 10) - ~$8.00
- Wiring: 6x Male-to-Male jumper wires
- Logic Shifter: 4-channel I2C/SPI level converter (Only if using the generic blue module)
Numbered Wiring Procedure (Uno R3 to Adafruit 254)
- De-energize: Ensure the Arduino is unplugged from USB or external power.
- Power: Connect the module's
5Vpin to the Uno's5Vpin. ConnectGNDtoGND. (The Adafruit module regulates this down to 3.3V internally). - Clock: Wire Uno Pin
13(SCK) to the module'sCLKpin. - Data Out: Wire Uno Pin
12(MISO) to the module'sDOpin. - Data In: Wire Uno Pin
11(MOSI) to the module'sDIpin. - Chip Select: Wire Uno Pin
10to the module'sCSpin. - Verify: Tug gently on all jumper wires to ensure solid friction fit before applying power.
Complete Arduino Code for Uno R3
This sketch initializes the SD card, creates a CSV file, and logs analog sensor data from pin A0 every 2 seconds. It includes robust error handling to catch initialization and file-writing failures without silently hanging.
#include <SPI.h>
#include <SD.h>
// Target: Arduino Uno R3
const int chipSelect = 10;
File dataFile;
void setup() {
Serial.begin(9600);
// Wait for serial port to connect. Needed for native USB boards.
while (!Serial) { ; }
Serial.print("Initializing SD card...");
// SD.begin() sets the CS pin to output and initializes the SPI bus
if (!SD.begin(chipSelect)) {
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 chipSelect pin to match your shield or module?");
// Halt execution to prevent infinite serial spam
while (1);
}
Serial.println("initialization done.");
// Open or create the file and write a CSV header
dataFile = SD.open("datalog.txt", FILE_WRITE);
if (dataFile) {
dataFile.println("Timestamp_ms, SensorValue_A0");
dataFile.close();
Serial.println("Header written successfully.");
} else {
Serial.println("error opening datalog.txt");
}
}
void loop() {
// Open the file in append mode
dataFile = SD.open("datalog.txt", FILE_WRITE);
if (dataFile) {
int sensorValue = analogRead(A0);
unsigned long timeStamp = millis();
dataFile.print(timeStamp);
dataFile.print(", ");
dataFile.println(sensorValue);
dataFile.close(); // Always close to flush the buffer and update the FAT table
Serial.print("Logged: ");
Serial.println(sensorValue);
} else {
Serial.println("error opening datalog.txt");
}
delay(2000); // Log every 2 seconds
}
Debugging: Fixing "initialization failed" & Common Errors
When working with the SD card module for Arduino, the serial monitor will throw specific error strings when the SPI handshake or FAT table parsing fails. Here is the exact troubleshooting decision path.
- File System Format: Is the card formatted to FAT32 with an MBR partition? (SDXC 64GB+ cards default to exFAT, which
SD.hcannot read). - Chip Select (CS) Pin: Is the physical wire connected to Pin 10, and does your code declare
const int chipSelect = 10;? (If using an Ethernet shield sharing the SPI bus, CS conflicts are common). - Logic Voltage: Are you feeding 5V logic directly into a 3.3V SD card without a level shifter? If so, the card's internal controller may have locked up or burned out.
Ranked Causes by Exact Error String
Error 1: initialization failed. Things to check:
- Cause A (Most Likely): The card is formatted as exFAT or NTFS. Reformat using the official SD Association tool linked above.
- Cause B: The CS pin is wired to the wrong digital pin, or Pin 10 is not set as an
OUTPUTin the background (theSD.hlibrary handles this, but if you manipulate Pin 10 manually elsewhere in your code beforeSD.begin(), it will break the SPI hardware SS line). - Cause C: The SD card is pushed in slightly crooked, failing to make contact with the internal leaf springs.
Error 2: error opening datalog.txt
- Cause A: The file name exceeds the 8.3 character limit of the standard
SD.hlibrary. "datalog.txt" is fine, but "my_sensor_data_2026.txt" will fail. Usedata.txt. - Cause B: The root directory is full. FAT32 limits the number of files in the root directory. Move existing files into a subfolder.
- Cause C: The card was pulled without closing the file previously, corrupting the FAT table. Run a disk repair utility (chkdsk /f on Windows) or reformat.
Error 3: card.init failed (When using the advanced SdFat library)
- Cause A: SPI clock speed is too high for the breadboard capacitance. Add
SdSpiConfig(chipSelect, DEDICATED_SPI, SD_SCK_MHZ(4))to drop the bus speed to 4 MHz. - Cause B: Missing pull-up resistor. Some SD cards require a 10kΩ pull-up on the MISO line to stabilize the bus when multiple SPI devices are present.
Extending and Simplifying the Build
How to Extend: Adding Real-Time Timestamps
The millis() function resets every time the Arduino loses power. To log actual dates and times, add a DS3231 RTC (Real Time Clock) module. The DS3231 communicates via I2C (Pins A4/A5 on the Uno). Because I2C and SPI use entirely different hardware buses, you can wire the RTC and the SD card module simultaneously without bus conflicts. Use the RTClib and SD.h libraries together to prepend ISO-8601 timestamps to your CSV rows.
How to Simplify: Migrating to ESP32
If you are tired of managing 5V-to-3.3V logic level shifters and slow SPI bit-banging, migrate your datalogger to an ESP32 DevKit V1. The ESP32 operates natively at 3.3V, meaning you can wire the cheap generic blue SD module directly without frying the card. Furthermore, the ESP32 features a native SDMMC host controller. By wiring the SD card to the ESP32's dedicated SDMMC pins (GPIO 2, 4, 12, 13, 14, 15), you bypass the SPI bus entirely, achieving write speeds up to 20 MB/s—fast enough for WAV audio recording or high-speed oscilloscope buffering, which the Arduino Uno's SPI bus simply cannot handle.






