From 8994fe8e52c9004288a419e8c13a50cb4eca46ca Mon Sep 17 00:00:00 2001 From: byun Date: Sun, 28 Dec 2025 20:53:42 +0000 Subject: [PATCH] =?UTF-8?q?sd=20card=20sdio=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ESP32_CAN_Logger-a.ino | 85 ++++++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/ESP32_CAN_Logger-a.ino b/ESP32_CAN_Logger-a.ino index d2c542f..4334721 100644 --- a/ESP32_CAN_Logger-a.ino +++ b/ESP32_CAN_Logger-a.ino @@ -18,7 +18,7 @@ #include #include #include -#include +#include // ⭐ SDIO 4-bit #include #include #include @@ -55,11 +55,14 @@ #define HSPI_SCLK 12 #define HSPI_CS 10 -// VSPI 핀 (SD Card) -#define VSPI_MISO 41 -#define VSPI_MOSI 40 -#define VSPI_SCLK 39 -#define VSPI_CS 42 +// ⭐⭐⭐ SDIO 4-bit Pins (ESP32-S3) +// CLK: GPIO39, CMD: GPIO38, D0-D3: GPIO40,41,42,21 +#define SDIO_CLK 39 +#define SDIO_CMD 38 +#define SDIO_D0 40 +#define SDIO_D1 41 +#define SDIO_D2 42 +#define SDIO_D3 21 // ⭐ OPI PSRAM 호환 // I2C2 핀 (RTC DS3231) #define RTC_SDA 8 @@ -216,7 +219,7 @@ SerialSettings serial2Settings = {115200, 8, 0, 1}; // ⭐ Serial2 추가 // 전역 객체 (내부 SRAM) SPIClass hspi(HSPI); -SPIClass vspi(FSPI); +// SPIClass vspi(FSPI); // ⭐ SDIO 사용으로 제거 MCP2515 mcp2515(HSPI_CS, 20000000, &hspi); HardwareSerial SerialComm(1); // UART1 HardwareSerial Serial2Comm(2); // ⭐ UART2 추가 @@ -1007,7 +1010,7 @@ void sdWriteTask(void *parameter) { // ⭐⭐⭐ 500개마다 파일 재오픈 (핵심!) if (++csvReopenCounter >= 500) { logFile.close(); - logFile = SD.open(currentFilename, FILE_APPEND); + logFile = SD_MMC.open(currentFilename, FILE_APPEND); if (logFile) { Serial.printf("✓ CSV 파일 재오픈: %s (%lu bytes)\n", currentFilename, currentFileSize); } else { @@ -1061,7 +1064,7 @@ void sdWriteTask(void *parameter) { // 파일 닫고 다시 열기 logFile.close(); - logFile = SD.open(currentFilename, FILE_APPEND); + logFile = SD_MMC.open(currentFilename, FILE_APPEND); if (logFile) { Serial.printf("✓ BIN 파일 재오픈: %s (%lu bytes)\n", currentFilename, currentFileSize); } else { @@ -1123,7 +1126,7 @@ void sdMonitorTask(void *parameter) { void saveFileComments() { if (!sdCardReady) return; if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) { - File commentFile = SD.open("/comments.dat", FILE_WRITE); + File commentFile = SD_MMC.open("/comments.dat", FILE_WRITE); if (commentFile) { commentFile.write((uint8_t*)&commentCount, sizeof(commentCount)); commentFile.write((uint8_t*)fileComments, sizeof(FileComment) * commentCount); @@ -1136,8 +1139,8 @@ void saveFileComments() { void loadFileComments() { if (!sdCardReady) return; if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) { - if (SD.exists("/comments.dat")) { - File commentFile = SD.open("/comments.dat", FILE_READ); + if (SD_MMC.exists("/comments.dat")) { + File commentFile = SD_MMC.open("/comments.dat", FILE_READ); if (commentFile) { commentFile.read((uint8_t*)&commentCount, sizeof(commentCount)); if (commentCount > MAX_FILE_COMMENTS) commentCount = MAX_FILE_COMMENTS; @@ -1184,7 +1187,7 @@ void addFileComment(const char* filename, const char* comment) { void saveSequences() { if (!sdCardReady) return; if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) { - File seqFile = SD.open("/sequences.dat", FILE_WRITE); + File seqFile = SD_MMC.open("/sequences.dat", FILE_WRITE); if (seqFile) { seqFile.write((uint8_t*)&sequenceCount, sizeof(sequenceCount)); seqFile.write((uint8_t*)sequences, sizeof(CANSequence) * sequenceCount); @@ -1197,8 +1200,8 @@ void saveSequences() { void loadSequences() { if (!sdCardReady) return; if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) { - if (SD.exists("/sequences.dat")) { - File seqFile = SD.open("/sequences.dat", FILE_READ); + if (SD_MMC.exists("/sequences.dat")) { + File seqFile = SD_MMC.open("/sequences.dat", FILE_READ); if (seqFile) { seqFile.read((uint8_t*)&sequenceCount, sizeof(sequenceCount)); if (sequenceCount > MAX_SEQUENCES) sequenceCount = MAX_SEQUENCES; @@ -1406,7 +1409,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, ext); // ⭐⭐⭐ 파일 생성 (헤더 쓰기) - logFile = SD.open(currentFilename, FILE_WRITE); + logFile = SD_MMC.open(currentFilename, FILE_WRITE); if (logFile) { if (canLogFormatCSV) { @@ -1416,7 +1419,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) logFile.close(); // ⭐ 헤더 쓰고 닫기 // ⭐⭐⭐ APPEND 모드로 다시 열기 - logFile = SD.open(currentFilename, FILE_APPEND); + logFile = SD_MMC.open(currentFilename, FILE_APPEND); if (logFile) { loggingEnabled = true; @@ -1498,7 +1501,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, ext); - serialLogFile = SD.open(currentSerialFilename, FILE_WRITE); + serialLogFile = SD_MMC.open(currentSerialFilename, FILE_WRITE); if (serialLogFile) { if (serialLogFormatCSV) { @@ -1623,7 +1626,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, ext); - serial2LogFile = SD.open(currentSerial2Filename, FILE_WRITE); + serial2LogFile = SD_MMC.open(currentSerial2Filename, FILE_WRITE); if (serial2LogFile) { if (serial2LogFormatCSV) { @@ -1765,7 +1768,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) response["type"] = "files"; JsonArray files = response.createNestedArray("files"); - File root = SD.open("/"); + File root = SD_MMC.open("/"); if (root) { File file = root.openNextFile(); int fileCount = 0; @@ -1844,8 +1847,8 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) { bool success = false; - if (SD.exists(fullPath)) { - if (SD.remove(fullPath)) { + if (SD_MMC.exists(fullPath)) { + if (SD_MMC.remove(fullPath)) { success = true; } } @@ -1959,7 +1962,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) // SD 카드에 저장 if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) { - File seqFile = SD.open("/sequences.dat", FILE_WRITE); + File seqFile = SD_MMC.open("/sequences.dat", FILE_WRITE); if (seqFile) { seqFile.write((uint8_t*)&sequenceCount, sizeof(sequenceCount)); seqFile.write((uint8_t*)sequences, sizeof(CANSequence) * sequenceCount); @@ -2061,7 +2064,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) // SD 카드에 저장 if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) { - File seqFile = SD.open("/sequences.dat", FILE_WRITE); + File seqFile = SD_MMC.open("/sequences.dat", FILE_WRITE); if (seqFile) { seqFile.write((uint8_t*)&sequenceCount, sizeof(sequenceCount)); seqFile.write((uint8_t*)sequences, sizeof(CANSequence) * sequenceCount); @@ -2406,13 +2409,8 @@ void setup() { hspi.begin(HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_CS); hspi.beginTransaction(SPISettings(40000000, MSBFIRST, SPI_MODE0)); hspi.endTransaction(); - pinMode(VSPI_CS, OUTPUT); - digitalWrite(VSPI_CS, HIGH); - delay(100); - - vspi.begin(VSPI_SCLK, VSPI_MISO, VSPI_MOSI, VSPI_CS); - vspi.setFrequency(40000000); - Serial.println("✓ SPI 초기화 완료"); + // ⭐ VSPI 제거: SDIO는 별도 SPI 초기화 불필요 + Serial.println("✓ SPI 초기화 완료 (HSPI only)"); // Watchdog 비활성화 esp_task_wdt_deinit(); @@ -2469,14 +2467,29 @@ void setup() { // RTC 초기화 initRTC(); - // SD 카드 초기화 - if (SD.begin(VSPI_CS, vspi)) { + // ⭐⭐⭐ SD 카드 초기화 (SDIO 4-bit Mode) + Serial.println("SD 카드 초기화 (SDIO 4-bit)..."); + + // setPins() 호출: clk, cmd, d0, d1, d2, d3 + if (!SD_MMC.setPins(SDIO_CLK, SDIO_CMD, SDIO_D0, SDIO_D1, SDIO_D2, SDIO_D3)) { + Serial.println("✗ SD_MMC.setPins() 실패!"); + sdCardReady = false; + } else if (SD_MMC.begin("/sdcard", false)) { // false = 4-bit mode sdCardReady = true; - Serial.println("✓ SD 카드 초기화 완료"); + Serial.println("✓ SD 카드 초기화 완료 (SDIO 4-bit)"); + Serial.printf(" 카드 크기: %llu MB\n", SD_MMC.cardSize() / (1024 * 1024)); + Serial.printf(" 핀: CLK=%d, CMD=%d, D0=%d, D1=%d, D2=%d, D3=%d\n", + SDIO_CLK, SDIO_CMD, SDIO_D0, SDIO_D1, SDIO_D2, SDIO_D3); loadFileComments(); loadSequences(); } else { + sdCardReady = false; Serial.println("✗ SD 카드 초기화 실패"); + Serial.println(" 확인 사항:"); + Serial.println(" - 배선: CLK=39, CMD=38, D0=40, D1=41, D2=42, D3=21"); + Serial.println(" - 10kΩ 풀업 저항 확인 (CMD, D0-D3)"); + Serial.println(" - SD 카드 포맷 (FAT32)"); + Serial.println(" - SDIO 지원 SD 카드 모듈 사용"); } // WiFi 설정 @@ -2550,8 +2563,8 @@ void setup() { if (server.hasArg("file")) { String filename = "/" + server.arg("file"); - if (SD.exists(filename)) { - File file = SD.open(filename, FILE_READ); + if (SD_MMC.exists(filename)) { + File file = SD_MMC.open(filename, FILE_READ); if (file) { String displayName = server.arg("file"); server.sendHeader("Content-Disposition",