기록
[GPT가 알려주는] Watchdog 본문
좋은 질문이에요 🙂 “Watchdog”은 **임베디드 시스템이나 서버 같은 전자 장치에서 시스템이 멈추거나 오동작할 때 자동으로 감지하고 리셋하는 장치(또는 소프트웨어 기능)**를 말합니다.
1. 기본 개념
- 마치 강아지(Watchdog)가 집을 지키듯, 시스템이 정상 동작하는지 계속 감시합니다.
- CPU나 프로그램이 멈추면(=강아지가 밥 못 받음), 일정 시간 안에 신호가 안 들어오면 “에러났다!” 하고 리셋을 걸어줍니다.
2. 동작 방식
- 타이머 기반
- Watchdog은 내부 타이머를 가지고 있어요.
- 프로그램이 정상적으로 돌고 있다면 주기적으로 "나는 살아있어!"라는 신호(=kick, feed)를 Watchdog에게 줍니다.
- 오류 감지
- 만약 프로그램이 멈춰서 그 신호를 못 주면, 타이머가 만료됩니다.
- 자동 리셋
- 타이머가 만료되면 Watchdog이 CPU를 강제로 리셋해서 다시 부팅시킵니다.
3. 비유
- 집에 강아지: 일정 시간마다 주인이 밥 줘야 함(=시스템이 kick 신호 보냄).
- 주인이 기절: 밥이 안 옴 → 강아지가 짖어서 집을 깨움(=시스템 리셋).
4. 실제 활용
- MCU/임베디드: 자동차 ECU, IoT 기기, 의료기기 등 멈추면 안 되는 장치에 필수.
- 서버: 커널 패닉, 시스템 멈춤 시 자동 재부팅.
- Linux: /dev/watchdog 디바이스로 접근 가능.
✅ 정리
Watchdog = 시스템이 멈췄는지 감시하고, 멈추면 자동으로 재부팅하는 “안전 장치”
혹시 원하시면, 제가 **STM32 같은 MCU에서 Watchdog 코드 예시 (HAL 기반)**를 보여드릴까요?
좋아! STM32(HAL) 기준으로 IWDG(Independent WDG) 와 WWDG(Window WDG) 두 가지 예제를 바로 쓸 수 있게 드릴게.
✅ IWDG (전원/클럭 독립, 가장 흔히 사용)
- LSI(≈32 kHz)로 동작, 메인 클럭이 죽어도 살아요.
- 타임아웃 계산: Tout ≈ (Reload+1) * Prescaler / LSI
- Prescaler ∈ {4,8,16,32,64,128,256}
- 예) LSI=32 kHz, Presc=64, Reload=1999 → (2000 * 64) / 32000 ≈ 4 s
1) CubeMX 설정(권장)
- Peripherals → IWDG Enable, Prescaler/Reload 설정.
2) 코드 (자동 생성 + 주기적 갱신)
// main.c
#include "main.h"
IWDG_HandleTypeDef hiwdg;
static void MX_IWDG_Init(void)
{
// Prescaler = 64, Reload = 1999 → 약 4초 타임아웃 (LSI=32kHz 가정)
hiwdg.Instance = IWDG;
hiwdg.Init.Prescaler = IWDG_PRESCALER_64;
hiwdg.Init.Reload = 1999;
HAL_IWDG_Init(&hiwdg);
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_IWDG_Init(); // IWDG 시작 (즉시 동작)
while (1)
{
// 애플리케이션 로직...
HAL_Delay(500); // 500ms마다 feed (4초보다 충분히 짧게)
HAL_IWDG_Refresh(&hiwdg);
}
}
주의
- IWDG는 시작하면 정지 불가(리셋 외). 타임아웃은 넉넉하게.
- LSI 주파수 편차(±%)가 커요. 마진을 두고 주기 설정하세요.
- 긴 블로킹 구간(플래시 쓰기, 저전력 등)에서도 주기적으로 Refresh 해야 함.
✅ FreeRTOS에서 안전하게 feed 하는 법
- 전용 WDG 태스크를 만들고, 핵심 태스크들이 “하트비트”를 보내면 묶어서 Refresh.
- 한 태스크라도 “멈추면” 하트비트가 끊겨 WDG가 리셋 → 진짜 헝걸림 감지.
// watchdog_task.c (개념 예시)
extern IWDG_HandleTypeDef hiwdg;
volatile uint32_t hb_bits = 0;
#define HB_TASK1 (1U<<0)
#define HB_TASK2 (1U<<1)
// ... 필요만큼 비트 정의
void Task1(void *arg) {
for(;;){
// 작업...
xTaskNotifyStateClear(NULL);
hb_bits |= HB_TASK1;
vTaskDelay(pdMS_TO_TICKS(200));
}
}
void Task2(void *arg) {
for(;;){
// 작업...
hb_bits |= HB_TASK2;
vTaskDelay(pdMS_TO_TICKS(300));
}
}
void WatchdogTask(void *arg) {
const uint32_t ALL = HB_TASK1 | HB_TASK2;
for(;;){
if ((hb_bits & ALL) == ALL) {
HAL_IWDG_Refresh(&hiwdg); // 모두 살아있으면 feed
hb_bits = 0; // 다음 윈도우를 위해 클리어
}
vTaskDelay(pdMS_TO_TICKS(500)); // IWDG 타임아웃보다 충분히 짧게
}
}
✅ WWDG (Window Watchdog) 예시
- APB 클럭 사용, “너무 빨라도/너무 늦어도” 리셋되는 윈도우형.
- 타이밍 제어가 까다롭지만, 타이밍 이상도 잡아냄.
#include "main.h"
WWDG_HandleTypeDef hwwdg;
static void MX_WWDG_Init(void)
{
// 예: PCLK1=84MHz, Presc=8 → counter 크기와 윈도우에 맞춰 설정
hwwdg.Instance = WWDG;
hwwdg.Init.Prescaler = WWDG_PRESCALER_8;
hwwdg.Init.Window = 0x50; // 윈도우 상한
hwwdg.Init.Counter = 0x7F; // 시작 카운터
hwwdg.Init.EWIMode = WWDG_EWI_ENABLE; // 조기 경보 인터럽트(선택)
HAL_WWDG_Init(&hwwdg);
}
void loop_feed_wwdg(void)
{
// 반드시 윈도우 안에서만 refresh!
// (실제론 타이머/틱 기준으로 정확히 맞춰 호출)
HAL_WWDG_Refresh(&hwwdg);
}
팁
- WWDG는 정확한 주기가 포인트 → 타이머 인터럽트에서 Refresh.
- 윈도우보다 빨리 Refresh 하면 바로 리셋됨.
🔍 부팅 원인 확인 (리셋 원인 로깅)
- 일부 STM32는 RCC_CSR 레지스터의 WDG Reset Flag로 리셋 원인 확인 가능.
if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) {
// 이전 리셋은 IWDG에 의해 발생
}
__HAL_RCC_CLEAR_RESET_FLAGS();
🧩 실전 체크리스트
- 타임아웃은 여유 있게(LSI 편차 고려)
- 블로킹 구간에도 feed 가능?
- FreeRTOS면 하트비트 집계 방식으로 설계
- 리셋 후 원인 로깅 남기기(UART/플래시에 카운터)
- 디버깅 중엔 WDG 비활성(CubeMX 옵션/HAL_DBGMCU_EnableDBGStopMode) 고려
필요하시면 귀하가 쓰는 STM32 모델명(예: F4, L4, H7 등) 알려주세요. 그 칩의 정확한 LSI 주파수·타이머 계산값으로 타임아웃을 산출해서, 프로젝트에 바로 붙일 수 있는 설정값까지 계산해 드릴게요!
좋아요—이번엔 워치독(Watchdog) 을 한 단계 깊게, 하지만 이해되게 정리해볼게요.
워치독이란?
**시스템이 멈추거나(헝걸림), 무한 루프·데드락 등 ‘비정상 상태’에 빠지면 자동으로 감지해 리셋시키는 ‘안전장치’**예요.
- 하드웨어 WDT(칩 내부 또는 외부 IC): 전용 타이머가 돌아가다 “기한 내에 신호(Feed/Kick)를 못 받으면” 즉시 리셋.
- 소프트웨어 WDT: 커널/OS가 타이머로 응답 지연을 감지해 리커버리(프로세스 kill 등). 보조 개념으로 쓰고, 최후 보루는 HW WDT로 잡는 게 일반적입니다.
어떻게 동작하나? (기본 루프)
- WDT 타이머 시작 → 2) 애플리케이션이 주기적으로 Feed(=“나 살아있어!” 신호) →
- 만약 멈추면 Feed 누락 → 4) 타이머 만료 → 5) 하드 리셋(재부팅)
용어: Feed/Pet/Kick(같은 뜻), Timeout(만료시간), Window(허용 갱신 구간)
유형별 특징
- IWDG(Independent WDT): 메인 클럭과 독립된 저속 오실레이터로 동작 → 메인 클럭이 죽어도 리셋 가능(신뢰성 ↑).
- WWDG(Window WDT): 너무 빨라도/늦어도 갱신하면 리셋(타이밍 이상까지 잡음).
- 외부 슈퍼바이저 IC(예: 전원감시+BOD): 칩 밖에서 감시 → 전원 이상/잠김에도 강함, 이중화 용이.
설계 패턴 (중요!)
1) “하트비트 집계” 패턴 (RTOS/멀티스레드 권장)
여러 중요한 태스크가 **각자 비트 플래그(하트비트)**를 올리고, 감시 태스크가 모든 비트를 확인해 모두 OK일 때만 WDT를 Feed.
- 장점: 한 태스크라도 멈추면 Feed가 멈춰 진짜 오류만 리셋 유발.
- 안티패턴: 메인 루프 한 곳에서 무조건 Feed(→ 일부 태스크가 죽어도 리셋 못 함).
2) “윈도우”로 타이밍 이상 탐지
- 너무 자주(빠르게) Feed하는 버그도 잡음(바쁘다고 계속 리셋을 미루다 무한 Feed 하는 경우).
- 타이머 인터럽트에서 정확히 Feed하거나, 주기 검증을 넣어요.
3) “계측 + 로그”로 원인 추적
- 리셋 원인 레지스터(예: IWDG 리셋 플래그)로 WDT 리셋 여부 기록.
- 부팅 카운터/부팅 시간 로그를 플래시에 남겨 리셋 루프 감지 → 안전모드 진입(네트워킹 지연, 기능 축소 등).
4) 펌웨어 업데이트/부트로더 연동
- OTA 중 멈추면 WDT가 자동 복구하게 설계.
- 업데이트 단계에 따라 타임아웃을 넉넉히 조정하거나 일시 정지/특별 루틴 사용.
5) 저전력·장시간 블로킹 고려
- 슬립/DEEP STOP 동안 Feed 불가 → 슬립 전 WDT 일시정지(가능한 칩만) 또는 타임아웃 확장.
- 플래시 쓰기/암호화 같은 블로킹 구간이 타임아웃보다 길지 않게 설계.
타임아웃 계산 요령
- 가장 긴 주기 작업(센서 폴링, I/O, 파일쓰기) +
- 지터/스케줄링 여유 +
- 클럭 편차(내부 LSI 오실레이터 편차)
→ 합산 후 안전 마진(예: 1.5~3배) 넣어 설정.
- IWDG는 내부 LSI 오차가 큽니다(수 %). 실측해서 마진을 넉넉히!
흔한 실수 (피하세요)
- ISR(인터럽트)에서 Feed: 메인 쓰레드가 죽어도 인터럽트는 계속 살아 Feed되어 오류를 숨김.
- 한 군데서 무조건 Feed: 일부 서브시스템 죽어도 감지 못함.
- 디버깅 중 활성화: 브레이크로 멈춰있다 리셋 반복 → 디버그 모드에서 일시 비활성 필요.
- 타임아웃 과소: 정상 동작도 리셋 → “불안정한 제품”이 됨.
- 리셋 루프 방치: 부팅 직후 같은 코드 경로에서 또 WDT 만료 → 플래시/네트워크 소모만 커짐.
Linux에서의 Watchdog (사용자 공간)
커널이 노출하는 /dev/watchdog로 제어합니다.
간단 C 예시
#include <linux/watchdog.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdio.h>
int main() {
int fd = open("/dev/watchdog", O_WRONLY);
int timeout = 10; // 10초
ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
while (1) {
// 주기적으로 keepalive
ioctl(fd, WDIOC_KEEPALIVE, 0);
sleep(5);
}
// 일부 드라이버는 'V'를 쓰고 닫아야 리부트 방지
write(fd, "V", 1);
close(fd);
return 0;
}
주의: 단순 close()가 즉시 리부트 트리거가 될 수 있음(드라이버마다 다름). “magic close”("V") 또는 WDIOC_SETOPTIONS로 DISABLE 후 종료.
systemd 통합
서비스 유닛에 WatchdogSec=15s 설정 후, 프로세스가 주기적으로 sd_notify("WATCHDOG=1") 보내면 systemd가 죽은 프로세스를 재시작.
- 장점: 프로세스 단위 감시
- 단점: 커널/하드락까지는 못 잡음 → 하드웨어 WDT와 병행 권장
MCU(예: STM32)에서의 Watchdog
- IWDG: LSI로 구동, 메인 클럭 고장에도 작동. 개발 중엔 마진 크게.
- WWDG: 윈도우 내에서만 Feed → 타이밍 이상까지 탐지.
- 리셋 원인 확인:
- if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) { // 이전 리셋이 IWDG 때문 } __HAL_RCC_CLEAR_RESET_FLAGS();
보안·안전 관점
- Fail-safe 설계: 장애 발생 시 안전한 동작 상태(밸브 닫기, 모터 정지 등)로 전환되도록 부팅 로직/하드웨어 릴레이 설계.
- 표준: 자동차(ISO 26262), 항공(DO-178C) 등은 독립 클럭 WDT + 외부 슈퍼바이저 조합, 부트 카운터/세이프모드 등 요구가 일반적.
요약
- Watchdog = “살아있다” 신호를 못 받으면 시스템을 강제로 재부팅하는 최후의 안전장치.
- 제대로 쓰려면 하트비트 집계, 윈도우 타이밍, 로그/세이프모드, 저전력·블로킹 고려가 핵심.
- **HW WDT(칩 내부/외부)**로 최종 보장을 하고, 필요하면 systemd/소프트 WDT를 보조로 겹겹이 설계하면 신뢰성이 크게 올라갑니다.
원하시면, 지금 사용 중인 보드/OS(예: RV1106 Linux, T527 Android, STM32 등)를 알려주세요. 그 환경에 맞춘 구체 타임아웃 수치·초기화 코드·하트비트 설계도를 바로 맞춰 드릴게요.
'잡동사니 > GPT가 알려주는' 카테고리의 다른 글
| [GPT가 알려주는] 오디오 코덱이란? (0) | 2025.09.12 |
|---|---|
| [GPT가 알려주는 Springboot] gradlew.bat 실행해서 실행파일 만드는 법 (0) | 2025.09.12 |
| [GPT가 알려주는] NEON과 FPU (0) | 2025.09.12 |
| [GPT가 알려주는] EC (Echo Cancellation), NS (Noise Suppression), Beamformer (빔포머, 마이크 배열 지향성 처리) (0) | 2025.09.12 |
| [GPT가 알려주는] 포팅이란? (0) | 2025.09.12 |