Bài viết 12 thuộc series STM32F103C8T6 tập trung theo hướng “học để làm được việc”. Với chủ đề Giao tiếp SPI 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.
SPI là giao tiếp tốc độ cao, phù hợp cho màn hình, bộ nhớ, ADC ngoài và nhiều module công nghiệp. Điểm mấu chốt là cấu hình mode đúng và điều khiển chip select chuẩn thời điểm.
1. Mục tiêu bài học
Bài giúp bạn hiểu bản chất timing của SPI và triển khai giao tiếp full-duplex một cách đáng tin cậy.
- Hiểu vai trò MOSI/MISO/SCK/NSS trong SPI master mode.
- Cấu hình mode SPI theo CPOL/CPHA đúng thiết bị ngoại vi.
- Truyền nhận dữ liệu bằng polling/interrupt/DMA.
- Debug lỗi lệch bit và framing error bằng analyzer.
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.
- Sự khác nhau giữa 4 mode SPI.
- LSB/MSB first và ảnh hưởng đến dữ liệu.
- Quản lý chip select khi có nhiều slave.
- Khái niệm full-duplex và dummy byte.
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
Mode SPI và tính tương thích thiết bị
Mỗi thiết bị ngoại vi yêu cầu mode riêng về cạnh lấy mẫu và cạnh dịch dữ liệu. Sai mode có thể dẫn đến đọc sai từng bit dù wiring đúng. Vì vậy cần đối chiếu chặt chẽ datasheet giữa master và slave.
- Xác nhận CPOL/CPHA trước khi viết driver.
- Kiểm tra bit order MSB/LSB theo tài liệu.
- Tạo hàm init linh hoạt cho nhiều loại slave.
Quản lý chip select và transaction
NSS/chip select phải được điều khiển đúng biên giao dịch. Nếu toggle sai thời điểm, slave có thể hiểu nhầm khung lệnh. Driver tốt luôn gom transaction theo lệnh hoàn chỉnh thay vì gửi byte rời rạc.
- Kéo CS xuống trước khung lệnh, nhả lên sau khi hoàn tất.
- Chèn delay tối thiểu nếu datasheet yêu cầu.
- Không chia nhỏ transaction khi slave cần khung liên tục.
Tối ưu thông lượng và độ ổn định
SPI rất nhanh nhưng cần cân bằng với khả năng xử lý phía slave và chất lượng tín hiệu đường truyền. Với dây dài hoặc môi trường nhiễu, nên giảm tốc độ và tăng kiểm tra phản hồi để giữ ổn định.
- Dùng DMA cho khối dữ liệu lớn.
- Kiểm tra CRC hoặc checksum ở lớp ứng dụng nếu cần.
- Bố trí dây tín hiệu ngắn, mass tốt.
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
Đừng bỏ qua datasheet của slave device; CPOL/CPHA sai chỉ một bit có thể làm dữ liệu hoàn toàn sai.
- Cấu hình SPI master mode theo datasheet của thiết bị slave.
- Kiểm tra wiring MOSI/MISO/SCK/CS và mức điện áp tương thích.
- Viết hàm transaction có điều khiển CS chuẩn.
- Đọc/ghi thanh ghi test để xác nhận giao tiếp.
- Tối ưu tốc độ SPI sau khi đã chạy ổn định ở mức thấp.
- Đánh giá tín hiệu bằng logic analyzer ở nhiều mức tốc độ.
Ở 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ụ transaction SPI có điều khiển CS
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_StatusTypeDef SPI_ReadReg(uint8_t reg, uint8_t *val)
{
uint8_t tx[2] = { (uint8_t)(reg | 0x80), 0x00 };
uint8_t rx[2] = {0};
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // CS low
HAL_StatusTypeDef st = HAL_SPI_TransmitReceive(&hspi1, tx, rx, 2, 50);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); // CS high
*val = rx[1];
return st;
}
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õ.
- Chọn sai CPOL/CPHA nên dữ liệu lệch hoàn toàn.
- Không điều khiển CS đúng biên transaction.
- Nhầm MOSI/MISO khi wiring ngoài thực tế.
- Tốc độ SPI quá cao so với khả năng slave.
- Bỏ qua kiểm tra phản hồi lỗi ở tầng ứng dụng.
Khi chưa chắc timing, hãy giảm tốc SPI để debug rồi tăng dần sau khi hệ thống ổn định.
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ế.
- Viết driver SPI đọc ID chip từ một module cảm biến.
- So sánh polling và DMA khi truyền block 1 KB dữ liệu.
- Tạo testbench thay đổi mode SPI để quan sát sai khác dữ liệu.
- Ghi lại dạng sóng analyzer cho transaction chuẩn và transaction lỗ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.