sd card sdio 변경

This commit is contained in:
2025-12-28 20:53:42 +00:00
parent b0999bc589
commit 8994fe8e52

View File

@@ -18,7 +18,7 @@
#include <SPI.h>
#include <mcp2515.h>
#include <SoftWire.h>
#include <SD.h>
#include <SD_MMC.h> // ⭐ SDIO 4-bit
#include <WiFi.h>
#include <esp_wifi.h>
#include <esp_task_wdt.h>
@@ -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",