Lập trình Embedded RISC-V: Bắt đầu với ESP32-P4
Hướng dẫn thực tế lập trình RISC-V trên ESP32-P4: cài ESP-IDF, chọn target esp32p4, build project đầu tiên, nạp USB và hiểu kiến trúc dual-core.
Chia sẻ

RISC-V có thể nghe hơi trừu tượng cho tới khi bạn có một board trên bàn và nhìn thấy log firmware chạy thật. Với ESP32-P4, điều đáng chú ý không chỉ là tập lệnh RISC-V. Đây là sự kết hợp giữa hệ thống RISC-V hiệu năng cao, một subsystem tiết kiệm điện, nhiều peripheral tốc độ cao và workflow ESP-IDF vẫn khá quen thuộc nếu bạn từng dùng một dòng ESP32 khác.
Có một điểm cần nói rõ ngay: ESP32-P4 không có Wi-Fi hoặc Bluetooth tích hợp. Nếu project cần wireless, bạn sẽ ghép thêm một wireless SoC bên ngoài như ESP32-C5 hoặc ESP32-C6. Đây không phải điều cần giấu đi; nó là một phần của kiến trúc và giúp bạn chọn board đúng ngay từ đầu.
Trong bài này, mình đi theo con đường ngắn nhưng đủ dùng: hiểu chip, cài đúng tool ESP-IDF, build hello_world, flash firmware, rồi nhìn vào hai hệ thống RISC-V trước khi bước sang ứng dụng thực tế.
ESP32-P4 khác gì?
ESP32-P4 có hai hệ thống RISC-V:
- Hệ thống HP gồm hai core RISC-V hiệu năng cao, chạy tới 400 MHz.
- Hệ thống LP có một core RISC-V riêng, chạy tới 40 MHz.
Chip cũng có USB, MIPI, SDIO, Ethernet, khả năng xử lý hình ảnh và voice, FPU đơn chính xác cùng phần cứng bảo mật. Vì vậy ESP32-P4 phù hợp với camera, màn hình, thiết bị HMI, gateway và các bài toán xử lý tín hiệu hoặc AI tại chỗ.
Cách hiểu thực tế đơn giản hơn: đừng xem ESP32-P4 là một bản thay thế nhanh hơn của ESP32-C3. Trước tiên hãy kiểm tra peripheral bạn cần thuộc subsystem nào, code sẽ chạy ở core nào và board phát triển có đưa đúng chân/đường USB ra ngoài hay không.
Chuẩn bị phần cứng và phần mềm
Bạn cần:
- Một board ESP32-P4, chẳng hạn ESP32-P4-Function-EV-Board hoặc ESP32-P4-EYE.
- Dây USB đúng với cổng trên board.
- Máy tính chạy Windows, Linux hoặc macOS.
- ESP-IDF và toolchain cho target ESP32-P4.

