Nâng cao8 phút đọc08/10/2026

Firmware fail-safe: watchdog phần cứng, brown-out, và trạng thái an toàn mặc định

Thiết kế cơ chế khôi phục khi mất nguồn hoặc treo firmware, đảm bảo thiết bị luôn trở về trạng thái an toàn đã định nghĩa trước.

Firmware fail-safe: watchdog phần cứng, brown-out, và trạng thái an toàn mặc định
Mục lục bài viết8 ▼
  1. Vì sao watchdog phần mềm không đủ
  2. Thiết kế watchdog phần cứng đúng cách
  3. Phát hiện và xử lý brown-out (sụt áp)
  4. Trạng thái an toàn mặc định (safe default state) là gì
  5. Trình tự khởi động lại sau reset bất thường
  6. Lỗi thường gặp khi làm thật
  7. Checklist khi thiết kế
  8. Đọc tiếp

Thiết bị treo giữa đêm, không ai thao tác, mất điện giữa chu kỳ ghi flash — những tình huống này không được xử lý bằng try/catch mà bằng mạch cứng và quy tắc thiết kế rõ ràng từ trước. Bài này dành cho kỹ sư firmware và kỹ sư phần cứng đang thiết kế lớp fail-safe cho thiết bị chạy ngoài hiện trường, nơi không có người đứng cạnh để nhấn nút reset.

#Vì sao watchdog phần mềm không đủ

Watchdog phần mềm — thường là một task FreeRTOS tự định kỳ "nạp lại" một biến đếm hoặc timer — chỉ hoạt động nếu scheduler và task đó còn sống. Nếu lỗi gây treo nằm ở chính chỗ scheduler bị kẹt (deadlock giữa mutex, ISR vòng lặp vô hạn, stack overflow đè lên vùng nhớ hệ thống), watchdog phần mềm cũng chết theo — không ai nuôi, nhưng cũng không ai kích hoạt reset vì cơ chế reset đó vẫn phải chạy qua đúng những thành phần đã treo.

Watchdog phần cứng (thường gọi IWDG — Independent Watchdog, hoặc WDT tuỳ họ MCU) giải quyết đúng lỗ hổng này: nó chạy trên clock riêng, độc lập với clock hệ thống và core CPU, và việc reset MCU được thực hiện bằng mạch logic riêng, không phụ thuộc RTOS còn chạy hay không. Đây là lớp bảo vệ cuối cùng, không phải lớp đầu tiên.

Cần phân biệt rõ hai cấp giám sát:

CấpGiám sát gìHành động khi lỗi
Watchdog cấp taskTừng task có "sống" đúng chu kỳ không (heartbeat)Log, cảnh báo, có thể tự phục hồi task
Watchdog cấp hệ thống (phần cứng)Toàn mạch MCU có đáp ứng khôngReset cứng toàn hệ thống

Hai cấp này không thay thế nhau — cấp task phát hiện sớm và chi tiết, cấp hệ thống là lưới an toàn cuối khi cấp task cũng không còn chạy.

Cần: bảng so sánh IWDG độc lập vs WWDG, theo datasheet của MCU cụ thể đang dùng

#Thiết kế watchdog phần cứng đúng cách

Timeout của watchdog không nên là một số "nhìn có vẻ hợp lý". Nguyên tắc: lấy thời gian thực thi của task hợp lệ dài nhất trong hệ thống (ví dụ task ghi flash, task xử lý OTA chunk), cộng biên an toàn — ví dụ gấp 1,5–2 lần (ví dụ minh hoạ) — rồi mới chọn giá trị timeout gần nhất mà phần cứng hỗ trợ.

Watchdog phải được nuôi từ một task giám sát tổng hợp, không nuôi trực tiếp từ ISR định kỳ và không để task bất kỳ tự tiện gọi lệnh nuôi. Task giám sát này có nhiệm vụ kiểm tra heartbeat của các task con khác (mỗi task con tự cập nhật một timestamp hoặc cờ "còn sống" vào biến dùng chung, có bảo vệ bằng mutex hoặc atomic), chỉ khi tất cả task con báo sống đúng hạn thì mới nạp lại watchdog phần cứng.

