If you are adding local storage to an embedded project, connecting an SD card module to an Arduino via SPI is the most cost-effective route. However, the ubiquitous blue MicroSD adapter modules are notorious for failing on the workbench. The direct answer to getting it working on a 5V Arduino Uno R3 is to wire it to the hardware SPI pins (11, 12, 13), use Pin 10 for Chip Select, and power the module's VCC pin with 5V so the onboard logic level shifter and 3.3V LDO regulator can function correctly.
This guide breaks down the exact hardware variants, provides a robust datalogger sketch with error handling, and gives you a systematic debugging path for when the serial monitor inevitably throws a card initialization error.
MicroSD Module Variants & SPI Pin Mapping
Not all SD modules are created equal. The raw MicroSD card operates at 3.3V logic and 3.3V power. Feeding 5V logic from an ATmega328P (Arduino Uno) directly into a raw SD card will fry the card's internal controller. You must know which module variant you are holding.
| Module Variant | Logic Level Shifter | Onboard 3.3V Regulator | VCC Input Required | Typical Price (2026) |
|---|---|---|---|---|
| Catalexus / LC Studio (Blue) | Yes (LVC125A IC) | Yes (1117 3.3V LDO) | 4.5V - 5.5V | $1.50 - $3.00 |
| Raw MicroSD Breakout | No | No | 3.3V Strict | $2.00 - $4.00 |
| Adafruit MicroSD Breakout | Yes (Integrated IC) | Yes (3V-5V tolerant) | 3.3V or 5V | $9.95 |
| Datalogger Shield (e.g., Adafruit) | Yes | Yes | 5V (via Shield) | $15.00 - $25.00 |
Assuming you are using the most common Catalexus/LC Studio blue module with an Arduino Uno R3, here is the mandatory pin mapping. The Uno uses hardware SPI, meaning MISO, MOSI, and SCK are locked to specific pins.
| SD Module Pin | Arduino Uno R3 Pin | Function & Notes |
|---|---|---|
| GND | GND | Common ground reference. Mandatory. |
| VCC | 5V | Powers the onboard LDO and LVC125A level shifter. |
| MISO | Pin 12 | Master In Slave Out (Data from SD to Arduino). |
| MOSI | Pin 11 | Master Out Slave In (Data from Arduino to SD). |
| SCK | Pin 13 | Serial Clock (SPI timing signal). |
| CS | Pin 10 | Chip Select. Can be any digital pin, but 10 is standard for Uno. |
Step-by-Step Wiring & Preparation
- Format the SD Card Correctly: The standard Arduino
SD.hlibrary only supports FAT16 and FAT32 file systems. It does not support exFAT. If you are using a card larger than 32GB, it likely shipped formatted as exFAT. Use the official SD Memory Card Formatter from the SD Association to format cards up to 32GB as FAT32. For cards 64GB+, you will need a third-party tool like GUIFormat to force FAT32, or switch to theSdFatlibrary. - Connect Power and Ground: Wire the module's GND to the Arduino GND. Wire the module's VCC to the Arduino 5V pin. Do not wire VCC to 3.3V on the blue Catalexus module; the onboard 1117 LDO needs headroom to regulate down to 3.3V for the card, and the LVC125A chip needs 5V to properly translate the Uno's 5V logic down to 3.3V.
- Wire the SPI Bus: Connect MISO to 12, MOSI to 11, and SCK to 13. Keep these jumper wires under 10cm (4 inches). SPI is a high-frequency bus; long, unshielded jumper wires act as antennas and cause clock skew, resulting in initialization failures.
- Wire Chip Select (CS): Connect CS to Pin 10. If you have an Ethernet Shield (W5100) stacked on the Uno, the Ethernet shield uses Pin 10 for its own CS. In that case, move the SD module CS to Pin 4 and update your code accordingly.
Never power a raw SD card directly from the Arduino Uno's onboard 3.3V pin. The Uno's onboard 3.3V regulator (typically an LP2985) is only rated for ~150mA. During heavy write operations, an SD card can spike to 200mA+. This causes a brownout, corrupting the file system and crashing the microcontroller. Always use a module with its own dedicated 3.3V LDO fed by the 5V rail.
Complete Datalogger Code (Arduino Uno R3)
The following code targets the Arduino Uno R3. It uses the built-in SD.h and SPI.h libraries. Unlike basic example sketches, this implementation includes robust error handling, file flushing to prevent data corruption on power loss, and explicit SPI bus initialization.
#include <SPI.h>
#include <SD.h>
// Pin definitions for Arduino Uno R3
const int chipSelect = 10;
const int ledPin = 8; // Optional: visual indicator for write status
File dataFile;
unsigned long logCount = 0;
void setup() {
Serial.begin(9600);
while (!Serial) { ; } // Wait for serial port to connect (needed for native USB boards)
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
Serial.print("Initializing SD card...");
// Explicitly set hardware SS pin (10 on Uno) as OUTPUT
// This is required for the ATmega328P to remain in SPI Master mode
pinMode(10, OUTPUT);
digitalWrite(10, HIGH); // Deselect SD card initially
// Initialize the SD card
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// Halt execution - no point continuing without storage
while (1) {
digitalWrite(ledPin, HIGH);
delay(100);
digitalWrite(ledPin, LOW);
delay(100);
}
}
Serial.println("card initialized.");
}
void loop() {
// Generate sensor data (replace with actual sensor reads)
float voltage = analogRead(A0) * (5.0 / 1023.0);
// Open the file. Note: only one file can be open at a time in SD.h
dataFile = SD.open("datalog.txt", FILE_WRITE);
if (dataFile) {
digitalWrite(ledPin, HIGH); // Indicate writing
String logData = String(millis()) + "," + String(logCount) + "," + String(voltage);
dataFile.println(logData);
Serial.println(logData);
// CRITICAL: Flush the buffer to physical card to prevent corruption
dataFile.flush();
dataFile.close();
digitalWrite(ledPin, LOW);
logCount++;
} else {
Serial.println("error opening datalog.txt");
}
// Log every 2 seconds
delay(2000);
}
Debugging: Fixing "Card failed, or not present"
If your serial monitor outputs the exact string "Card failed, or not present" or "error opening datalog.txt", do not immediately assume the module is dead. SD initialization failures are rarely caused by broken hardware; they are almost always protocol or power violations.
The First Three Things to Check When It Fails
- Verify the File System Format: Pull the SD card and plug it into your PC. Check the properties. If it says exFAT or NTFS, the Arduino cannot read it. Reformat to FAT32. If the card is 64GB or larger, Windows will refuse to format it as FAT32 natively. Use a tool like FAT32 Format (GUIFormat) to force the correct cluster size (typically 32KB clusters for cards between 8GB and 32GB).
- Measure the VCC and Logic Voltages: Grab your multimeter. Probe the module's VCC pin relative to GND while the Arduino is powered. It should read ~4.8V to 5.1V. Next, probe the MISO pin during an initialization attempt. If you don't see the 5V logic pulsing from the Arduino, check your jumper wires for continuity. Cheap Dupont wires frequently have internal breaks or loose crimps.
- Check for SPI Bus Contention: If you have other SPI devices wired to the bus (like an NRF24L01 radio or an RC522 RFID reader), their Chip Select (CS) lines must be set to
HIGH(deselected) in yoursetup()function before callingSD.begin(). If another device is holding the MISO line low, the SD card cannot send its initialization response back to the Uno.
Ranked Causes for Persistent Failures
| Root Cause | Symptom / Behavior | Fix / Workaround |
|---|---|---|
| Wire Length / Signal Integrity | Initializes sometimes, fails others. Works on desk, fails in enclosure. | Reduce SPI wire length to <10cm. Add SD.begin(chipSelect, SPI_HALF_SPEED) to lower the clock rate. |
| Fried Level Shifter | Module gets unusually hot. MISO line is stuck HIGH or LOW. | Replace module. You likely fed 5V into a raw 3.3V breakout or shorted VCC to MOSI. |
| Filename Constraints | SD.begin() succeeds, but SD.open() fails. |
FAT32 via SD.h requires 8.3 filenames. Change "sensor_data_log.txt" to "datalog.txt". |
| Card Incompatibility | Fails on brand new, high-endurance SanDisk/Samsung cards. | Some modern UHS-II/UHS-III cards fail to step down to legacy SPI speeds. Use an older Class 10 SDHC card. |
Extending and Simplifying Your SD Build
Once you have the basic datalogger running, you will eventually hit the limitations of the standard SD.h library. Here is how to scale your project up or strip it down based on your end goal.
How to Extend: Upgrading to SdFat
The standard SD.h library is essentially a wrapper around an older, stripped-down version of Bill Greiman's SdFat library. If your project requires logging to 64GB+ exFAT cards, writing high-speed burst data (like audio sampling), or managing multiple directories, you must switch to the native SdFat library.
When using SdFat, you gain access to SPI clock dividers. If your wires are slightly too long and you are experiencing intermittent dropouts, initializing the card at half-speed solves 90% of signal integrity issues without requiring you to re-solder your harness:
// SdFat specific initialization for long wires
if (!sd.begin(chipSelect, SPI_HALF_SPEED)) {
sd.initErrorHalt();
}
How to Simplify: Ditch the Level Shifter
If you are designing a custom PCB or moving past the prototyping phase, the Catalexus module's LVC125A level shifter and 1117 LDO add unnecessary quiescent current draw (often 5-10mA just sitting idle) and board space.
To simplify the hardware, switch to a native 3.3V microcontroller. Boards like the Arduino Nano 33 IoT, ESP32-WROOM-32, or Raspberry Pi Pico output 3.3V logic natively. With a 3.3V MCU, you can wire a raw MicroSD breakout (or just the bare SD card socket) directly to the SPI pins without any logic translation. You only need to ensure your 3.3V power rail can supply the 200mA write-spike current, which is easily handled by a dedicated AMS1117-3.3 voltage regulator on your custom PCB.
By matching your microcontroller's native logic level to the SD card's 3.3V requirement, you eliminate the most common point of failure in Arduino SD projects: the 5V-to-3.3V translation layer.






