소프트웨어가 정해진 시간 안에 신호를 주지 않으면 시스템을 강제로 리셋하는 하드웨어 타이머(watchdog timer).
동작
워치독 카운터가 계속 감소한다 소프트웨어가 주기적으로 리로드(kick, feed, pet)한다
- 리로드를 못 하면 0에 도달 → 리셋
"프로그램이 살아 있다는 증거" 를 주기적으로 요구하는 것이다. 무한 루프, 데드락, 폭주로 코드가 멈추면 자동으로 복구된다.
두 종류
| 독립 워치독 (IWDG) | 윈도 워치독 (WWDG) | |
|---|---|---|
| 클럭 | 전용 저속 발진기(LSI) | 시스템 클럭(APB) |
| 시스템 클럭 고장 시 | 동작한다 | 함께 멈춘다 |
| 너무 일찍 리로드 | 허용 | 리셋 ★ |
| 정확도 | 낮다 (LSI ±5%) | 높다 |
| 용도 | 일반적 보호 | 타이밍 검증 |
★ 윈도 워치독의 특징 — "너무 늦어도 안 되고 너무 일찍 해도 안 된다".
[금지] [허용 창] [금지]
─────────┼───────────┼─────────
너무 이름 여기서 리로드 타임아웃
왜 이른 리로드를 막나 — 코드가 폭주해 루프를 너무 빨리 돌면서 우연히 리로드 코드를 계속 실행하는 상황을 잡아낸다. 정상 동작이라면 리로드 주기가 일정해야 한다는 논리다.
잘못 쓰는 대표적인 방법
❌ // 타이머 인터럽트에서 리로드
void TIM2_IRQHandler(void) { HAL_IWDG_Refresh(&hiwdg); }
메인 루프가 멈춰도 인터럽트는 계속 돈다. 워치독이 항상 리로드되어 아무것도 감지하지 못한다. 워치독이 있다는 착각만 주는 최악의 구성이다.
❌ // 여기저기서 리로드
void func_a(void) { … HAL_IWDG_Refresh(&hiwdg); … }
void func_b(void) { … HAL_IWDG_Refresh(&hiwdg); … }
어느 부분이 멈췄는지 알 수 없고, 일부만 살아 있어도 통과한다.
올바른 패턴 — 태스크별 체크인
volatile uint32_t task_alive_flags = 0;
#define TASK_SENSOR (1 << 0)
#define TASK_COMM (1 << 1)
#define TASK_CONTROL (1 << 2)
#define ALL_TASKS (TASK_SENSOR | TASK_COMM | TASK_CONTROL)
// 각 태스크가 자기 비트를 세운다
void sensor_task(void) { … task_alive_flags |= TASK_SENSOR; }
// 메인 루프(또는 최저 우선순위 태스크)에서만 리로드
void main_loop(void) {
if ((task_alive_flags & ALL_TASKS) == ALL_TASKS) {
task_alive_flags = 0;
HAL_IWDG_Refresh(&hiwdg);
}
}
모든 태스크가 살아 있을 때만 리로드한다. 하나라도 멈추면 워치독이 동작한다.
리로드를 최저 우선순위에서 하는 것도 중요하다 — 높은 우선순위 태스크가 CPU를 독점하는 상황도 감지할 수 있다.
타임아웃 설정
너무 짧으면 → 정상 동작에서도 리셋 (특히 플래시 쓰기, 긴 계산 중)
- 너무 길면 — → 복구가 늦어 서비스가 오래 멈춘다
일반적으로 정상 주기의 2~5배
긴 작업이 있으면 그 안에서도 주기적으로 리로드하거나, 작업 전에 타임아웃을 늘렸다가 되돌린다.
리셋 원인 기록 — 반드시 해야 한다
if (RCC->CSR & RCC_CSR_IWDGRSTF) {
watchdog_reset_count++; // 백업 레지스터에 누적
log_error("워치독 리셋 발생");
}
RCC->CSR |= RCC_CSR_RMVF; // 플래그 클리어
"현장에서 가끔 재부팅된다" 는 문제를 추적할 유일한 단서인 경우가 많다. 백업 SRAM이나 RTC 백업 레지스터에 카운터와 마지막 상태를 남기면 원인 분석에 결정적이다.
워치독은 만능이 아니다
✅ 잡는 것: 무한 루프, 데드락, 폭주, 인터럽트 폭주 ❌ 못 잡는 것
-
- 논리 오류 (계속 돌지만 결과가 틀림)
-
- 부분 고장 (센서 값이 이상해도 루프는 정상)
-
- 리셋 후 다시 같은 상태가 되는 문제 (부팅 루프)
리셋이 반복되면 오히려 위험할 수 있다. 반복 횟수를 세어 일정 횟수를 넘으면 안전 모드로 진입하는 설계가 필요하다.
디버깅 중에는
__HAL_DBGMCU_FREEZE_IWDG(); // 디버거로 멈추면 워치독도 정지
브레이크포인트에서 멈춘 동안 워치독이 리셋해 버리면 디버깅이 불가능하다. 개발 중에는 이 설정을 켜지만, 양산 빌드에서는 반드시 꺼야 한다.
외부 워치독
- MCU 내장 워치독은 MCU 자체가 완전히 멈추면 무력할 수 있다
- 별도 IC(외부 워치독)가 MCU의 RESET 핀을 제어
- 기능 안전(ISO 26262, IEC 61508)에서 요구되기도 한다