Vì sao ISR không được dùng Mutex trong FreeRTOS?
Giải thích vì sao ISR không được block và vì sao Mutex thường không phù hợp trong interrupt context của FreeRTOS/CMSIS-RTOS.
Ghi chú nhanh
ISR không nên dùng Mutex thường vì Mutex sinh ra cho task context, nơi một task có thể chờ, nhường CPU, rồi được scheduler đánh thức lại sau.
ISR thì khác. ISR phải chạy nhanh, dứt khoát, không đứng chờ ai cả.
Task context → có thể block/chờ Mutex
ISR context → không được block
Nếu ISR mà cũng ngồi chờ Mutex thì giống như đang xử lý cháy nhà nhưng lại xếp hàng lấy số thứ tự. Firmware real-time không thích kiểu lịch sự đó.
Khi nào bạn sẽ đụng lỗi này?
Lỗi này thường không xuất hiện lúc code còn đơn giản. Nó hay xuất hiện khi bạn bắt đầu “tiện tay” dùng chung một API cho cả task và callback interrupt.
Ví dụ:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
Debug_Printf("RX done
"); // nguy hiểm nếu Debug_Printf dùng mutex
}
Nếu Debug_Printf() bên trong có lock Mutex, cấp phát động, hoặc chờ UART rảnh, callback này có thể làm hệ thống bị treo rất khó đoán.
Vì sao ISR không được block?
ISR chạy ở interrupt context. Trong lúc ISR đang chạy, nhiều cơ chế bình thường của task không hoạt động theo cách bạn nghĩ.
Một ISR dài hoặc bị kẹt có thể gây ra:
- mất interrupt khác;
- tăng interrupt latency;
- task quan trọng bị trễ;
- watchdog reset;
- bug chỉ xảy ra “thỉnh thoảng”, rất khó tái hiện.
Đây là kiểu bug mà log càng thêm nhiều thì nó càng biến mất hoặc càng nặng hơn. Debug rất vui, theo nghĩa không vui chút nào.
Cách xử lý đúng hơn
Thay vì dùng một API cho mọi nơi, nên tách rõ:
Task API → có thể dùng mutex, queue thường, timeout
ISR API → dùng API FromISR hoặc chỉ set flag / ghi buffer ngắn
Ví dụ hướng thiết kế:
void Debug_LogFromTask(const char *msg);
void Debug_LogFromISR(const char *msg);
Trong ISR, hãy làm ít nhất có thể:
void EXTI_Callback(void)
{
BaseType_t higher_woken = pdFALSE;
xQueueSendFromISR(log_queue, &event, &higher_woken);
portYIELD_FROM_ISR(higher_woken);
}
Checklist khi review code
Cách nhớ
Task được phép chờ.
ISR chỉ nên báo hiệu rồi đi ra.
Bài liên quan nên đọc tiếp
- Producer-Consumer pattern trong hệ thống logging embedded
- Thiết kế hệ thống UART logging non-blocking trên STM32
Thấy nội dung này hữu ích?
Lưu lại hoặc chia sẻ cho người cũng đang học firmware, BIOS/UEFI và embedded systems.
Nội dung liên quan
Một số bài viết, ghi chú hoặc project có liên quan đến nội dung bạn vừa đọc.
FreeRTOS trên STM32: Task, Queue, Signal và cách tổ chức firmware cho cả team
Triển khai dự án FreeRTOS trên STM32.
UART non-blocking logger trên STM32 với DMA + Ring Buffer
Thiết kế debug UART non-blocking cho STM32: tránh printf, xử lý mất log với DMA, dùng ring buffer và DMA callback.
STM32 Non-Blocking UART Logger
Case study thiết kế module logging non-blocking cho STM32, hỗ trợ UART DMA, Ring Buffer, bare-metal, FreeRTOS và production build mode.
Biến note thành bài viết hoàn chỉnh
Notes là nơi ghi nhanh khái niệm.