sd card sdio 변경
This commit is contained in:
@@ -18,7 +18,7 @@
|
|||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include <mcp2515.h>
|
#include <mcp2515.h>
|
||||||
#include <SoftWire.h>
|
#include <SoftWire.h>
|
||||||
#include <SD.h>
|
#include <SD_MMC.h> // ⭐ SDIO 4-bit
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <esp_wifi.h>
|
#include <esp_wifi.h>
|
||||||
#include <esp_task_wdt.h>
|
#include <esp_task_wdt.h>
|
||||||
@@ -55,11 +55,14 @@
|
|||||||
#define HSPI_SCLK 12
|
#define HSPI_SCLK 12
|
||||||
#define HSPI_CS 10
|
#define HSPI_CS 10
|
||||||
|
|
||||||
// VSPI 핀 (SD Card)
|
// ⭐⭐⭐ SDIO 4-bit Pins (ESP32-S3)
|
||||||
#define VSPI_MISO 41
|
// CLK: GPIO39, CMD: GPIO38, D0-D3: GPIO40,41,42,21
|
||||||
#define VSPI_MOSI 40
|
#define SDIO_CLK 39
|
||||||
#define VSPI_SCLK 39
|
#define SDIO_CMD 38
|
||||||
#define VSPI_CS 42
|
#define SDIO_D0 40
|
||||||
|
#define SDIO_D1 41
|
||||||
|
#define SDIO_D2 42
|
||||||
|
#define SDIO_D3 21 // ⭐ OPI PSRAM 호환
|
||||||
|
|
||||||
// I2C2 핀 (RTC DS3231)
|
// I2C2 핀 (RTC DS3231)
|
||||||
#define RTC_SDA 8
|
#define RTC_SDA 8
|
||||||
@@ -216,7 +219,7 @@ SerialSettings serial2Settings = {115200, 8, 0, 1}; // ⭐ Serial2 추가
|
|||||||
|
|
||||||
// 전역 객체 (내부 SRAM)
|
// 전역 객체 (내부 SRAM)
|
||||||
SPIClass hspi(HSPI);
|
SPIClass hspi(HSPI);
|
||||||
SPIClass vspi(FSPI);
|
// SPIClass vspi(FSPI); // ⭐ SDIO 사용으로 제거
|
||||||
MCP2515 mcp2515(HSPI_CS, 20000000, &hspi);
|
MCP2515 mcp2515(HSPI_CS, 20000000, &hspi);
|
||||||
HardwareSerial SerialComm(1); // UART1
|
HardwareSerial SerialComm(1); // UART1
|
||||||
HardwareSerial Serial2Comm(2); // ⭐ UART2 추가
|
HardwareSerial Serial2Comm(2); // ⭐ UART2 추가
|
||||||
@@ -1007,7 +1010,7 @@ void sdWriteTask(void *parameter) {
|
|||||||
// ⭐⭐⭐ 500개마다 파일 재오픈 (핵심!)
|
// ⭐⭐⭐ 500개마다 파일 재오픈 (핵심!)
|
||||||
if (++csvReopenCounter >= 500) {
|
if (++csvReopenCounter >= 500) {
|
||||||
logFile.close();
|
logFile.close();
|
||||||
logFile = SD.open(currentFilename, FILE_APPEND);
|
logFile = SD_MMC.open(currentFilename, FILE_APPEND);
|
||||||
if (logFile) {
|
if (logFile) {
|
||||||
Serial.printf("✓ CSV 파일 재오픈: %s (%lu bytes)\n", currentFilename, currentFileSize);
|
Serial.printf("✓ CSV 파일 재오픈: %s (%lu bytes)\n", currentFilename, currentFileSize);
|
||||||
} else {
|
} else {
|
||||||
@@ -1061,7 +1064,7 @@ void sdWriteTask(void *parameter) {
|
|||||||
|
|
||||||
// 파일 닫고 다시 열기
|
// 파일 닫고 다시 열기
|
||||||
logFile.close();
|
logFile.close();
|
||||||
logFile = SD.open(currentFilename, FILE_APPEND);
|
logFile = SD_MMC.open(currentFilename, FILE_APPEND);
|
||||||
if (logFile) {
|
if (logFile) {
|
||||||
Serial.printf("✓ BIN 파일 재오픈: %s (%lu bytes)\n", currentFilename, currentFileSize);
|
Serial.printf("✓ BIN 파일 재오픈: %s (%lu bytes)\n", currentFilename, currentFileSize);
|
||||||
} else {
|
} else {
|
||||||
@@ -1123,7 +1126,7 @@ void sdMonitorTask(void *parameter) {
|
|||||||
void saveFileComments() {
|
void saveFileComments() {
|
||||||
if (!sdCardReady) return;
|
if (!sdCardReady) return;
|
||||||
if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
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) {
|
if (commentFile) {
|
||||||
commentFile.write((uint8_t*)&commentCount, sizeof(commentCount));
|
commentFile.write((uint8_t*)&commentCount, sizeof(commentCount));
|
||||||
commentFile.write((uint8_t*)fileComments, sizeof(FileComment) * commentCount);
|
commentFile.write((uint8_t*)fileComments, sizeof(FileComment) * commentCount);
|
||||||
@@ -1136,8 +1139,8 @@ void saveFileComments() {
|
|||||||
void loadFileComments() {
|
void loadFileComments() {
|
||||||
if (!sdCardReady) return;
|
if (!sdCardReady) return;
|
||||||
if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
||||||
if (SD.exists("/comments.dat")) {
|
if (SD_MMC.exists("/comments.dat")) {
|
||||||
File commentFile = SD.open("/comments.dat", FILE_READ);
|
File commentFile = SD_MMC.open("/comments.dat", FILE_READ);
|
||||||
if (commentFile) {
|
if (commentFile) {
|
||||||
commentFile.read((uint8_t*)&commentCount, sizeof(commentCount));
|
commentFile.read((uint8_t*)&commentCount, sizeof(commentCount));
|
||||||
if (commentCount > MAX_FILE_COMMENTS) commentCount = MAX_FILE_COMMENTS;
|
if (commentCount > MAX_FILE_COMMENTS) commentCount = MAX_FILE_COMMENTS;
|
||||||
@@ -1184,7 +1187,7 @@ void addFileComment(const char* filename, const char* comment) {
|
|||||||
void saveSequences() {
|
void saveSequences() {
|
||||||
if (!sdCardReady) return;
|
if (!sdCardReady) return;
|
||||||
if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
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) {
|
if (seqFile) {
|
||||||
seqFile.write((uint8_t*)&sequenceCount, sizeof(sequenceCount));
|
seqFile.write((uint8_t*)&sequenceCount, sizeof(sequenceCount));
|
||||||
seqFile.write((uint8_t*)sequences, sizeof(CANSequence) * sequenceCount);
|
seqFile.write((uint8_t*)sequences, sizeof(CANSequence) * sequenceCount);
|
||||||
@@ -1197,8 +1200,8 @@ void saveSequences() {
|
|||||||
void loadSequences() {
|
void loadSequences() {
|
||||||
if (!sdCardReady) return;
|
if (!sdCardReady) return;
|
||||||
if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
||||||
if (SD.exists("/sequences.dat")) {
|
if (SD_MMC.exists("/sequences.dat")) {
|
||||||
File seqFile = SD.open("/sequences.dat", FILE_READ);
|
File seqFile = SD_MMC.open("/sequences.dat", FILE_READ);
|
||||||
if (seqFile) {
|
if (seqFile) {
|
||||||
seqFile.read((uint8_t*)&sequenceCount, sizeof(sequenceCount));
|
seqFile.read((uint8_t*)&sequenceCount, sizeof(sequenceCount));
|
||||||
if (sequenceCount > MAX_SEQUENCES) sequenceCount = MAX_SEQUENCES;
|
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);
|
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 (logFile) {
|
||||||
if (canLogFormatCSV) {
|
if (canLogFormatCSV) {
|
||||||
@@ -1416,7 +1419,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length)
|
|||||||
logFile.close(); // ⭐ 헤더 쓰고 닫기
|
logFile.close(); // ⭐ 헤더 쓰고 닫기
|
||||||
|
|
||||||
// ⭐⭐⭐ APPEND 모드로 다시 열기
|
// ⭐⭐⭐ APPEND 모드로 다시 열기
|
||||||
logFile = SD.open(currentFilename, FILE_APPEND);
|
logFile = SD_MMC.open(currentFilename, FILE_APPEND);
|
||||||
|
|
||||||
if (logFile) {
|
if (logFile) {
|
||||||
loggingEnabled = true;
|
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_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
|
||||||
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, ext);
|
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 (serialLogFile) {
|
||||||
if (serialLogFormatCSV) {
|
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_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
|
||||||
timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, ext);
|
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 (serial2LogFile) {
|
||||||
if (serial2LogFormatCSV) {
|
if (serial2LogFormatCSV) {
|
||||||
@@ -1765,7 +1768,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length)
|
|||||||
response["type"] = "files";
|
response["type"] = "files";
|
||||||
JsonArray files = response.createNestedArray("files");
|
JsonArray files = response.createNestedArray("files");
|
||||||
|
|
||||||
File root = SD.open("/");
|
File root = SD_MMC.open("/");
|
||||||
if (root) {
|
if (root) {
|
||||||
File file = root.openNextFile();
|
File file = root.openNextFile();
|
||||||
int fileCount = 0;
|
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) {
|
if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
if (SD.exists(fullPath)) {
|
if (SD_MMC.exists(fullPath)) {
|
||||||
if (SD.remove(fullPath)) {
|
if (SD_MMC.remove(fullPath)) {
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1959,7 +1962,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length)
|
|||||||
|
|
||||||
// SD 카드에 저장
|
// SD 카드에 저장
|
||||||
if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
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) {
|
if (seqFile) {
|
||||||
seqFile.write((uint8_t*)&sequenceCount, sizeof(sequenceCount));
|
seqFile.write((uint8_t*)&sequenceCount, sizeof(sequenceCount));
|
||||||
seqFile.write((uint8_t*)sequences, sizeof(CANSequence) * 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 카드에 저장
|
// SD 카드에 저장
|
||||||
if (xSemaphoreTake(sdMutex, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
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) {
|
if (seqFile) {
|
||||||
seqFile.write((uint8_t*)&sequenceCount, sizeof(sequenceCount));
|
seqFile.write((uint8_t*)&sequenceCount, sizeof(sequenceCount));
|
||||||
seqFile.write((uint8_t*)sequences, sizeof(CANSequence) * 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.begin(HSPI_SCLK, HSPI_MISO, HSPI_MOSI, HSPI_CS);
|
||||||
hspi.beginTransaction(SPISettings(40000000, MSBFIRST, SPI_MODE0));
|
hspi.beginTransaction(SPISettings(40000000, MSBFIRST, SPI_MODE0));
|
||||||
hspi.endTransaction();
|
hspi.endTransaction();
|
||||||
pinMode(VSPI_CS, OUTPUT);
|
// ⭐ VSPI 제거: SDIO는 별도 SPI 초기화 불필요
|
||||||
digitalWrite(VSPI_CS, HIGH);
|
Serial.println("✓ SPI 초기화 완료 (HSPI only)");
|
||||||
delay(100);
|
|
||||||
|
|
||||||
vspi.begin(VSPI_SCLK, VSPI_MISO, VSPI_MOSI, VSPI_CS);
|
|
||||||
vspi.setFrequency(40000000);
|
|
||||||
Serial.println("✓ SPI 초기화 완료");
|
|
||||||
|
|
||||||
// Watchdog 비활성화
|
// Watchdog 비활성화
|
||||||
esp_task_wdt_deinit();
|
esp_task_wdt_deinit();
|
||||||
@@ -2469,14 +2467,29 @@ void setup() {
|
|||||||
// RTC 초기화
|
// RTC 초기화
|
||||||
initRTC();
|
initRTC();
|
||||||
|
|
||||||
// SD 카드 초기화
|
// ⭐⭐⭐ SD 카드 초기화 (SDIO 4-bit Mode)
|
||||||
if (SD.begin(VSPI_CS, vspi)) {
|
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;
|
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();
|
loadFileComments();
|
||||||
loadSequences();
|
loadSequences();
|
||||||
} else {
|
} else {
|
||||||
|
sdCardReady = false;
|
||||||
Serial.println("✗ SD 카드 초기화 실패");
|
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 설정
|
// WiFi 설정
|
||||||
@@ -2550,8 +2563,8 @@ void setup() {
|
|||||||
if (server.hasArg("file")) {
|
if (server.hasArg("file")) {
|
||||||
String filename = "/" + server.arg("file");
|
String filename = "/" + server.arg("file");
|
||||||
|
|
||||||
if (SD.exists(filename)) {
|
if (SD_MMC.exists(filename)) {
|
||||||
File file = SD.open(filename, FILE_READ);
|
File file = SD_MMC.open(filename, FILE_READ);
|
||||||
if (file) {
|
if (file) {
|
||||||
String displayName = server.arg("file");
|
String displayName = server.arg("file");
|
||||||
server.sendHeader("Content-Disposition",
|
server.sendHeader("Content-Disposition",
|
||||||
|
|||||||
Reference in New Issue
Block a user