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 đó.
Ghi chú nhanh
HAL_BUSY thường xảy ra khi bạn gọi HAL_UART_Transmit_DMA() trong lúc UART/DMA vẫn đang bận truyền dữ liệu trước đó.
Ví dụ sai rất quen thuộc:
HAL_UART_Transmit_DMA(&huart1, buf1, len1);
HAL_UART_Transmit_DMA(&huart1, buf2, len2); // có thể trả về HAL_BUSY
DMA không phải là queue. Nó không tự nhớ “gửi xong buf1 thì gửi tiếp buf2”. Nó chỉ nhận một vùng nhớ, truyền vùng đó, rồi kết thúc.
Vì sao lỗi này hay đánh lừa người mới?
Vì tên hàm có chữ DMA, nhiều người kỳ vọng rằng “đã dùng DMA thì không blocking, vậy cứ gọi thoải mái”.
Thực tế, DMA chỉ giúp CPU không phải tự đẩy từng byte ra UART. Nhưng trạng thái truyền vẫn cần được quản lý.
Nếu lần truyền trước chưa xong, lần gọi mới có thể bị từ chối bằng HAL_BUSY.
Một tình huống thực tế
Bạn redirect printf() sang DMA:
int _write(int file, char *ptr, int len)
{
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)ptr, len);
return len;
}
Nhìn qua có vẻ rất thông minh: printf() không còn blocking nữa.
Nhưng nếu hai dòng log đi xuống gần nhau:
printf("ADC start");
printf("ADC value = %d", value);
Dòng thứ hai có thể gọi DMA khi dòng thứ nhất vẫn chưa truyền xong. Nếu không kiểm tra return value, log sẽ mất âm thầm. Đây là loại bug rất khó chịu: firmware vẫn chạy, chỉ có log là “mất trí nhớ”.
Cách xử lý đúng hơn
Thay vì gọi DMA trực tiếp cho từng lần printf(), nên dùng kiến trúc:
printf()
-> _write()
-> ghi vào Ring Buffer
-> nếu DMA rảnh thì start transmit
-> Tx complete callback gửi chunk tiếp theo
Khi đó, DMA chỉ truyền một chunk tại một thời điểm. Các log mới được giữ trong buffer chờ lượt.
Checklist khi gặp HAL_BUSY
Cách nhớ
DMA là người vận chuyển, không phải hàng đợi.
Muốn xếp hàng log → cần Ring Buffer hoặc queue.
Bài liên quan nên đọc tiếp
- Ring Buffer là gì trong firmware embedded?
- 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.
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.
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.