신호 살아있는 상태에서 리셋 시 수신 멈춤 수정
This commit is contained in:
@@ -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();
|
||||
}
|
||||
// 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);
|
||||
|
||||
delay(50);
|
||||
|
||||
// 버퍼 클리어
|
||||
Serial.println("CAN 버퍼 클리어...");
|
||||
// 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 통신 초기화
|
||||
|
||||
Reference in New Issue
Block a user