Producer-Consumer pattern trong hệ thống logging embedded
Giải thích mô hình producer-consumer khi CPU ghi log vào buffer và DMA/UART truyền dữ liệu ở background.
Ghi chú nhanh
Producer-Consumer là mô hình tách bên tạo dữ liệu và bên tiêu thụ dữ liệu.
Trong UART logger:
Producer = CPU / task / ISR ghi log
Buffer = Ring Buffer trong RAM
Consumer = UART TX DMA truyền log ra ngoài
Mô hình này nghe có vẻ sách vở, nhưng trong firmware nó xuất hiện rất nhiều: UART, USB, audio, sensor stream, flash log, network packet… Nói hơi vui: cứ nơi nào có một bên “đẻ dữ liệu” nhanh hơn bên kia xử lý, bạn sẽ gặp producer-consumer.
Vì sao logging cần mô hình này?
CPU có thể tạo log rất nhanh. Một task chỉ cần vài micro giây để format và ghi dữ liệu vào RAM.
UART thì chậm hơn nhiều. Ở 115200 bps, một dòng log vài chục ký tự có thể mất vài mili giây để truyền vật lý.
Nếu bắt CPU chờ UART gửi xong từng dòng, debug log sẽ bắt đầu ảnh hưởng tới timing của firmware. Khi đó log không còn là công cụ quan sát nữa, mà trở thành một phần của bug.
Ví dụ tư duy thiết kế
Thay vì để producer gọi thẳng UART:
Task A -> UART
Task B -> UART
ISR -> UART
Ta gom log vào một buffer chung:
Task A ----Task B -----+--> Ring Buffer --> UART DMA
ISR ----/
Lợi ích là các producer chỉ cần ghi nhanh vào RAM rồi quay lại việc chính. Consumer sẽ truyền dữ liệu ra ngoài theo tốc độ mà UART chịu được.
Câu hỏi quan trọng: buffer đầy thì sao?
Producer-consumer không làm UART nhanh hơn. Nó chỉ giúp firmware không bị block ngay lập tức.
Nếu log đến nhanh hơn UART truyền trong thời gian dài, buffer chắc chắn sẽ đầy. Khi đó phải có policy rõ ràng:
| Policy | Ý nghĩa | Khi nào dùng |
|---|---|---|
| Drop new byte/message | Bỏ log mới khi buffer đầy | Ưu tiên giữ log cũ |
| Drop old data | Ghi đè log cũ | Ưu tiên xem trạng thái mới nhất |
| Block producer | Chờ còn chỗ trống | Không phù hợp ISR/real-time critical |
| Count dropped logs | Ghi lại số log bị mất | Rất nên có khi debug nghiêm túc |
Một logger tốt không nhất thiết phải giữ mọi byte log. Nhưng nó nên nói thật rằng đã mất bao nhiêu log.
Cách tự hỏi khi đọc source
- Ai là producer?
- Ai là consumer?
- Buffer nằm ở đâu?
- Producer có thể chạy trong ISR không?
- Consumer được kích hoạt bằng polling, interrupt, DMA callback hay task?
- Khi buffer đầy thì policy là gì?
Cách nhớ
Producer nhanh thì ghi vào RAM.
Consumer chậm thì xử lý nền.
Buffer là vùng đệm giữa hai tốc độ khác nhau.
Bài liên quan nên đọc tiếp
- Ring Buffer là gì trong firmware embedded?
- HAL_BUSY xảy ra khi nào trong UART DMA?
- Cách tính thời gian truyền UART từ baudrate
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.
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.
DMA Normal mode và Circular mode khác nhau thế nào?
Phân biệt DMA Normal mode và Circular mode khi dùng UART, ADC, audio stream hoặc logger trên STM32.
HAL_BUSY xảy ra khi nào trong UART DMA?
Giải thích lỗi HAL_BUSY khi gọi HAL_UART_Transmit_DMA() trong lúc UART/DMA vẫn đang truyền dữ liệu trước đó.
Biến note thành bài viết hoàn chỉnh
Notes là nơi ghi nhanh khái niệm.