Bài viết 14 thuộc series STM32F103C8T6 tập trung theo hướng “học để làm được việc”. Với chủ đề NVIC và quản lý ưu tiên ngắt trên STM32F103C8T6, bạn sẽ đi từ lý thuyết cốt lõi đến quy trình triển khai thực tế trong phòng lab. Nội dung được thiết kế để sinh viên, kỹ thuật viên bảo trì và người mới chuyển từ PLC sang Embedded đều có thể áp dụng ngay vào project mẫu.
Hệ thống nhiều ngắt dễ rơi vào trạng thái khó debug nếu thiếu chiến lược ưu tiên rõ ràng. NVIC không chỉ là tham số cấu hình, mà là kiến trúc điều phối thời gian thực của toàn bộ firmware.
1. Mục tiêu bài học
Bài giúp bạn xây tư duy phân tầng ngắt theo mức độ khẩn cấp và hậu quả khi trễ, từ đó vận hành ổn định cả trong điều kiện tải cao.
- Hiểu preemption priority và subpriority.
- Thiết kế bảng ưu tiên ngắt cho ứng dụng đa ngoại vi.
- Giữ ISR ngắn và tránh deadlock giữa các ngắt.
- Đo tác động của ưu tiên ngắt tới độ trễ hệ thống.
Sau khi hoàn thành, bạn nên tự trả lời được ba câu hỏi: hệ thống cần đo/điều khiển đại lượng gì, vòng đời xử lý dữ liệu chạy theo chu kỳ nào, và cơ chế bảo vệ lỗi nào cần có để hệ thống ổn định khi chạy liên tục ngoài hiện trường.
2. Kiến thức nền tảng
STM32F103C8T6 dùng lõi ARM Cortex-M3, phù hợp để học đồng thời kiến trúc MCU và phương pháp lập trình thời gian thực. Khi học theo lộ trình chuẩn, bạn nên nắm đồng thời phần cứng (clock, GPIO, bus, nguồn), firmware (HAL/LL, ngắt, timer), và phương pháp test (scope, logic analyzer, UART log). Việc kết hợp đủ ba lớp kiến thức giúp quá trình debug nhanh hơn nhiều so với chỉ học code thuần.
- Latency và interrupt nesting.
- Khái niệm critical section trong firmware nhúng.
- Ảnh hưởng của hàm blocking trong ISR.
- Theo dõi ngắt bằng timestamp và log sự kiện.
Trong quá trình thực hành, bạn nên duy trì checklist kiểm thử ở từng vòng: xác nhận wiring, xác nhận xung clock, xác nhận trạng thái ngoại vi, sau đó mới kiểm tra thuật toán. Cách làm này giảm đáng kể lỗi dây chuyền và giúp nhóm dự án phối hợp hiệu quả giữa phần cứng và phần mềm.
3. Phân tích kỹ thuật
Phân loại ngắt theo mức quan trọng
Ngắt nên được phân loại theo hậu quả khi trễ: mức an toàn, mức điều khiển cứng, mức truyền thông và mức giao diện. Cách phân loại này giúp ưu tiên có cơ sở kỹ thuật thay vì cảm tính.
- An toàn/hard deadline: ưu tiên cao.
- Truyền thông có buffer: ưu tiên trung bình.
- Giao diện người dùng: ưu tiên thấp hơn.
Tránh đảo ưu tiên và nghẽn ngắt
Nếu ISR thấp ưu tiên nhưng chạy quá dài, nó vẫn có thể gây nghẽn luồng chính. Ngoài ra, dùng mutex hoặc resource chung không kiểm soát giữa ISR và main dễ gây lỗi khó tái hiện.
- Không gọi printf blocking trong ISR.
- Dùng flag/queue để chuyển xử lý về nền.
- Giới hạn thời gian thực thi ISR bằng code review.
Kiểm thử thiết kế ưu tiên ngắt
Thiết kế ưu tiên đúng phải được kiểm thử dưới tải cao: tăng tần suất ngắt, tạo burst dữ liệu, đo độ trễ phản hồi. Chỉ khi vượt qua bài test tải thì cấu hình mới thực sự đáng tin cậy.
- Ghi timestamp vào bộ đệm vòng để phân tích.
- Mô phỏng tình huống xấu nhất trong phòng lab.
- Điều chỉnh dần priority và so sánh kết quả.
Từ góc nhìn hệ thống, chủ đề này không chỉ là “chạy được chức năng”, mà còn là bài toán tối ưu độ tin cậy, độ trễ xử lý, khả năng mở rộng khi thêm cảm biến hoặc thêm kênh truyền thông. Nếu ngay từ đầu bạn chuẩn hóa cấu trúc code theo module driver/app/service thì giai đoạn mở rộng về sau sẽ nhẹ hơn rất nhiều.
4. Các bước thực hiện
Trước khi set priority, hãy vẽ sơ đồ luồng sự kiện và định nghĩa deadline cho từng ngắt.
- Liệt kê toàn bộ nguồn ngắt trong hệ thống.
- Định nghĩa mức ưu tiên theo deadline và mức độ ảnh hưởng.
- Cấu hình NVIC grouping và priority trong code.
- Refactor ISR để chỉ giữ xử lý tối thiểu.
- Tạo test tải cao để đo latency từng ngắt.
- Khóa cấu hình ưu tiên vào tài liệu dự án.
Ở mỗi bước, bạn nên lưu log kỹ thuật (ảnh wiring, ảnh cấu hình CubeMX, thông số timer/UART/ADC, snapshot kết quả đo). Bộ log này giúp giảng viên hoặc trưởng nhóm đánh giá tiến độ nhanh và giảm thời gian trao đổi khi cần hỗ trợ từ xa.
5. Ví dụ thiết lập ưu tiên ngắt cơ bản
Code dưới đây là mẫu rút gọn theo HAL Library, tập trung phần cốt lõi để bạn nhìn rõ luồng xử lý. Khi đưa vào dự án thực, hãy tách code thành các module rõ ràng, thêm kiểm tra lỗi trả về và timeout cho mọi giao tiếp ngoại vi.
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
HAL_NVIC_SetPriority(TIM2_IRQn, 1, 0); // tác vụ thời gian cứng
HAL_NVIC_SetPriority(USART1_IRQn, 2, 0); // truyền thông
HAL_NVIC_SetPriority(EXTI0_IRQn, 3, 0); // nút nhấn / UI
HAL_NVIC_EnableIRQ(TIM2_IRQn);
HAL_NVIC_EnableIRQ(USART1_IRQn);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
Nguyên tắc quan trọng: giữ hàm ngắt ngắn gọn, xử lý nặng chuyển về vòng lặp chính hoặc task nền; dùng biến trạng thái rõ ràng để tránh race condition; thêm timeout cho mọi thao tác có thể block. Đây là nền tảng để firmware ổn định khi chạy lâu dài.
6. Lỗi thường gặp
Phần lớn lỗi trong STM32F103C8T6 đến từ cấu hình chưa đồng bộ giữa clock, ngoại vi và wiring thực tế. Nếu bạn xử lý theo thứ tự “đọc triệu chứng -> khoanh vùng lớp lỗi -> test độc lập từng khối”, thời gian debug sẽ giảm rất rõ.
- Đặt priority ngẫu nhiên không theo deadline thực tế.
- ISR quá dài làm mất lợi thế cấu hình ưu tiên.
- Không kiểm thử dưới tải cao nên lỗi chỉ xuất hiện ngoài hiện trường.
- Dùng tài nguyên chia sẻ mà thiếu cơ chế bảo vệ.
- Không có tài liệu NVIC mapping cho đội phát triển.
Đặt quy tắc ưu tiên ngay từ đầu dự án và lưu thành tài liệu bắt buộc cho mọi thành viên.
7. Bài tập thực hành
Để chuyển từ mức “hiểu lý thuyết” sang “làm chủ kỹ năng”, bạn nên làm các bài tập sau theo đúng thứ tự từ dễ đến khó, sau mỗi bài đều ghi lại tiêu chí đạt/chưa đạt và thông số đo thực tế.
- Thiết kế bảng ưu tiên cho hệ gồm Timer + UART + ADC + EXTI.
- Đo latency của ngắt timer trước/sau khi tối ưu ISR UART.
- Mô phỏng burst UART và đánh giá ảnh hưởng tới task điều khiển.
- Viết guideline 1 trang về quy tắc viết ISR trong dự án.
Khuyến nghị chấm bài theo rubric: đúng chức năng (40%), độ ổn định 30 phút chạy liên tục (30%), chất lượng cấu trúc code (20%), tài liệu kỹ thuật và báo cáo đo kiểm (10%).
Tài liệu tham khảo
- STMicroelectronics, STM32F103x8/B Datasheet.
- STMicroelectronics, RM0008 Reference Manual: STM32F10xxx advanced ARM-based 32-bit MCUs.
- STMicroelectronics, UM1850 STM32CubeMX user manual và tài liệu STM32Cube liên quan.
- ARM, Cortex-M3 Technical Reference Manual.
- STMicroelectronics Application Notes về GPIO, ADC, Timer, UART, I2C, SPI, DMA và Watchdog.