diff --git a/ESP32_CAN_Logger-a.ino b/ESP32_CAN_Logger-a.ino index ab55fe6..a623672 100644 --- a/ESP32_CAN_Logger-a.ino +++ b/ESP32_CAN_Logger-a.ino @@ -343,13 +343,15 @@ void resetMCP2515() { // 큐에서 모든 메시지 제거 } - // 3. MCP2515 하드 리셋 + // 3. 하드웨어 리셋 (CS 토글) + Serial.println(" 1. 하드웨어 리셋..."); digitalWrite(HSPI_CS, LOW); - delay(10); + delayMicroseconds(100); digitalWrite(HSPI_CS, HIGH); - delay(50); + delay(100); - // 4. MCP2515 재초기화 + // 4. 소프트웨어 리셋 (Configuration 모드로 진입) + Serial.println(" 2. 소프트웨어 리셋..."); mcp2515.reset(); delay(100); @@ -365,12 +367,26 @@ void resetMCP2515() { } preferences.end(); - Serial.printf("🔧 resetMCP2515: Speed=%d, Mode=%d\n", (int)currentCanSpeed, (int)currentMcpMode); + Serial.printf(" 3. Speed=%d, Mode=%d\n", (int)currentCanSpeed, (int)currentMcpMode); + // 5. Bitrate 설정 (Configuration 모드에서) mcp2515.setBitrate(currentCanSpeed, MCP_8MHZ); delay(10); - // 5. 모드 설정 (Normal/Loopback/Listen Only) + // 6. 필터/마스크 설정 (모든 메시지 수신) + Serial.println(" 4. 필터 설정 (모든 메시지 수신)..."); + mcp2515.setFilterMask(MCP2515::MASK0, false, 0x000); + mcp2515.setFilterMask(MCP2515::MASK1, false, 0x000); + mcp2515.setFilter(MCP2515::RXF0, false, 0x000); + mcp2515.setFilter(MCP2515::RXF1, false, 0x000); + mcp2515.setFilter(MCP2515::RXF2, false, 0x000); + mcp2515.setFilter(MCP2515::RXF3, false, 0x000); + mcp2515.setFilter(MCP2515::RXF4, false, 0x000); + mcp2515.setFilter(MCP2515::RXF5, false, 0x000); + delay(10); + + // 7. 모드 설정 (마지막에!) + Serial.printf(" 5. 모드 설정: %d\n", (int)currentMcpMode); if (currentMcpMode == MCP_MODE_NORMAL) { mcp2515.setNormalMode(); } else if (currentMcpMode == MCP_MODE_LOOPBACK) { @@ -378,20 +394,59 @@ void resetMCP2515() { } else { mcp2515.setListenOnlyMode(); } + delay(50); - // 6. 버퍼 클리어 + // 8. 버퍼 클리어 (모드 전환 후) + Serial.println(" 6. 버퍼 클리어..."); struct can_frame dummyFrame; + int clearCount = 0; while (mcp2515.readMessage(&dummyFrame) == MCP2515::ERROR_OK) { - // MCP2515 수신 버퍼 비우기 + clearCount++; + if (clearCount > 100) break; + } + if (clearCount > 0) { + Serial.printf(" %d개 메시지 버림\n", clearCount); } - mcp2515.clearRXnOVRFlags(); - // 7. 통계 리셋 + // 9. 에러/오버플로우 플래그 클리어 + mcp2515.clearRXnOVRFlags(); + mcp2515.clearInterrupts(); + mcp2515.clearTXInterrupts(); + mcp2515.clearMERR(); + mcp2515.clearERRIF(); + delay(10); + + // 10. 에러 상태 확인 + uint8_t errorFlag = mcp2515.getErrorFlags(); + uint8_t txErr = mcp2515.errorCountTX(); + uint8_t rxErr = mcp2515.errorCountRX(); + Serial.printf(" 7. 에러 상태: EFLG=0x%02X, TEC=%d, REC=%d\n", errorFlag, txErr, rxErr); + + if (errorFlag != 0 || txErr > 0 || rxErr > 0) { + Serial.println(" ⚠️ 에러 감지됨 - 추가 리셋 시도..."); + // 에러가 있으면 완전 리셋 + mcp2515.reset(); + delay(50); + mcp2515.setBitrate(currentCanSpeed, MCP_8MHZ); + delay(10); + if (currentMcpMode == MCP_MODE_NORMAL) { + mcp2515.setNormalMode(); + } else if (currentMcpMode == MCP_MODE_LOOPBACK) { + mcp2515.setLoopbackMode(); + } else { + mcp2515.setListenOnlyMode(); + } + delay(50); + mcp2515.clearRXnOVRFlags(); + mcp2515.clearInterrupts(); + } + + // 11. 통계 리셋 totalMsgCount = 0; lastMsgCount = 0; msgPerSecond = 0; - // 8. 최근 메시지 테이블 클리어 + // 12. 최근 메시지 테이블 클리어 for (int i = 0; i < RECENT_MSG_COUNT; i++) { recentData[i].count = 0; } @@ -1275,6 +1330,8 @@ void serial2RxTask(void *parameter) { void canRxTask(void *parameter) { struct can_frame frame; CANMessage msg; + uint32_t lastErrorCheck = 0; + uint32_t errorRecoveryCount = 0; Serial.println("✓ CAN RX Task 시작 (Core 0, Priority 24 - 절대 최고!)"); @@ -1299,8 +1356,72 @@ void canRxTask(void *parameter) { } while (1) { - ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(100)); // 100ms 타임아웃으로 변경 + // 🆕 주기적 에러 체크 (1초마다) + uint32_t now = millis(); + if (now - lastErrorCheck > 1000) { + lastErrorCheck = now; + + uint8_t errorFlag = mcp2515.getErrorFlags(); + uint8_t txErr = mcp2515.errorCountTX(); + uint8_t rxErr = mcp2515.errorCountRX(); + + // 에러 감지 시 복구 시도 + if (errorFlag & 0xC0) { // RX0OVR 또는 RX1OVR (오버플로우) + Serial.printf("⚠️ CAN 오버플로우 감지! EFLG=0x%02X - 클리어 중...\n", errorFlag); + mcp2515.clearRXnOVRFlags(); + mcp2515.clearInterrupts(); + errorRecoveryCount++; + } + + if (errorFlag & 0x20) { // TXBO (Bus-Off) + Serial.printf("🚨 CAN Bus-Off 감지! EFLG=0x%02X, TEC=%d, REC=%d\n", errorFlag, txErr, rxErr); + + // Bus-Off 복구: 완전 리셋 필요 + Serial.println(" → 자동 복구 시도..."); + + // 1. 완전 리셋 (Configuration 모드로 진입 + 에러 카운터 자동 리셋) + mcp2515.reset(); + delay(100); + + // 2. Bitrate 재설정 + mcp2515.setBitrate(currentCanSpeed, MCP_8MHZ); + delay(10); + + // 3. 모든 에러 플래그 클리어 + mcp2515.clearRXnOVRFlags(); + mcp2515.clearInterrupts(); + mcp2515.clearTXInterrupts(); + mcp2515.clearMERR(); + mcp2515.clearERRIF(); + delay(10); + + // 4. 모드 재설정 + if (currentMcpMode == MCP_MODE_NORMAL) { + mcp2515.setNormalMode(); + } else if (currentMcpMode == MCP_MODE_LOOPBACK) { + mcp2515.setLoopbackMode(); + } else { + mcp2515.setListenOnlyMode(); + } + delay(50); + + // 5. 버퍼 클리어 + while (mcp2515.readMessage(&frame) == MCP2515::ERROR_OK) {} + mcp2515.clearRXnOVRFlags(); + + errorRecoveryCount++; + Serial.printf(" ✓ Bus-Off 복구 완료 (총 %lu회 복구)\n", errorRecoveryCount); + } + + // Error Passive 상태 감지 + if ((errorFlag & 0x18) && rxErr > 96) { + Serial.printf("⚠️ CAN Error Passive! REC=%d - 주의 필요\n", rxErr); + } + } + + // 메시지 읽기 while (mcp2515.readMessage(&frame) == MCP2515::ERROR_OK) { struct timeval tv; // 🎯 Auto Trigger 체크 @@ -3049,46 +3170,121 @@ void setup() { // Watchdog 비활성화 esp_task_wdt_deinit(); - // MCP2515 초기화 + // ======================================== + // MCP2515 초기화 (개선된 시퀀스) + // ======================================== Serial.println("MCP2515 초기화..."); - // ⭐⭐⭐ 하드 리셋 - digitalWrite(HSPI_CS, LOW); - delay(10); + // 1. CS 핀 초기 상태 설정 + pinMode(HSPI_CS, OUTPUT); digitalWrite(HSPI_CS, HIGH); - delay(50); + delay(10); + // 2. 하드웨어 리셋 (CS 토글) + Serial.println(" 1. 하드웨어 리셋..."); + digitalWrite(HSPI_CS, LOW); + delayMicroseconds(100); + digitalWrite(HSPI_CS, HIGH); + delay(100); // 리셋 후 충분한 대기 + + // 3. 소프트웨어 리셋 (Configuration 모드로 진입) + Serial.println(" 2. 소프트웨어 리셋..."); mcp2515.reset(); - delay(100); - // ✅ loadSettings()에서 이미 불러왔으므로 중복 제거 + delay(100); // Configuration 모드 안정화 대기 + + // 4. Configuration 모드에서 설정 (중요: 이 순서대로!) + Serial.println(" 3. Bitrate 설정..."); mcp2515.setBitrate(currentCanSpeed, MCP_8MHZ); delay(10); - Serial.printf("🔧 Setup: MCP Mode = %d\n", (int)currentMcpMode); - - // 5. 모드 설정 (Normal/Loopback/Listen Only) - if (currentMcpMode == MCP_MODE_NORMAL) { - mcp2515.setNormalMode(); - } else if (currentMcpMode == MCP_MODE_LOOPBACK) { - mcp2515.setLoopbackMode(); - } else { - mcp2515.setListenOnlyMode(); - } - - delay(50); - // 버퍼 클리어 - Serial.println("CAN 버퍼 클리어..."); + // 5. 필터/마스크 설정 (모든 메시지 수신) + Serial.println(" 4. 필터 설정 (모든 메시지 수신)..."); + mcp2515.setFilterMask(MCP2515::MASK0, false, 0x000); + mcp2515.setFilterMask(MCP2515::MASK1, false, 0x000); + mcp2515.setFilter(MCP2515::RXF0, false, 0x000); + mcp2515.setFilter(MCP2515::RXF1, false, 0x000); + mcp2515.setFilter(MCP2515::RXF2, false, 0x000); + mcp2515.setFilter(MCP2515::RXF3, false, 0x000); + mcp2515.setFilter(MCP2515::RXF4, false, 0x000); + mcp2515.setFilter(MCP2515::RXF5, false, 0x000); + delay(10); + + // 6. 수신 버퍼 비우기 (Configuration 모드에서) + Serial.println(" 5. 수신 버퍼 클리어..."); struct can_frame dummyFrame; int clearCount = 0; + while (clearCount < 10) { + if (mcp2515.readMessage(&dummyFrame) != MCP2515::ERROR_OK) break; + clearCount++; + } + if (clearCount > 0) { + Serial.printf(" %d개 메시지 버림\n", clearCount); + } + + // 7. 에러/오버플로우 플래그 클리어 + Serial.println(" 6. 에러 플래그 클리어..."); + mcp2515.clearRXnOVRFlags(); + mcp2515.clearInterrupts(); + mcp2515.clearTXInterrupts(); + mcp2515.clearMERR(); + mcp2515.clearERRIF(); + delay(10); + + // 8. 모드 전환 (마지막에!) + Serial.printf(" 7. 모드 설정: %d\n", (int)currentMcpMode); + if (currentMcpMode == MCP_MODE_NORMAL) { + mcp2515.setNormalMode(); + Serial.println(" → Normal Mode"); + } else if (currentMcpMode == MCP_MODE_LOOPBACK) { + mcp2515.setLoopbackMode(); + Serial.println(" → Loopback Mode"); + } else if (currentMcpMode == MCP_MODE_LISTEN_ONLY) { + mcp2515.setListenOnlyMode(); + Serial.println(" → Listen-Only Mode"); + } else { + // TRANSMIT 모드는 Listen-Only로 시작 (TX 시에만 Normal로 전환) + mcp2515.setListenOnlyMode(); + Serial.println(" → Listen-Only Mode (TX mode)"); + } + delay(50); // 모드 전환 안정화 + + // 9. 최종 버퍼 클리어 (모드 전환 후) + Serial.println(" 8. 최종 버퍼 클리어..."); + clearCount = 0; while (mcp2515.readMessage(&dummyFrame) == MCP2515::ERROR_OK) { clearCount++; if (clearCount > 100) break; } if (clearCount > 0) { - Serial.printf("✓ 버퍼 클리어 완료 (%d개)\n", clearCount); + Serial.printf(" %d개 메시지 버림\n", clearCount); } mcp2515.clearRXnOVRFlags(); + // 10. 에러 상태 확인 + uint8_t errorFlag = mcp2515.getErrorFlags(); + uint8_t txErr = mcp2515.errorCountTX(); + uint8_t rxErr = mcp2515.errorCountRX(); + Serial.printf(" 9. 에러 상태: EFLG=0x%02X, TEC=%d, REC=%d\n", errorFlag, txErr, rxErr); + + if (errorFlag != 0 || txErr > 0 || rxErr > 0) { + Serial.println(" ⚠️ 에러 감지됨 - 추가 리셋 시도..."); + // 에러가 있으면 완전 리셋 재시도 + mcp2515.reset(); + delay(50); + mcp2515.setBitrate(currentCanSpeed, MCP_8MHZ); + delay(10); + mcp2515.clearRXnOVRFlags(); + mcp2515.clearInterrupts(); + if (currentMcpMode == MCP_MODE_NORMAL) { + mcp2515.setNormalMode(); + } else if (currentMcpMode == MCP_MODE_LOOPBACK) { + mcp2515.setLoopbackMode(); + } else { + mcp2515.setListenOnlyMode(); + } + delay(50); + } + Serial.println("✓ MCP2515 초기화 완료"); // Serial 통신 초기화 @@ -3281,4 +3477,4 @@ void loop() { ESP.getFreePsram() / 1024); lastPrint = millis(); } -} +} \ No newline at end of file