Dự án này giúp phát video RAW 16-bit RGB565 từ thẻ SD lên hai màn hình tròn GC9A01A 240x240 sử dụng STM32F411.
Tối ưu hiệu năng với SPI + DMA, hỗ trợ preload hoặc stream trực tiếp từ thẻ SD, phù hợp cho các ứng dụng nhúng hiển thị video tốc độ cao.
- Đọc dữ liệu video từ thẻ SD qua SPI2 sử dụng FatFs và DMA.
- Xuất hình ảnh lên hai LCD GC9A01A qua SPI1 bằng DMA, chia dữ liệu an toàn theo chunk.
- Hỗ trợ hai chế độ phát: preload toàn bộ vào RAM hoặc stream trực tiếp từ file.
- Tối ưu FPS (~25–30 fps cho 240x240), giảm sử dụng RAM.
- Cấu trúc mã nguồn rõ ràng, dễ mở rộng và bảo trì.
- Mục tiêu: Phát video RAW 16-bit RGB565 từ thẻ SD lên 2 màn tròn GC9A01A 240x240 trên STM32F411, ưu tiên FPS cao và sử dụng RAM hiệu quả.
- Điểm nổi bật:
- Đọc thẻ SD qua SPI2 + FatFs (driver SPI tự viết, hỗ trợ DMA).
- Xuất ảnh qua SPI1 tới 2 LCD GC9A01A bằng DMA, chia dữ liệu theo chunk an toàn.
- Hỗ trợ 2 cách phát: preload full-frame vào RAM hoặc stream trực tiếp từ file bằng
f_forward(giảm sử dụng RAM).
- MCU:
STM32F411CEU6 - LCD: 2x GC9A01A 240x240 (SPI)
- Lưu trữ: thẻ microSD (SPI)
- SPI1 (LCD):
PA5=SCK,PA6=MISO,PA7=MOSI- LCD1:
CS=PB10,DC=PB1,RST=PB0 - LCD2:
CS=PB6,DC=PB7,RST=PB8
- LCD1:
- SPI2 (SD):
PB13=SCK,PB14=MISO,PB15=MOSI,SD_CS=SD_CS_Pin(portGPIOB)
Core/IncvàCore/Srcgc9a01.[ch]: driver GC9A01A (khởi tạo, vẽ pixel/chuỗi, rectangle, DMA, invert/rotate/scroll, gamma). Có nhánh streamf_forwardđể đẩy trực tiếp từ file qua SPI DMA.Function_Paint.[ch]: primitive 2D (line, rect, circle, triangle, rounded rect) dựa trên APIgc9a01.fonts.[ch]: font 7x10, 11x18, 16x26.main.c: khởi tạo clock/GPIO/DMA/SPI, mount SD, chọn pipeline phát, vòng lặp phát file RAW.
FATFSTarget/user_diskio_spi.c: driver SPI cho FatFs (DMA full‑duplex tự quản, hiệu năng cao).App/fatfs.[ch],Middlewares/Third_Party/FatFs: stack FatFs.
- Màu: RGB565, kích thước cố định 240x240 (hoặc biến thể 200/180/150/100/50 theo file mẫu).
- Endian: little-endian (phù hợp ARM Cortex‑M, gửi byte cao trước trên SPI).
- File mẫu:
eye240.raw,eye200.raw,eye180.raw,eye150.raw,eye100.raw,eye50.rawnằm ở thư mục gốc.
- Công cụ: STM32CubeIDE hoặc Makefile (thư mục
Debug/sinh ra tự động bởi IDE). - Bước thực hiện (STM32CubeIDE):
- Mở dự án (
Exam.iochoặc import thư mục). - Chọn target board/chip đúng
STM32F411CEUx. - Build Release/Debug.
- Nạp firmware qua ST‑Link.
- Mở dự án (
- Format FAT32.
- Sao chép các file RAW vào gốc thẻ (ví dụ
eye240.raw). - Lắp thẻ vào hệ thống.
- Cách 1 — Preload vào RAM (đơn giản, RAM ~115 KB cho 240x240):
// Trong Core/Src/main.c
display_all_frames_preload(&lcd1, &lcd2, "eye240.raw", 240, 240, 1);- Cách 2 — Stream trực tiếp bằng FatFs
f_forward+ SPI DMA (giảm RAM):
// Ví dụ trong Core/Src/main.c (có thể bật nhánh sẵn có)
FIL file;
if (f_open(&file, "0:/eye240.raw", FA_READ) == FR_OK) {
GC9A01A_SetAddressWindow(&lcd1, 0, 0, 239, 239);
// Đẩy 1 frame từ file ra LCD1 bằng DMA forwarding (không cần full buffer)
GC9A01A_DrawImage_DMA_fwd(&lcd1, &file, 240*240*2);
f_close(&file);
}Lưu ý: để f_forward bằng DMA hoạt động, callback HAL_SPI_TxCpltCallback cần xả cờ đang bận cho đúng hspi tương ứng.
- Mục tiêu: ~25–30 fps cho 240x240 (tăng ~50–100% so với baseline preload/không tối ưu).
- Kỹ thuật:
- Chia chunk DMA an toàn (≤ 65535B), khuyến nghị ~32 KB.
- Loại bỏ
HAL_Delaythừa trong vòng chờ DMA. - Thêm timeout khi chờ DMA để tránh kẹt; reset CS nếu quá hạn.
- Dùng
f_forwardđể stream, giảm chiếm dụng RAM và cache locality tốt hơn. - Chuẩn bị double buffering để overlap đọc SD và phát DMA.
- Xem thêm:
FPS_OPTIMIZATION_README.md.
- SPI1 (LCD):
BaudRatePrescaler = 2(tốc độ cao, tùy chất lượng dây/khoảng cách). - SPI2 (SD): chậm khi init (prescaler lớn), sau init tăng tốc (
SD_MAX_SPEED). - DMA NVIC: bật interrupt cho các stream sử dụng (xem
MX_DMA_Init).
Core/Inc,Core/Src: mã người dùng, driver LCD, primitives, main.Drivers: HAL/LL/CMSIS của ST.FATFS: driver và middleware FatFs.Middlewares/Third_Party/FatFs: mã nguồn FatFs.- File dữ liệu mẫu:
eye*.rawtại thư mục gốc.
- Hai LCD đang dùng chung
SPI1nên truyền lần lượt, không song song thực sự. - Biến cờ DMA (
dma_busy) dùng chung; nếu tách LCD2 sangSPI3cần cờ/logic riêng theohspitrong callback. - Tránh cấp phát buffer khung lớn trên stack (nguy cơ HardFault). Dùng buffer tĩnh/toàn cục hoặc stream/tiling.
- Tách LCD2 sang
SPI3để phát ảnh song song thực sự. - Áp dụng double buffering hoàn chỉnh cho overlap SD ↔ LCD.
- Bổ sung công cụ chuyển đổi video → RAW 16‑bit.
- Mã HAL/CMSIS thuộc STMicroelectronics (theo license gốc đính kèm).
- FatFs thuộc ChaN (theo license gốc).
- Mã người dùng trong thư mục
Core/FATFS/Targetcó thể sử dụng theo nhu cầu nội bộ; cân nhắc bổ sung LICENSE riêng khi công khai.
- Tác giả: thực tập sinh (Naiscop), 2025.
- Nếu bạn dùng project này, vui lòng trích dẫn nguồn.