신호 살아있는 상태에서 리셋 시 수신 멈춤 수정

This commit is contained in:
2026-01-13 18:30:04 +00:00
parent d0b2c61999
commit b89d489c72

View File

@@ -343,13 +343,15 @@ void resetMCP2515() {
// 큐에서 모든 메시지 제거 // 큐에서 모든 메시지 제거
} }
// 3. MCP2515 하드 리셋 // 3. 하드웨어 리셋 (CS 토글)
Serial.println(" 1. 하드웨어 리셋...");
digitalWrite(HSPI_CS, LOW); digitalWrite(HSPI_CS, LOW);
delay(10); delayMicroseconds(100);
digitalWrite(HSPI_CS, HIGH); digitalWrite(HSPI_CS, HIGH);
delay(50); delay(100);
// 4. MCP2515 재초기화 // 4. 소프트웨어 리셋 (Configuration 모드로 진입)
Serial.println(" 2. 소프트웨어 리셋...");
mcp2515.reset(); mcp2515.reset();
delay(100); delay(100);
@@ -365,12 +367,26 @@ void resetMCP2515() {
} }
preferences.end(); 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); mcp2515.setBitrate(currentCanSpeed, MCP_8MHZ);
delay(10); 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) { if (currentMcpMode == MCP_MODE_NORMAL) {
mcp2515.setNormalMode(); mcp2515.setNormalMode();
} else if (currentMcpMode == MCP_MODE_LOOPBACK) { } else if (currentMcpMode == MCP_MODE_LOOPBACK) {
@@ -378,20 +394,59 @@ void resetMCP2515() {
} else { } else {
mcp2515.setListenOnlyMode(); mcp2515.setListenOnlyMode();
} }
delay(50);
// 6. 버퍼 클리어 // 8. 버퍼 클리어 (모드 전환 후)
Serial.println(" 6. 버퍼 클리어...");
struct can_frame dummyFrame; struct can_frame dummyFrame;
int clearCount = 0;
while (mcp2515.readMessage(&dummyFrame) == MCP2515::ERROR_OK) { 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; totalMsgCount = 0;
lastMsgCount = 0; lastMsgCount = 0;
msgPerSecond = 0; msgPerSecond = 0;
// 8. 최근 메시지 테이블 클리어 // 12. 최근 메시지 테이블 클리어
for (int i = 0; i < RECENT_MSG_COUNT; i++) { for (int i = 0; i < RECENT_MSG_COUNT; i++) {
recentData[i].count = 0; recentData[i].count = 0;
} }
@@ -1275,6 +1330,8 @@ void serial2RxTask(void *parameter) {
void canRxTask(void *parameter) { void canRxTask(void *parameter) {
struct can_frame frame; struct can_frame frame;
CANMessage msg; CANMessage msg;
uint32_t lastErrorCheck = 0;
uint32_t errorRecoveryCount = 0;
Serial.println("✓ CAN RX Task 시작 (Core 0, Priority 24 - 절대 최고!)"); Serial.println("✓ CAN RX Task 시작 (Core 0, Priority 24 - 절대 최고!)");
@@ -1299,8 +1356,72 @@ void canRxTask(void *parameter) {
} }
while (1) { 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) { while (mcp2515.readMessage(&frame) == MCP2515::ERROR_OK) {
struct timeval tv; struct timeval tv;
// 🎯 Auto Trigger 체크 // 🎯 Auto Trigger 체크
@@ -3049,23 +3170,111 @@ void setup() {
// Watchdog 비활성화 // Watchdog 비활성화
esp_task_wdt_deinit(); esp_task_wdt_deinit();
// MCP2515 초기화 // ========================================
// MCP2515 초기화 (개선된 시퀀스)
// ========================================
Serial.println("MCP2515 초기화..."); Serial.println("MCP2515 초기화...");
// ⭐⭐⭐ 하드 리셋 // 1. CS 핀 초기 상태 설정
digitalWrite(HSPI_CS, LOW); pinMode(HSPI_CS, OUTPUT);
delay(10);
digitalWrite(HSPI_CS, HIGH); 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(); mcp2515.reset();
delay(100); delay(100); // Configuration 모드 안정화 대기
// ✅ loadSettings()에서 이미 불러왔으므로 중복 제거
// 4. Configuration 모드에서 설정 (중요: 이 순서대로!)
Serial.println(" 3. Bitrate 설정...");
mcp2515.setBitrate(currentCanSpeed, MCP_8MHZ); mcp2515.setBitrate(currentCanSpeed, MCP_8MHZ);
delay(10); delay(10);
Serial.printf("🔧 Setup: MCP Mode = %d\n", (int)currentMcpMode);
// 5. 모드 설정 (Normal/Loopback/Listen Only) // 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);
}
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) { if (currentMcpMode == MCP_MODE_NORMAL) {
mcp2515.setNormalMode(); mcp2515.setNormalMode();
} else if (currentMcpMode == MCP_MODE_LOOPBACK) { } else if (currentMcpMode == MCP_MODE_LOOPBACK) {
@@ -3073,21 +3282,8 @@ void setup() {
} else { } else {
mcp2515.setListenOnlyMode(); mcp2515.setListenOnlyMode();
} }
delay(50); delay(50);
// 버퍼 클리어
Serial.println("CAN 버퍼 클리어...");
struct can_frame dummyFrame;
int clearCount = 0;
while (mcp2515.readMessage(&dummyFrame) == MCP2515::ERROR_OK) {
clearCount++;
if (clearCount > 100) break;
} }
if (clearCount > 0) {
Serial.printf("✓ 버퍼 클리어 완료 (%d개)\n", clearCount);
}
mcp2515.clearRXnOVRFlags();
Serial.println("✓ MCP2515 초기화 완료"); Serial.println("✓ MCP2515 초기화 완료");