Comprehensive Guide to ESP32 SD Card File Operations
1. Hardware Connection and Configuration
Hardware Requirements
- ESP32 Development Board
- Micro SD Card Module (SPI Interface)
- Micro SD Card (Recommended 4GB-32GB, FAT32 format)
- Several Dupont Wires
Wiring Diagram
SD Card Module → ESP32 Pins
------------------
CS → GPIO5 (customizable)
SCK → GPIO18
MOSI → GPIO23
MISO → GPIO19
VCC → 5V/VIN (requires 5V power)
GND → GND
Note: Some SD card modules use 3.3V logic levels, please check the module specifications.
2. Library Installation and Initialization
Library Installation
Arduino IDE Operations:
- Tools > Manage Libraries
- Search and install SD (built-in library)
- Optional installation of SdFat (for advanced features)
Initialization Code
#include<SPI.h>
#include<SD.h>
const int chipSelect = 5; // CS pin
void setup() {
Serial.begin(115200);
// Initialize SD card
if (!SD.begin(chipSelect)) {
Serial.println("SD card initialization failed");
while (1); // Stop execution
}
Serial.println("SD card initialized successfully");
// Print card information
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD card capacity: %lluMB\n", cardSize);
}
3. Basic File Operations
1. Create/Write File
void writeFile(const char* path, const char* message) {
// Open file (write mode)
File file = SD.open(path, FILE_WRITE);
if (file) {
file.println(message); // Write data
file.close(); // Must close file
Serial.println("Write successful");
} else {
Serial.println("Failed to open file");
}
}
2. Read File Content
void readFile(const char* path) {
File file = SD.open(path);
if (file) {
Serial.printf("File content [%s]:\n", path);
while (file.available()) {
Serial.write(file.read());
}
file.close();
} else {
Serial.println("Failed to open file");
}
}
3. Create Directory
bool createDir(const char* path) {
if (SD.mkdir(path)) {
Serial.println("Directory created successfully");
return true;
} else {
Serial.println("Failed to create directory");
return false;
}
}
4. Advanced File Operations
1. List Directory Traversal
void listDir(const char* dirname) {
Serial.printf("Listing directory: %s\n", dirname);
File root = SD.open(dirname);
if (!root) {
Serial.println("Failed to open directory");
return;
}
if (!root.isDirectory()) {
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
Serial.print(" DIR : ");
Serial.println(file.name());
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
2. File System Operations
void fileSystemOperations() {
// Check if file exists
Serial.printf("Does test.txt exist? %s\n", SD.exists("/test.txt") ? "Yes" : "No");
// Rename file
if (SD.rename("/old.txt", "/new.txt")) {
Serial.println("Rename successful");
}
// Delete file
if (SD.remove("/unneeded.txt")) {
Serial.println("Delete successful");
}
}
5. Data Logging Applications
Sensor Data Logging
#include<DHT.h>
#define DHTPIN 25
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
void logSensorData() {
float temp = dht.readTemperature();
float hum = dht.readHumidity();
File dataFile = SD.open("/sensor.log", FILE_APPEND);
if (dataFile) {
String dataLine = getTimestamp() + "," +
String(temp) + "," +
String(hum);
dataFile.println(dataLine);
dataFile.close();
}
}
String getTimestamp() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
return "2023-01-01 00:00:00";
}
char buffer[20];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &timeinfo);
return String(buffer);
}
CSV File Processing
void processCSV(const char* filename) {
File file = SD.open(filename);
if (!file) return;
Serial.println("CSV content analysis:");
while (file.available()) {
String line = file.readStringUntil('\n');
int firstComma = line.indexOf(',');
String date = line.substring(0, firstComma);
String temperature = line.substring(firstComma + 1);
Serial.printf("Date: %s, Temperature: %s°C\n", date.c_str(), temperature.c_str());
}
file.close();
}
6. Performance Optimization Techniques
1. Buffered Writing
#define BUF_SIZE 512
char buffer[BUF_SIZE];
int bufIndex = 0;
void bufferedWrite(File file, const char* data) {
int len = strlen(data);
// Write when buffer is full
if (bufIndex + len >= BUF_SIZE) {
file.write((uint8_t*)buffer, bufIndex);
bufIndex = 0;
}
// Add data to buffer
memcpy(buffer + bufIndex, data, len);
bufIndex += len;
}
void flushBuffer(File file) {
if (bufIndex > 0) {
file.write((uint8_t*)buffer, bufIndex);
bufIndex = 0;
}
}
2. File Operation Frequency Control
const int LOG_INTERVAL = 5000; // 5 seconds
unsigned long lastLogTime = 0;
void loop() {
if (millis() - lastLogTime > LOG_INTERVAL) {
logSensorData();
lastLogTime = millis();
}
}
7. Error Handling and Recovery
1. Error Detection and Recovery
void safeWrite(const char* path, const char* data) {
// Attempt to write 3 times
for (int i = 0; i < 3; i++) {
if (writeFileWithRetry(path, data)) {
return;
}
delay(100 * (i + 1)); // Exponential backoff
}
Serial.println("Fatal error: Data write failed");
ESP.restart(); // Restart system
}
bool writeFileWithRetry(const char* path, const char* data) {
File file = SD.open(path, FILE_WRITE);
if (!file) return false;
size_t bytesWritten = file.print(data);
file.close();
return bytesWritten == strlen(data);
}
2. File System Health Check
void checkFileSystem() {
// Check available space
uint64_t freeSpace = SD.totalBytes() - SD.usedBytes();
Serial.printf("Available space: %lluMB\n", freeSpace / (1024 * 1024));
// Check error counter
uint32_t errorCount = 0;
if (SD.card()->errorCode()) {
Serial.printf("SD card error: %d\n", SD.card()->errorCode());
errorCount++;
}
if (errorCount > 10) {
Serial.println("Warning: Frequent SD card failures");
}
}
8. Advanced Applications: Web Server File Management
File Download Server
#include<WiFi.h>
#include<WebServer.h>
WebServer server(80);
void setupWebServer() {
// ...WiFi connection settings...
server.on("/download", HTTP_GET, handleDownload);
server.begin();
}
void handleDownload() {
String path = server.arg("file");
if (SD.exists(path.c_str())) {
File file = SD.open(path.c_str());
server.streamFile(file, "application/octet-stream");
file.close();
} else {
server.send(404, "text/plain", "File not found");
}
}
void listFilesWeb() {
String json = "[";
File root = SD.open("/");
File file = root.openNextFile();
while (file) {
if (json != "[") json += ",";
json += "{\"name\":\"" + String(file.name()) + "\",";
json += "\"size\":" + String(file.size()) + "}";
file = root.openNextFile();
}
json += "]";
server.send(200, "application/json", json);
}
OTA Firmware Update
void updateFirmware() {
File firmware = SD.open("/firmware.bin");
if (!firmware) return;
size_t fileSize = firmware.size();
if (Update.begin(fileSize)) {
size_t written = Update.writeStream(firmware);
if (written == fileSize) {
if (Update.end()) {
Serial.println("Firmware update successful, restarting...");
ESP.restart();
} else {
Serial.println("Firmware update error");
}
} else {
Serial.println("Incomplete file write");
}
}
firmware.close();
}
9. Best Practices Summary
-
File System Maintenance
- Regularly run
<span>SD.remove()</span>to delete temporary files - Use defragmentation tools to optimize the SD card
- Keep at least 20% of available space
Error Handling
// Check return values of all file operations
File file = SD.open("data.log", FILE_APPEND);
if (!file) {
Serial.println("Unable to open file");
// Error handling logic
}
Log Management
- Use date-named log files (/logs/2023-08-15.log)
- Implement log rotation
- Compress old logs to save space
Low Power Optimization
void disableSD() {
pinMode(chipSelect, INPUT); // Disable CS
digitalWrite(SCK, LOW); // Stop clock
}
Safety Considerations
- Avoid prolonged writes to prevent overheating
- Use UPS or battery backup power
- Protect file integrity during unexpected power outages
By applying these techniques appropriately, the ESP32 can efficiently and reliably perform file storage tasks, meeting various application needs from simple data logging to complex file management.
ESP32 IoT GuideThree Days to Master MicrocontrollersArduino Development Board