BSP Thermal과 Watchdog — Trip Point·Cooling Device·Hardware Reset
#한 줄 요약
Thermal과 watchdog은 최후의 안전망입니다. 부팅 후 software가 정상 동작하지 않거나 칩이 너무 뜨거워졌을 때, 사용자 개입 없이 시스템을 보호하는 마지막 메커니즘입니다. BSP가 이 둘을 빠뜨리면 양산 후 필드에서 “왜 갑자기 보드가 죽었는가”를 영원히 추적하게 됩니다.
여름철 차량 내부 70°C, 산업 현장 먼지 속의 fanless 보드, 무인 키오스크의 24시간 운용 — 임베디드는 사람이 옆에 없는 환경에서 동작하는 경우가 많습니다. 그래서 BSP의 마지막 챕터는 시스템의 자기 보호 능력입니다. thermal framework가 발열을 다스리고, watchdog이 hang을 끊습니다.
#Thermal framework 구조
#DT의 thermal-zones
i.MX8M Mini를 예로 듭니다.
thermal-zones { cpu-thermal { polling-delay-passive = <250>; polling-delay = <2000>; thermal-sensors = <&tmu>;
trips { cpu_alert0: trip0 { temperature = <85000>; /* 85 °C */ hysteresis = <2000>; type = "passive"; };
cpu_alert1: trip1 { temperature = <95000>; /* 95 °C */ hysteresis = <2000>; type = "hot"; };
cpu_crit: trip2 { temperature = <105000>; /* 105 °C */ hysteresis = <2000>; type = "critical"; }; };
cooling-maps { map0 { trip = <&cpu_alert0>; cooling-device = <&A53_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, <&A53_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, <&A53_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, <&A53_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; }; };};| trip type | 동작 |
|---|---|
active | fan 같은 능동 냉각 가동 |
passive | CPU throttling (DVFS down) |
hot | 경고 알림, userspace 통보 |
critical | 강제 shutdown |
critical trip은 반드시 한 개 이상 있어야 합니다. 이 값을 넘으면 커널이 emergency_restart()를 호출합니다.
#Cortex-A 등급별 최대 온도
칩 등급에 따라 허용 온도가 다릅니다.
| 등급 | 동작 범위 (Tj) | critical 권장 |
|---|---|---|
| Commercial | 0 ~ 95°C | 90 °C |
| Industrial | -40 ~ 105°C | 100 °C |
| Automotive AEC-Q100 Grade 3 | -40 ~ 125°C | 115 °C |
| Automotive AEC-Q100 Grade 2 | -40 ~ 105°C | 100 °C |
부품 datasheet의 Tj_max를 확인하고, 그 값보다 5~10°C 낮게 critical trip을 둡니다. ambient와 internal의 thermal lag을 감안한 마진입니다.
#동작 확인
$ ls /sys/class/thermal/cooling_device0 cooling_device1 thermal_zone0
$ cat /sys/class/thermal/thermal_zone0/typecpu-thermal
$ cat /sys/class/thermal/thermal_zone0/temp58234 # 58.234 °C
$ cat /sys/class/thermal/thermal_zone0/trip_point_0_temp85000
$ cat /sys/class/thermal/thermal_zone0/trip_point_2_typecritical
$ cat /sys/class/thermal/cooling_device0/typethermal-cpufreq-0
$ cat /sys/class/thermal/cooling_device0/cur_state0 # 0 = no throttling$ cat /sys/class/thermal/cooling_device0/max_state3cooling device의 cur_state가 증가하면 그만큼 cpufreq가 낮아집니다.
#Thermal governor
| governor | 알고리즘 |
|---|---|
step_wise | 한 단계씩 throttle/release |
fair_share | 여러 cooling device에 분배 |
bang_bang | hysteresis 기반 ON/OFF |
user_space | userspace daemon이 정책 결정 |
power_allocator | power budget 기반 (PID 제어) |
기본은 step_wise이며, 정밀 제어가 필요하면 power_allocator로 바꿉니다.
thermal-zones { cpu-thermal { thermal-governor = "power_allocator"; sustainable-power = <1500>; /* ... */ };};확인:
$ cat /sys/class/thermal/thermal_zone0/policystep_wise$ cat /sys/class/thermal/thermal_zone0/available_policiesbang_bang fair_share power_allocator step_wise user_space$ echo power_allocator > /sys/class/thermal/thermal_zone0/policy#외부 sensor와 cooling device
칩 내부 sensor만으로 부족하면 외부 thermistor, fan, peltier 등을 추가합니다.
/* i2c thermistor */&i2c1 { tmp103@70 { compatible = "ti,tmp103"; reg = <0x70>; #thermal-sensor-cells = <0>; };};
/* fan via PWM */fan0: pwm-fan { compatible = "pwm-fan"; pwms = <&pwm1 0 40000 0>; cooling-levels = <0 102 170 255>; /* PWM duty */ #cooling-cells = <2>;};
thermal-zones { case-thermal { polling-delay-passive = <1000>; polling-delay = <5000>; thermal-sensors = <&tmp103>;
trips { case_active: trip0 { temperature = <60000>; hysteresis = <2000>; type = "active"; }; };
cooling-maps { map0 { trip = <&case_active>; cooling-device = <&fan0 0 3>; /* fan level 0~3 */ }; }; };};#hwmon 통합
thermal sensor가 hwmon으로도 노출됩니다.
$ sensorsimx8mm_thermal-virtual-0Adapter: Virtual devicetemp1: +58.2°C (high = +85.0°C, crit = +105.0°C)
tmp103-i2c-1-70Adapter: i.MX I2C adapter 1temp1: +32.1°C (low = -55.0°C, high = +127.0°C)lm-sensors 패키지의 sensors 명령이 표준입니다.
#Watchdog — 자기 reset 메커니즘
Watchdog은 주기적으로 키워주지 않으면 시스템을 reset하는 timer입니다. software hang 시 마지막 안전망입니다.
[watchdog timer] ├─ enable ├─ timeout 설정 (예: 60 s) └─ tick
[application] └─ 매 N초마다 WDIOC_KEEPALIVE ioctl ↓ watchdog 카운터 초기화
만약 application이 hang → KEEPALIVE 안 옴 → timeout → reset#/dev/watchdog 사용
#include <fcntl.h>#include <linux/watchdog.h>#include <sys/ioctl.h>#include <unistd.h>
int main(void){ int fd = open("/dev/watchdog", O_WRONLY); if (fd < 0) { perror("open"); return 1; }
/* timeout 30초 설정 */ int timeout = 30; ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
/* 활성화 */ int options = WDIOS_ENABLECARD; ioctl(fd, WDIOC_SETOPTIONS, &options);
while (1) { sleep(10); /* keepalive */ ioctl(fd, WDIOC_KEEPALIVE, NULL); }
/* close하면 watchdog stop. 'V'를 쓴 후에야 stop 허용 */ write(fd, "V", 1); close(fd); return 0;}WDIOC_KEEPALIVE 외에 어떤 데이터든 fd에 쓰면 keepalive 효과를 냅니다. 단, ‘V’ 문자열을 보낸 후 close하면 명시적 종료로 처리되어 watchdog이 멈춥니다.
#systemd watchdog 통합
systemd가 PID 1로서 watchdog을 직접 잡아 줍니다.
[Manager]RuntimeWatchdogSec=30ShutdownWatchdogSec=10min
[Service]WatchdogSec=10sRuntimeWatchdogSec=30은 systemd가 /dev/watchdog을 잡고 매 ~15초마다 키워줍니다. 서비스 단위의 WatchdogSec은 그 서비스가 systemd에 sd_notify로 신호를 보내야 하는 주기입니다.
#include <systemd/sd-daemon.h>
void worker_loop(void){ while (1) { do_work(); sd_notify(0, "WATCHDOG=1"); /* systemd에 신호 */ usleep(5000000); }}서비스가 hang하면 systemd가 그 서비스를 restart하고, systemd 자체가 hang하면 kernel watchdog이 reset.
#DT binding
&wdog1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_wdog>; fsl,ext-reset-output; /* WDOG_B 핀으로 외부 reset 신호 출력 */ status = "okay"; timeout-sec = <30>;};timeout-sec은 기본 timeout. fsl,ext-reset-output이 있으면 internal reset이 아닌 외부 reset 라인을 toggle합니다. PMIC 등을 통해 보드 전체를 reset할 때 필요합니다.
#boot-time watchdog
부팅이 너무 오래 걸리면 reset하는 메커니즘입니다. SPL이 watchdog을 켜고 timeout을 짧게(예: 120초) 둡니다. U-Boot proper, kernel 부팅을 거쳐 systemd가 watchdog을 인계받기 전까지 멈추지 않게 됩니다.
U-Boot:
- WDT: Started watchdog@30280000 with servicing (60s timeout)
U-Boot가 watchdog을 서비싱하면서 부팅을 진행합니다. 부팅 단계 어디서든 hang하면 watchdog이 reset해 재부팅 루프를 만듭니다. 이 루프 자체는 정상 동작입니다 — fail-safe 설계가 의도한 동작입니다.
#측정과 검증
#thermal 스트레스 테스트
# 부하 발생$ stress-ng --cpu $(nproc) --timeout 600s &
# 다른 터미널에서 모니터링$ while true; do cat /sys/class/thermal/thermal_zone0/temp cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq sleep 1 donepassive trip에 도달하면 frequency가 단계적으로 떨어지는지 확인합니다.
#watchdog 동작 테스트
# watchdog을 잡고 의도적으로 keepalive 멈춤echo 1 > /dev/watchdogsleep 30 # 또는 timeout 만큼 대기# → reset 발생해야 함부팅 후 dmesg에 reset 원인을 확인:
$ cat /proc/reset-reason # 보드별watchdog_reset
$ dmesg | grep -i wdog[ 0.123456] imx2-wdt 30280000.watchdog: timeout 30 sec (nowayout=0)[ 0.234567] imx2-wdt 30280000.watchdog: Last reset was caused by watchdog#자주 하는 실수
- critical trip 누락: critical 없이는 진짜 위급 상황에서 shutdown이 안 됩니다.
- DT의 thermal-zones 누락: sensor는 동작하지만 throttling이 안 됩니다. dmesg에
no thermal-zones found경고. - cooling device map 누락: throttle해야 할 cpu를 지정 안 하면 발열만 측정하고 대응 없음.
- wdt가 비활성:
CONFIG_WATCHDOG=y만 켜고CONFIG_<vendor>_WATCHDOG=y가 없어 드라이버 미사용. - systemd RuntimeWatchdogSec 미설정:
/dev/watchdog존재해도 누가 keepalive 안 함. - wdt timeout이 너무 짧음: 부팅이 30초인데 timeout이 20초면 영원히 부팅 못 함.
fsl,ext-reset-output없는 PMIC reset 의존: 내부 reset만 동작해 PMIC가 안 끊기면 잔존 상태로 부팅.
#정리
- Thermal framework는 sensor, zone, trip point, cooling device의 4개 레이어로 구성됩니다.
- DT의
thermal-zones가 zone과 trip을 선언하고,cooling-maps가 trip과 cooling device를 연결합니다. - trip type은 active, passive, hot, critical이며 critical은 반드시 한 개 있어야 합니다.
- Cortex-A 등급별 Tj_max를 기준으로 critical을 5~10°C 마진 두고 설정합니다.
- thermal governor는 step_wise가 기본이며 정밀 제어는 power_allocator를 씁니다.
- Watchdog은
/dev/watchdog을 통해WDIOC_KEEPALIVE로 키워 주는 timer입니다. - systemd의
RuntimeWatchdogSec이 PID 1 차원에서 watchdog을 자동 운용합니다. - 부팅 hang 보호를 위해 SPL/U-Boot부터 watchdog을 켜고 부팅 단계에서 keepalive를 유지합니다.
#다음 편 예고
이 글은 BSP Development 시리즈의 마지막 챕터입니다. 다음 시리즈로 Buildroot로 첫 이미지 만들기 또는 Practical RTOS Internals를 추천합니다. BSP가 완성되면 이미지 빌드와 양산 펌웨어 관리가 다음 관심사입니다.
#관련 항목
- Ch 12: 드라이버 추가 — sensor driver 통합
- Ch 13: Power Management — DVFS와 thermal 연동
- Buildroot로 첫 이미지 만들기 — systemd 설정
- Modern Embedded Recipes — 양산 안전 설계
- Embedded Performance Engineering — thermal과 성능의 트레이드오프
- Practical RTOS Internals — watchdog 패턴 비교
BSP Development · 14 of 21
- 1BSP의 본질 분해 — 새 보드 부팅을 위한 코드의 자리
- 2SoC 데이터시트 읽기 — Pin Mux·Clock·Memory Map 파악법
- 3새 보드 Device Tree 설계 — node·property·phandle 작성 흐름
- 4Pin Mux와 Clock Tree 분석 — 보드 부팅의 첫 두 관문
- 5DDR 매개변수 결정 — 보드별 Timing·Training 추출
- 6U-Boot 새 보드 포팅 — defconfig·board.c·DTS 작성 흐름
- 7TF-A·TrustZone 통합 — BL31·secure world·SMC 흐름 적용
- 8Linux 커널 BSP 설정 — defconfig·Kconfig·DT 통합
- 9Multi-core SMP Bring-up — PSCI·Secondary CPU 깨우기
- 10첫 부팅 추적 — 0%부터 login prompt까지의 단계 분석
- 11부트로그 디버깅 — earlyprintk·loglevel·serial 추적
- 12BSP 드라이버 추가 — 보드별 Peripheral 통합 흐름
- 13BSP Power Management — Suspend/Resume·Runtime PM·Regulator
- 14BSP Thermal과 Watchdog — Trip Point·Cooling Device·Hardware Reset
- 15BSP 부트 시간 최적화 — Bootchart·initcall_debug·Parallel Init
- 16BSP RootFS 통합 — Buildroot·Yocto와 보드별 패키지 묶기
- 17BSP 이미지 패키징 — Flash Layout·Partition·GPT 설계
- 18BSP OTA와 Field Recovery — A/B 슬롯·롤백·BootCount
- 19BSP Stability Testing — Stress·Soak·Power Cycle 시나리오
- 20BSP 양산 환경 구축 — CI/CD·재현 가능 빌드·서명
- 21BSP 유지보수 — 업스트림 기여·커널 버전업·LTS 전략
관련 글
이 글을 참조하는 글 (5)
- Buildroot OTA 이미지 업데이트 — RAUC·swupdate 통합— Buildroot Practical
- BSP Stability Testing — Stress·Soak·Power Cycle 시나리오— BSP Development
- BSP 부트 시간 최적화 — Bootchart·initcall_debug·Parallel Init— BSP Development
- BSP Power Management — Suspend/Resume·Runtime PM·Regulator— BSP Development
- BSP 드라이버 추가 — 보드별 Peripheral 통합 흐름— BSP Development