Bài viết 9 thuộc series STM32F103C8T6 tập trung theo hướng “học để làm được việc”. Với chủ đề ADC đa kênh và DMA 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.

Khi hệ thống cần đọc nhiều cảm biến liên tục, polling sẽ nhanh chóng chiếm CPU và làm trễ các tác vụ khác. Kết hợp ADC scan + DMA là hướng đi chuẩn cho firmware hiệu quả và ổn định.

ADC đa kênh DMA
Minh họa cho bài 9: ADC đa kênh và DMA trên STM32F103C8T6.

1. Mục tiêu bài học

Bài hướng dẫn thiết kế pipeline dữ liệu ADC đa kênh theo mô hình producer-consumer, giúp dễ mở rộng và giảm nhiễu xử lý.

  • Cấu hình ADC scan multiple channels với DMA circular.
  • Đọc ổn định nhiều cảm biến mà không chiếm CPU lớn.
  • Thiết kế buffer và chu kỳ xử lý dữ liệu an toàn.
  • Tối ưu tốc độ lấy mẫu theo yêu cầu ứng dụ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.

  • Khái niệm DMA transfer và circular mode.
  • Scan conversion và thứ tự rank kênh ADC.
  • Half transfer/full transfer callback.
  • Tư duy xử lý dữ liệu theo batch thay vì từng mẫu.

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

Thiết kế buffer DMA cho ADC đa kênh

Buffer nên được khai báo rõ kích thước = số kênh x số mẫu mỗi batch. Việc xử lý theo batch giúp lọc số tốt hơn và giảm overhead so với xử lý từng điểm ngay khi có ngắt.

  • Đặt buffer ở vùng nhớ đủ nhanh và tránh ghi chồng.
  • Dùng chỉ số kênh hằng số để tránh nhầm map.
  • Tách lớp acquire và lớp process dữ liệu.

Đồng bộ callback DMA và vòng lặp chính

Callback chỉ nên gắn cờ dữ liệu sẵn sàng, phần tính toán trung bình hoặc quy đổi để main/task xử lý. Đây là cách giảm nguy cơ jitter và giữ ngắt nhẹ.

  • Half-transfer dùng cho latency thấp nếu cần.
  • Full-transfer phù hợp xử lý theo block ổn định.
  • Kiểm soát race condition bằng cờ trạng thái rõ ràng.

Đảm bảo chất lượng dữ liệu nhiều cảm biến

Khi đọc nhiều cảm biến, nhiễu chéo và sai lệch thời điểm lấy mẫu có thể xuất hiện. Cần đồng bộ chu kỳ, lọc theo từng kênh và đánh dấu timestamp để phân tích.

  • Hiệu chuẩn từng kênh trước khi đưa vào thuật toán.
  • Theo dõi min/max và outlier cho mỗi batch.
  • Lưu log để truy vết khi cảm biến bất thường.

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

Quan trọng nhất là quản lý buffer DMA rõ ràng và đồng bộ thời điểm xử lý để tránh đọc dữ liệu nửa chừng.

  1. Chọn danh sách kênh ADC và xác nhận thứ tự rank trong CubeMX.
  2. Bật DMA circular, cấu hình buffer theo số kênh mong muốn.
  3. Khởi động ADC DMA và kiểm tra callback hoạt động.
  4. Xử lý trung bình theo batch ở main loop.
  5. Quy đổi từng kênh về đơn vị vật lý tương ứng.
  6. Đánh giá tải CPU trước/sau khi dùng DMA.

Ở 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ụ ADC scan 3 kênh với DMA circular

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.

#define ADC_CH 3
uint16_t adc_buf[ADC_CH];
volatile uint8_t adc_ready = 0;

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if (hadc->Instance == ADC1) adc_ready = 1;
}

// Start once
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buf, ADC_CH);

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õ.

  • Sai thứ tự rank nên dữ liệu kênh bị đảo.
  • Xử lý nặng trong callback DMA làm trễ hệ thống.
  • Kích thước buffer không khớp số kênh cấu hình.
  • Quên volatile cho cờ dữ liệu sẵn sàng.
  • Không kiểm soát outlier khiến dữ liệu nhảy bất thường.

Luôn kiểm tra thứ tự kênh ADC trong buffer vì sai index là lỗi phổ biến nhất.

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ế.

  1. Đọc 4 kênh cảm biến và hiển thị theo định dạng CSV qua UART.
  2. Áp dụng moving average riêng cho từng kênh.
  3. So sánh tải CPU giữa polling ADC và ADC+DMA.
  4. Thiết kế cảnh báo khi một kênh vượt ngưỡng liên tục 5 chu kỳ.

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.