Bài viết 13 thuộc series STM32F103C8T6 tập trung theo hướng “học để làm được việc”. Với chủ đề DMA trên STM32F103C8T6: giảm tải CPU khi truyền nhận dữ liệu, 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.
DMA là một trong những kỹ thuật quan trọng nhất để nâng cấp firmware từ mức “chạy được” lên mức “chạy mượt và ổn định”. Với DMA, CPU không còn phải bận rộn sao chép từng byte dữ liệu.
1. Mục tiêu bài học
Bài này tập trung vào cách tư duy pipeline dữ liệu khi dùng DMA và cách phối hợp với interrupt để đảm bảo tính đúng và hiệu năng.
- Hiểu vai trò DMA và khi nào nên áp dụng.
- Cấu hình DMA cho ADC/UART/SPI trên STM32F103C8T6.
- Thiết kế luồng xử lý dữ liệu theo batch an toàn.
- Đánh giá mức giảm tải CPU trước và sau khi dùng DMA.
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.
- Memory-to-peripheral và peripheral-to-memory.
- Normal mode vs circular mode.
- Half/full transfer interrupt.
- Quản lý đồng bộ dữ liệu trong hệ thống thời gian thực.
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
Kiến trúc dữ liệu khi dùng DMA
Dùng DMA hiệu quả đòi hỏi thiết kế trước luồng dữ liệu: nguồn sinh dữ liệu, buffer trung gian, bước xử lý và bước xuất dữ liệu. Nếu chỉ bật DMA mà không kiến trúc luồng, hệ thống vẫn dễ lỗi race condition.
- Định nghĩa rõ owner của từng buffer tại mỗi thời điểm.
- Tách callback báo sự kiện và hàm xử lý dữ liệu.
- Dùng cờ trạng thái để tránh xử lý trùng.
DMA với UART và ADC
ADC DMA phù hợp lấy mẫu định kỳ nhiều kênh. UART DMA phù hợp gửi/nhận block dữ liệu lớn. Khi kết hợp cả hai, CPU có thêm thời gian xử lý logic điều khiển hoặc giao diện.
- ADC DMA circular cho dòng dữ liệu liên tục.
- UART TX DMA cho gói log lớn không block main.
- UART RX DMA + idle line cho khung dữ liệu biến độ dài.
Đo hiệu năng và chứng minh lợi ích
Để chứng minh DMA hiệu quả, cần đo cụ thể: CPU load, tần suất mất gói, độ trễ phản hồi nhiệm vụ khác. Những số liệu này giúp quyết định chỗ nào cần DMA và chỗ nào polling là đủ.
- Đo chu kỳ main loop trước/sau khi dùng DMA.
- Theo dõi tỷ lệ trễ deadline của tác vụ định kỳ.
- So sánh dung lượng log gửi được trong cùng thời gian.
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ọng tâm không phải chỉ bật DMA trong CubeMX, mà là thiết kế buffer, trạng thái và thời điểm xử lý dữ liệu.
- Xác định luồng dữ liệu nào đang gây tải CPU cao.
- Cấu hình DMA channel tương ứng cho ngoại vi mục tiêu.
- Thiết kế buffer và callback trạng thái rõ ràng.
- Di chuyển xử lý nặng ra khỏi ISR/callback.
- Đo hiệu năng định lượng trước và sau khi áp dụng DMA.
- Viết tài liệu kiến trúc dữ liệu cho team maintain.
Ở 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ụ UART TX DMA gửi gói dữ liệu
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.
volatile uint8_t uart_tx_busy = 0;
HAL_StatusTypeDef UART_SendDMA(uint8_t *buf, uint16_t len)
{
if (uart_tx_busy) return HAL_BUSY;
uart_tx_busy = 1;
return HAL_UART_Transmit_DMA(&huart1, buf, len);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1) uart_tx_busy = 0;
}
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õ.
- Thiết kế buffer không rõ owner gây ghi đè dữ liệu.
- Xử lý dữ liệu nặng trong callback DMA.
- Không khóa truy cập biến chia sẻ giữa callback và main.
- Dùng DMA cho gói quá nhỏ, lợi ích không đáng kể.
- Không đo hiệu năng nên khó đánh giá hiệu quả thật.
Đừng dùng DMA cho mọi thứ; chỉ dùng ở luồng dữ liệu đủ lớn hoặc cần đều đặn theo thời gian.
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ế.
- Chuyển một luồng log UART polling sang UART DMA.
- Thiết kế ADC DMA 4 kênh và xử lý theo block 32 mẫu.
- Đo và báo cáo % giảm thời gian CPU bận I/O.
- Viết state machine quản lý TX DMA chống gửi chồng gói.
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.