파일 라이팅 페일 조치
This commit is contained in:
@@ -1506,14 +1506,27 @@ void sdWriteTask(void *parameter) {
|
||||
csvFlushCounter = 0;
|
||||
}
|
||||
|
||||
// ⭐⭐⭐ 500개마다 파일 재오픈 (핵심!)
|
||||
if (++csvReopenCounter >= 500) {
|
||||
// ⭐⭐⭐ 2000개마다 파일 재오픈 (500 → 2000 변경, SDIO 안정성)
|
||||
if (++csvReopenCounter >= 2000) {
|
||||
logFile.close();
|
||||
logFile = SD_MMC.open(currentFilename, FILE_APPEND);
|
||||
if (logFile) {
|
||||
Serial.printf("✓ CSV 파일 재오픈: %s (%lu bytes)\n", currentFilename, currentFileSize);
|
||||
} else {
|
||||
Serial.println("✗ CSV 파일 재오픈 실패!");
|
||||
delay(50); // SD 카드 안정화 대기
|
||||
|
||||
// 파일 재오픈 (재시도 로직)
|
||||
bool reopenSuccess = false;
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
logFile = SD_MMC.open(currentFilename, FILE_APPEND);
|
||||
if (logFile) {
|
||||
Serial.printf("✓ CSV 파일 재오픈: %s (%lu bytes)\n", currentFilename, currentFileSize);
|
||||
reopenSuccess = true;
|
||||
break;
|
||||
} else {
|
||||
Serial.printf("⚠ CSV 파일 재오픈 실패, 재시도 %d/3\n", retry + 1);
|
||||
delay(100); // 재시도 전 대기
|
||||
}
|
||||
}
|
||||
|
||||
if (!reopenSuccess) {
|
||||
Serial.println("✗ CSV 파일 재오픈 완전 실패! 로깅 중지");
|
||||
loggingEnabled = false;
|
||||
}
|
||||
csvReopenCounter = 0;
|
||||
@@ -1552,8 +1565,8 @@ void sdWriteTask(void *parameter) {
|
||||
}
|
||||
}
|
||||
|
||||
// ⭐⭐⭐ 4단계: 500개마다 파일 재오픈 (핵심!)
|
||||
if (binReopenCounter >= 500) {
|
||||
// ⭐⭐⭐ 4단계: 2000개마다 파일 재오픈 (500 → 2000 변경, SDIO 안정성)
|
||||
if (binReopenCounter >= 2000) {
|
||||
// 버퍼 먼저 플러시
|
||||
if (logFile && bufferIndex > 0) {
|
||||
logFile.write(fileBuffer, bufferIndex);
|
||||
@@ -1561,15 +1574,29 @@ void sdWriteTask(void *parameter) {
|
||||
bufferIndex = 0;
|
||||
}
|
||||
|
||||
// 파일 닫고 다시 열기
|
||||
// 파일 닫기
|
||||
logFile.close();
|
||||
logFile = SD_MMC.open(currentFilename, FILE_APPEND);
|
||||
if (logFile) {
|
||||
Serial.printf("✓ BIN 파일 재오픈: %s (%lu bytes)\n", currentFilename, currentFileSize);
|
||||
} else {
|
||||
Serial.println("✗ BIN 파일 재오픈 실패!");
|
||||
delay(50); // SD 카드 안정화 대기
|
||||
|
||||
// 파일 재오픈 (재시도 로직)
|
||||
bool reopenSuccess = false;
|
||||
for (int retry = 0; retry < 3; retry++) {
|
||||
logFile = SD_MMC.open(currentFilename, FILE_APPEND);
|
||||
if (logFile) {
|
||||
Serial.printf("✓ BIN 파일 재오픈: %s (%lu bytes)\n", currentFilename, currentFileSize);
|
||||
reopenSuccess = true;
|
||||
break;
|
||||
} else {
|
||||
Serial.printf("⚠ BIN 파일 재오픈 실패, 재시도 %d/3\n", retry + 1);
|
||||
delay(100); // 재시도 전 대기
|
||||
}
|
||||
}
|
||||
|
||||
if (!reopenSuccess) {
|
||||
Serial.println("✗ BIN 파일 재오픈 완전 실패! 로깅 중지");
|
||||
loggingEnabled = false;
|
||||
}
|
||||
|
||||
binReopenCounter = 0;
|
||||
}
|
||||
}
|
||||
@@ -3368,7 +3395,6 @@ void setup() {
|
||||
// WebSocket 시작
|
||||
webSocket.begin();
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
webSocket.enableHeartbeat(15000, 3000, 2); // ping 15초, pong 3초, 재시도 2회
|
||||
|
||||
// ★★★ 웹 서버 라우팅 (중요!) ★★★
|
||||
server.on("/", HTTP_GET, []() {
|
||||
@@ -3644,22 +3670,55 @@ void setup() {
|
||||
// CAN 인터럽트 활성화
|
||||
attachInterrupt(digitalPinToInterrupt(CAN_INT_PIN), canISR, FALLING);
|
||||
|
||||
// Task 생성
|
||||
xTaskCreatePinnedToCore(canRxTask, "CAN_RX", 8192, NULL, configMAX_PRIORITIES - 1, &canRxTaskHandle, 1); // Core 0, Pri 24
|
||||
xTaskCreatePinnedToCore(sdWriteTask, "SD_WRITE", 18576, NULL, 6, &sdWriteTaskHandle, 0);
|
||||
xTaskCreatePinnedToCore(sequenceTask, "SEQ", 4096, NULL, 2, NULL, 1);
|
||||
xTaskCreatePinnedToCore(serialRxTask, "SERIAL_RX", 6144, NULL, 5, &serialRxTaskHandle, 0);
|
||||
xTaskCreatePinnedToCore(serial2RxTask, "SERIAL2_RX", 6144, NULL, 5, &serial2RxTaskHandle, 0); // ⭐ Serial2
|
||||
xTaskCreatePinnedToCore(txTask, "TX", 4096, NULL, 3, NULL, 1);
|
||||
xTaskCreatePinnedToCore(webUpdateTask, "WEB_UPDATE", 18384, NULL, 2, &webTaskHandle, 1); // ⭐ 10240 → 16384
|
||||
xTaskCreatePinnedToCore(sdMonitorTask, "SD_MONITOR", 4096, NULL, 1, NULL, 1);
|
||||
// ========================================
|
||||
// Task 생성 (최적화 버전)
|
||||
// ========================================
|
||||
Serial.println("\nTask 생성 중...");
|
||||
|
||||
// Core 1: 실시간 처리 + 웹 서비스
|
||||
// - CAN RX: 최고 우선순위로 메시지 수신
|
||||
// - WEB: Core 0의 SD 쓰기와 분리하여 응답성 확보
|
||||
// - TX: CAN 전송
|
||||
// - SEQ: 시퀀스 재생
|
||||
// - MONITOR: 상태 모니터링
|
||||
xTaskCreatePinnedToCore(canRxTask, "CAN_RX", 12288, NULL, 24, &canRxTaskHandle, 1); // ⭐ 8KB → 12KB, Pri 24 (최고)
|
||||
xTaskCreatePinnedToCore(webUpdateTask, "WEB_UPDATE", 12288, NULL, 4, &webTaskHandle, 1); // ⭐ Core 0 → 1, Pri 4 (SD와 분리)
|
||||
xTaskCreatePinnedToCore(txTask, "TX", 4096, NULL, 3, NULL, 1); // Pri 3
|
||||
xTaskCreatePinnedToCore(sequenceTask, "SEQ", 4096, NULL, 2, NULL, 1); // Pri 2
|
||||
xTaskCreatePinnedToCore(sdMonitorTask, "SD_MONITOR", 4096, NULL, 1, NULL, 1); // Pri 1
|
||||
|
||||
// Core 0: I/O 전용 (SD, Serial, RTC)
|
||||
// - SD 쓰기와 Serial 수신만 처리
|
||||
// - 웹은 Core 1에서 처리하므로 SD 지연 영향 없음
|
||||
xTaskCreatePinnedToCore(sdWriteTask, "SD_WRITE", 18576, NULL, 8, &sdWriteTaskHandle, 0); // Pri 8 (최우선)
|
||||
xTaskCreatePinnedToCore(serialRxTask, "SERIAL_RX", 6144, NULL, 6, &serialRxTaskHandle, 0); // Pri 6
|
||||
xTaskCreatePinnedToCore(serial2RxTask, "SERIAL2_RX", 6144, NULL, 6, &serial2RxTaskHandle,0); // Pri 6
|
||||
|
||||
if (timeSyncStatus.rtcAvailable) {
|
||||
xTaskCreatePinnedToCore(rtcSyncTask, "RTC_SYNC", 3072, NULL, 0, &rtcTaskHandle, 0);
|
||||
xTaskCreatePinnedToCore(rtcSyncTask, "RTC_SYNC", 3072, NULL, 0, &rtcTaskHandle, 0); // Pri 0 (최저)
|
||||
}
|
||||
|
||||
Serial.println("✓ 모든 Task 시작 완료");
|
||||
Serial.println("\n========================================");
|
||||
Serial.println(" Task 구성 (Core 분리 전략)");
|
||||
Serial.println("========================================");
|
||||
Serial.println("Core 1 (실시간 + 웹 서비스):");
|
||||
Serial.println(" - CAN_RX: 12KB, Pri 24 (최고)");
|
||||
Serial.println(" - WEB_UPDATE: 12KB, Pri 4 ⭐ SD와 분리");
|
||||
Serial.println(" - TX: 4KB, Pri 3");
|
||||
Serial.println(" - SEQ: 4KB, Pri 2");
|
||||
Serial.println(" - SD_MONITOR: 4KB, Pri 1");
|
||||
Serial.println("Core 0 (I/O 전용):");
|
||||
Serial.println(" - SD_WRITE: 18KB, Pri 8 (최우선)");
|
||||
Serial.println(" - SERIAL_RX: 6KB, Pri 6");
|
||||
Serial.println(" - SERIAL2_RX: 6KB, Pri 6");
|
||||
if (timeSyncStatus.rtcAvailable) {
|
||||
Serial.println(" - RTC_SYNC: 3KB, Pri 0");
|
||||
}
|
||||
Serial.println("========================================");
|
||||
Serial.println("📌 웹을 Core 1로 배치 → SD 쓰기 지연 영향 없음");
|
||||
Serial.println("========================================");
|
||||
Serial.println("\n========================================");
|
||||
Serial.println(" 접속 방법");
|
||||
Serial.println("========================================");
|
||||
Serial.printf(" WiFi SSID: %s\n", wifiSSID);
|
||||
@@ -3678,6 +3737,7 @@ void loop() {
|
||||
server.handleClient();
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
// 주기적 상태 출력 (30초)
|
||||
static uint32_t lastPrint = 0;
|
||||
if (millis() - lastPrint > 30000) {
|
||||
Serial.printf("[상태] CAN: %d/%d | S1: %d/%d | S2: %d/%d | PSRAM: %d KB\n",
|
||||
@@ -3687,4 +3747,44 @@ void loop() {
|
||||
ESP.getFreePsram() / 1024);
|
||||
lastPrint = millis();
|
||||
}
|
||||
|
||||
// 스택 사용량 모니터링 (5분마다)
|
||||
static uint32_t lastStackCheck = 0;
|
||||
if (millis() - lastStackCheck > 300000) {
|
||||
Serial.println("\n========== Task Stack Usage ==========");
|
||||
|
||||
if (canRxTaskHandle) {
|
||||
UBaseType_t stackLeft = uxTaskGetStackHighWaterMark(canRxTaskHandle);
|
||||
Serial.printf("CAN_RX: %5u bytes free (alloc: 12288)\n", stackLeft * 4);
|
||||
if (stackLeft * 4 < 2000) Serial.println(" ⚠️ 스택 부족 위험!");
|
||||
}
|
||||
|
||||
if (sdWriteTaskHandle) {
|
||||
UBaseType_t stackLeft = uxTaskGetStackHighWaterMark(sdWriteTaskHandle);
|
||||
Serial.printf("SD_WRITE: %5u bytes free (alloc: 18576)\n", stackLeft * 4);
|
||||
if (stackLeft * 4 < 3000) Serial.println(" ⚠️ 스택 부족 위험!");
|
||||
}
|
||||
|
||||
if (webTaskHandle) {
|
||||
UBaseType_t stackLeft = uxTaskGetStackHighWaterMark(webTaskHandle);
|
||||
Serial.printf("WEB_UPDATE: %5u bytes free (alloc: 12288)\n", stackLeft * 4);
|
||||
if (stackLeft * 4 < 2000) Serial.println(" ⚠️ 스택 부족 위험!");
|
||||
}
|
||||
|
||||
if (serialRxTaskHandle) {
|
||||
UBaseType_t stackLeft = uxTaskGetStackHighWaterMark(serialRxTaskHandle);
|
||||
Serial.printf("SERIAL_RX: %5u bytes free (alloc: 6144)\n", stackLeft * 4);
|
||||
}
|
||||
|
||||
if (serial2RxTaskHandle) {
|
||||
UBaseType_t stackLeft = uxTaskGetStackHighWaterMark(serial2RxTaskHandle);
|
||||
Serial.printf("SERIAL2_RX: %5u bytes free (alloc: 6144)\n", stackLeft * 4);
|
||||
}
|
||||
|
||||
Serial.printf("Free Heap: %u bytes\n", ESP.getFreeHeap());
|
||||
Serial.printf("Free PSRAM: %u KB\n", ESP.getFreePsram() / 1024);
|
||||
Serial.println("======================================\n");
|
||||
|
||||
lastStackCheck = millis();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user