Hãy bắt đầu bằng layout thật của board: một cổng USB-C, hai nút nhấn, lỗ bắt vít và các hàng header bạn có thể dùng.
Đừng mặc định mọi board P4 đều có cùng cổng hoặc cùng cách mở serial. Có board đưa USB trực tiếp ra ngoài, có board dùng USB-to-UART bridge. Pinout, nút boot, nguồn và các đầu nối camera/màn hình là chi tiết của từng board, không nên đoán chỉ từ tên chip.
Cài ESP-IDF cho target P4
Luồng cài đặt hiện tại của Espressif dùng ESP-IDF Installation Manager, nhưng điều quan trọng với bài này là bạn phải cài bộ tool cho esp32p4. Sau khi mở terminal ESP-IDF đã activate, kiểm tra môi trường:
idf.py --version
Tạo project từ example chính thức:
cd ~/esp
cp -r $IDF_PATH/examples/get-started/hello_world esp32-p4-hello
cd esp32-p4-hello
idf.py set-target esp32p4
Trên Windows PowerShell, bạn dùng ESP-IDF terminal do Espressif cung cấp và copy example bằng lệnh PowerShell tương đương. Lệnh quan trọng vẫn là:
idf.py set-target esp32p4
Việc chọn target quyết định compiler, linker, header SoC, bootloader và các option component phù hợp. Nếu bỏ qua bước này, project có thể vẫn đang cấu hình cho một dòng ESP32 khác.
Build, flash và monitor
Hãy build trước để tách lỗi code khỏi lỗi kết nối:
idf.py build
Kết nối board rồi flash:
idf.py -p PORT flash
Mở serial monitor:
idf.py -p PORT monitor
Hoặc gộp hai bước cuối:
idf.py -p PORT flash monitor
Nếu board dùng USB peripheral của ESP32-P4, bạn có thể flash trực tiếp mà không cần USB-to-UART rời. Lần kết nối đầu tiên có thể cần vào download mode thủ công: giữ BOOT, nhấn RESET, sau đó thả BOOT. Tên port sẽ tùy hệ điều hành và board.
Mình thường lưu lại log thành công đầu tiên. Đây là baseline rất hữu ích trước khi thay clock, chỉnh FreeRTOS task, bật USB hoặc thêm driver peripheral.
Thử nghiệm RISC-V đầu tiên
Thử nghiệm đầu tiên không cần viết assembly. Tạo một FreeRTOS task nhỏ, in ra core ID và xem task đang chạy ở đâu:
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
static const char *TAG = "riscv-demo";
static void worker_task(void *arg)
{
while (1) {
ESP_LOGI(TAG, "running on core %d", xPortGetCoreID());
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void app_main(void)
{
xTaskCreate(worker_task, "worker", 4096, NULL, 5, NULL);
}
Giá trị của thử nghiệm này không nằm ở dòng log. Nó giúp bạn tập thói quen kiểm chứng giả định. Với hệ dual-core, affinity của task và vị trí interrupt có thể ảnh hưởng latency. Hãy đo trước khi quyết định task nào nên cố định ở một core.
Nghĩ về HP và LP như thế nào?
Với ứng dụng đầu tiên, bạn có thể bắt đầu theo hướng thực tế:
| Công việc | Nơi nên bắt đầu | Lý do |
|---|---|---|
| UI, camera pipeline, networking, biến đổi dữ liệu nặng | Hệ thống HP | Nhiều compute và peripheral tốc độ cao hơn |
| Housekeeping định kỳ hoặc monitor tiết kiệm điện | Hệ thống LP, khi board/SDK hỗ trợ | Có thể tách phần việc ít điện khỏi app chính |
| Timing quan trọng | Subsystem sở hữu peripheral, sau khi đo | Ownership của peripheral quan trọng hơn nhãn HP/LP |
LP core không phải nút bấm tiết kiệm pin tự động. Board, power tree, nguồn wake-up, SDK và trạng thái ứng dụng đều ảnh hưởng. Hãy bắt đầu với app chạy trên HP, sau đó chuyển một trách nhiệm nhỏ sang LP và đo dòng điện, thời gian wake cùng chi phí handoff dữ liệu.

Thiết kế dual-core chỉ thực sự hữu ích khi bạn đo được tải thay vì đoán core nào đang bận.
Khi debug, hãy log timestamp, core ID, queue latency và quyền sở hữu buffer. Nếu camera hoặc màn hình bị rớt frame, trước hết kiểm tra task có bị block, buffer có bị copy quá nhiều hoặc interrupt có bị đói hay không. RISC-V cho bạn một kiến trúc rõ ràng hơn; nó không xóa đi các đánh đổi quen thuộc của embedded.
USB đóng vai trò gì?
USB đặc biệt hữu ích trên ESP32-P4 vì có thể tạo đường flash và serial/JTAG trực tiếp, tùy thiết kế board. Espressif có tài liệu riêng cho USB D+ và D- của P4, đồng thời lưu ý rằng một số board dùng USB-to-UART bridge thay vì USB trực tiếp.

Nạp firmware qua đường USB được board hỗ trợ là cột mốc gọn gàng trước khi thêm màn hình, camera hoặc chip wireless phụ.
Khi flash thất bại, mình thường kiểm tra theo thứ tự:
- Target đã thực sự là
esp32p4chưa? - Board dùng native USB hay bridge chip?
- Port đúng chưa và có process monitor khác đang giữ port không?
- Board đã vào download mode chưa?
- Dây USB có truyền data hay chỉ sạc?
Checklist này thường hiệu quả hơn việc đổi baud rate ngẫu nhiên.
Project tiếp theo nên làm gì?
Khi hello_world đã chạy, hãy chọn một lát cắt dọc thay vì bật toàn bộ peripheral cùng lúc. Ví dụ:
- Đọc một sensor qua I2C.
- Render một màn hình status nhỏ.
- Stream một format camera.
- Gửi một gói tin Ethernet.
- Ghép P4 với ESP32-C6 bên ngoài để có wireless.
Giữ phiên bản đầu tiên có thể quan sát được: serial log, heartbeat LED, frame rate đo được hoặc counter trên màn hình. Một mốc nhỏ nhưng đo được sẽ cho bạn biết lỗi nằm ở board, driver, scheduler hay application.
Một số lỗi dễ gặp
- Nghĩ ESP32-P4 có Wi-Fi/Bluetooth native.
- Dùng example ESP32 chung mà không kiểm tra supported-target table.
- Cho rằng mọi board P4 có cùng cổng USB và boot flow.
- Chuyển việc sang LP trước khi hiểu chi phí wake-up và handoff dữ liệu.
- Debug timing bằng quá nhiều log khiến chính log tạo ra vấn đề timing.
Kết luận
ESP32-P4 là một cách khá dễ tiếp cận để học RISC-V theo hướng thực hành, vì toolchain, command project và API ESP-IDF vẫn cho bạn một điểm bắt đầu quen thuộc. Những phần mới cần để ý là hệ HP dual-core, subsystem LP, bộ peripheral phong phú hơn và việc dùng wireless companion bên ngoài khi cần.
Lời khuyên của mình là để project đầu tiên thật bình thường: chọn esp32p4, build example chính thức, flash qua đúng đường USB của board và lưu lại serial log sạch. Khi baseline đã ổn, các project camera, display, Ethernet và multi-chip sẽ dễ phân tích hơn nhiều.
Tài liệu tham khảo
Chia sẻ
Tiếp tục khám phá
Đọc tiếp
Bài viết liên quan
ESP32 Memory Management Deep Dive: SRAM, PSRAM, Heap và Stack FreeRTOS
Bài hướng dẫn thực tế về layout SRAM, cách dùng PSRAM, phân mảnh heap, cấp phát stack cho task FreeRTOS và các mẹo tối ưu bộ nhớ hữu ích trong firmware ESP32.
18 lỗi ESP32 thường gặp – Phần 2: Các lỗi nghiêm trọng
Cách mình đọc backtrace và xử lý crash, watchdog, heap, stack, FreeRTOS, Wi-Fi, ADC, deep sleep và OTA trên ESP32 theo một checklist runtime dễ áp dụng.
Chạy Linux trên ESP32-S31: MMU thay đổi điều gì?
ESP32-S31 đã có Linux BSP chính thức ở dạng Developer Preview. Mình cùng xem MMU, Buildroot, U-Boot, Linux 6.18 và những giới hạn thực tế trước khi chọn board để thử.