C
/* Minh hoạ, chưa biên dịch — ý tưởng task giám sát tổng hợp */
void vWatchdogMonitorTask(void *pv) {
    for (;;) {
        bool all_alive = true;
        for (int i = 0; i < TASK_COUNT; i++) {
            if (xTaskGetTickCount() - g_heartbeat[i] > HEARTBEAT_TIMEOUT_TICKS) {
                all_alive = false;
                break;
            }
        }
        if (all_alive) {
            HAL_WDT_Refresh(); /* tên hàm minh hoạ, không phải API thật của MCU cụ thể */
        }
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

Nếu MCU hỗ trợ early-warning interrupt (ngắt báo trước khi watchdog hết hạn, còn gọi window hoặc pre-warning interrupt tuỳ dòng chip), nên dùng để ghi log nguyên nhân nghi vấn (task nào không heartbeat, trạng thái stack) vào bộ nhớ non-volatile trước khi reset cứng xảy ra — việc này quyết định có debug được sự cố thực địa hay không.

Cần: sơ đồ task giám sát + đoạn code cấu hình watchdog (giả định, ghi rõ là ví dụ minh họa)

#Phát hiện và xử lý brown-out (sụt áp)

Brown-out detector (BOD) giám sát điện áp cấp nguồn MCU và kích hoạt reset khi điện áp xuống dưới ngưỡng. Ngưỡng BOD phải được chọn thấp hơn điện áp hoạt động tối thiểu của flash và lõi MCU theo datasheet — nếu đặt sai, MCU có thể tiếp tục chạy ở điện áp không đủ để ghi flash tin cậy, dẫn đến dữ liệu ghi dở bị hỏng mà không có cảnh báo.

Khi BOD kích hoạt, firmware (ở mức ISR, không chờ task scheduler) cần:

  • Hủy ngay thao tác ghi flash đang chạy nếu còn kịp can thiệp
  • Đánh dấu trạng thái "ghi chưa hoàn tất" vào vùng bộ nhớ còn ghi được, để lần boot sau kiểm tra và rollback nếu cần
  • Không cố gắng ghi thêm log chi tiết vào flash lúc này — việc ghi log ở điện áp thấp cũng có rủi ro tương tự

Thiết kế tụ dự phòng hoặc nguồn backup (ví dụ tụ điện dung lớn, hoặc siêu tụ) phải đủ thời gian để MCU hoàn tất xử lý brown-out an toàn — tức là đủ cho khoảng thời gian từ lúc BOD kích hoạt đến lúc điện áp xuống dưới ngưỡng hoạt động tối thiểu — giá trị tụ cụ thể phải tính theo dòng tải và mạch nguồn thực tế của từng thiết kế.

Cần: thông số BOD threshold trích từ datasheet MCU, mục/trang cụ thể

#Trạng thái an toàn mặc định (safe default state) là gì

Trước khi viết code, cần định nghĩa: khi thiết bị mất kiểm soát (treo, mất nguồn, reset bất ngờ), từng ngõ ra — relay, van, động cơ — phải về trạng thái nào. Đây không phải lúc code mới quyết định, mà là quyết định thiết kế hệ thống cần văn bản hoá trước.

Trạng thái an toàn phải được đảm bảo bằng cả hai lớp:

  • Phần cứng: điện trở pull-up/pull-down đúng hướng tại chân GPIO, mạch chốt (latch) cơ khí nếu cần, để khi MCU chưa chạy (đang boot, đang reset) ngõ ra tự về đúng trạng thái mà không cần lệnh nào
  • Phần mềm: code khởi tạo GPIO đúng trạng thái ngay dòng đầu tiên có thể, không chờ đến khi hệ thống "sẵn sàng" mới set

Không phải lúc nào OFF cũng là an toàn. Với van xả áp an toàn (relief valve), trạng thái an toàn có thể là mở để tránh tích áp; với động cơ nâng, trạng thái an toàn có thể là giữ phanh chứ không phải ngắt điện hoàn toàn (nếu ngắt điện làm mất phanh điện từ). Mỗi ngõ ra cần được đánh giá riêng theo đặc tính cơ khí của tải, không áp dụng mặc định chung cho toàn hệ thống.

Cần: bảng mapping từng ngõ ra → trạng thái an toàn mặc định, theo tài liệu thiết kế hệ thống

#Trình tự khởi động lại sau reset bất thường

Ngay sau reset, bước đầu tiên là đọc cờ nguyên nhân reset (reset-cause flag) từ thanh ghi dành riêng cho mục đích này — tên thanh ghi cụ thể tra theo datasheet của MCU đang dùng — phân biệt watchdog reset, brown-out reset, hay power-on reset bình thường. Thông tin này cần được log vào bộ nhớ non-volatile trước khi làm gì khác, vì đây là manh mối duy nhất để debug sự cố thực địa sau này.

Trước khi khởi động lại các task điều khiển, firmware phải chủ động đưa toàn bộ ngõ ra về trạng thái an toàn mặc định — không giả định phần cứng đã tự làm đúng, kể cả khi đã có pull-up/down, vì một số cấu hình GPIO có thể bị thay đổi bởi code cũ chạy trước khi treo.

Cần giới hạn số lần reset liên tiếp trong khoảng thời gian ngắn (cơ chế chống boot-loop): nếu MCU reset quá một số lần cho phép trong một khoảng thời gian ngắn (ngưỡng cụ thể do yêu cầu hệ thống quyết định), chuyển sang chế độ an toàn kéo dài (safe-hold mode) thay vì tiếp tục thử khởi động bình thường — tránh dao động nguồn hoặc lỗi phần cứng gây reset liên tục làm hệ thống kẹt ở trạng thái không xác định.

Cần: lưu đồ trình tự boot sau reset, kèm tên thanh ghi reset-cause theo datasheet

#Lỗi thường gặp khi làm thật

  • Nuôi watchdog từ ISR định kỳ (timer interrupt): ISR vẫn chạy đều đặn dù task chính đã treo hoàn toàn, khiến watchdog hoàn toàn mất tác dụng — đây là lỗi thiết kế phổ biến nhất, biến watchdog phần cứng thành vật trang trí.
  • Không lưu nguyên nhân reset vào bộ nhớ non-volatile trước khi reset xảy ra: khi sự cố xảy ra ngoài hiện trường, không có cách nào biết nguyên nhân là watchdog, brown-out, hay lỗi khác — mất hoàn toàn khả năng debug từ xa.
  • Thiết kế an toàn mặc định chỉ ở lớp phần mềm: bỏ qua việc trong khoảng thời gian MCU đang boot hoặc đang reset (chưa chạy code), phần cứng phải tự đảm bảo trạng thái đúng — nếu không có pull-up/down đúng hướng, ngõ ra có thể ở trạng thái không xác định (floating) trong khoảng thời gian đó, đủ để gây sự cố với tải có đáp ứng nhanh.

#Checklist khi thiết kế

  • Watchdog phần cứng độc lập được bật, timeout tính toán có biên an toàn rõ ràng
  • BOD threshold phù hợp với yêu cầu điện áp tối thiểu ghi flash
  • Mọi ngõ ra có trạng thái an toàn mặc định xác định bằng cả phần cứng và phần mềm
  • Cờ reset-cause được đọc, log, và dùng để quyết định luồng khởi động
  • Có cơ chế chống boot-loop
  • Đã kiểm thử thực tế: rút nguồn giữa lúc ghi flash, treo task cố ý để xem watchdog phản ứng

#Đọc tiếp

Bài kế tiếp trong series: "Giám sát thiết bị thực địa: log cấu trúc, health-check định kỳ, và cảnh báo sớm trước khi hỏng".