Cài ESP-IDF trên Windows và dự án đầu tiên: idf.py, app_main, menuconfig, nạp và xem nhật ký
Cài ESP-IDF trên Windows bằng bộ cài hoặc tiện ích VS Code, cấu trúc dự án, các lệnh idf.py, dự án đầu tiên với app_main và ESP_LOGI, tệp nạp và địa chỉ, so với Arduino.
ESP-IDF là bộ công cụ lập trình chính thức của Espressif cho ESP32. Gói esp32 của Arduino thực ra được dựng trên ESP-IDF, nên mọi thứ chạy trong Arduino đều có gốc ở đây. Dùng ESP-IDF trực tiếp giúp cấu hình được mọi chi tiết của chip (bộ nhớ, Wi-Fi, bảo mật, tiết kiệm điện), dùng được tính năng mới ngay khi ra mắt, và đọc được tài liệu, ví dụ của hãng mà không phải "dịch" sang Arduino. Bài này hướng dẫn cài ESP-IDF trên Windows, cấu trúc một dự án, các lệnh idf.py hay dùng, và dự án đầu tiên: in thông tin chip, nháy đèn.
1. Cài ESP-IDF trên Windows
Có hai cách, chọn một:
- Bộ cài cho Windows (ESP-IDF Tools Installer) tải từ trang tài liệu của Espressif: chọn bản ổn định mới nhất của nhánh 5.x; bộ cài tự cài Python, Git, trình biên dịch và tạo lối tắt ESP-IDF Command Prompt (hoặc PowerShell).
- Tiện ích ESP-IDF cho VS Code: cài tiện ích, chạy trình cài đặt có hướng dẫn trong VS Code; tiện ích có sẵn nút build, flash, monitor và menuconfig.
Lưu ý quan trọng trên máy Windows dùng tiếng Việt: đặt thư mục cài ESP-IDF và thư mục dự án ở đường dẫn ngắn, không dấu cách, không dấu tiếng Việt, ví dụ C:\esp\idf_den_nhay. Đường dẫn kiểu C:\Users\Tên\Tài liệu\... là nguyên nhân rất hay gặp của lỗi biên dịch khó hiểu.
2. Cấu trúc dự án và các lệnh idf.py

Một dự án ESP-IDF gồm tệp CMakeLists.txt ở gốc (ba dòng, đặt tên dự án) và ít nhất một thành phần main có CMakeLists.txt riêng khai báo các tệp mã nguồn:
# PYWORLD.VN - Tệp CMake gốc của dự án ESP-IDF: ba dòng này gần như giống hệt ở mọi dự án
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(idf_den_nhay)
# PYWORLD.VN - Thành phần "main": khai báo các tệp mã nguồn và thư mục chứa tệp .h
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")
Các lệnh gõ trong ESP-IDF Command Prompt, tại thư mục dự án:
idf.py set-target esp32: chọn dòng chip (esp32, esp32s3, esp32c3, esp32c6…). Chạy một lần khi tạo dự án hoặc khi đổi chip.idf.py menuconfig: mở trình cấu hình dạng chữ, đổi dung lượng flash, mức nhật ký, Wi-Fi, FreeRTOS… Kết quả lưu vào tệpsdkconfig.idf.py build: biên dịch. Lần đầu mất vài phút vì biên dịch toàn bộ các thành phần của ESP-IDF.idf.py -p COM5 flash monitor: nạp qua cổng COM5 rồi mở cửa sổ nhật ký; thoát bằngCtrl + ].
3. Dự án đầu tiên
Khác với Arduino, chương trình ESP-IDF không có setup() và loop(): mọi thứ bắt đầu ở hàm app_main(), và bản thân hàm này chạy trong một task FreeRTOS. Muốn lặp mãi thì tự viết vòng lặp, và nhớ vTaskDelay() để nhường CPU.
// PYWORLD.VN - Dự án ESP-IDF đầu tiên: in thông tin chip rồi nháy đèn GPIO2 mỗi 500 ms, ghi nhật ký bằng ESP_LOGI
// Không có setup()/loop(): chương trình bắt đầu ở app_main(), bản thân app_main là một task FreeRTOS
// Biên dịch và nạp bằng: idf.py set-target esp32, idf.py build, idf.py -p COMx flash monitor
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#define CHAN_DEN GPIO_NUM_2
static const char *TAG = "DEN"; // nhãn đứng đầu mỗi dòng nhật ký
void app_main(void)
{
esp_chip_info_t chip;
esp_chip_info(&chip);
uint32_t dungLuongFlash = 0;
esp_flash_get_size(NULL, &dungLuongFlash);
ESP_LOGI(TAG, "Chip %s, %d nhan, flash %lu MB", CONFIG_IDF_TARGET, chip.cores, (unsigned long)(dungLuongFlash >> 20));
gpio_reset_pin(CHAN_DEN); // đưa chân về trạng thái mặc định rồi đặt làm ngõ ra
gpio_set_direction(CHAN_DEN, GPIO_MODE_OUTPUT);
int muc = 0;
for (int lan = 1;; lan++) {
muc = !muc;
gpio_set_level(CHAN_DEN, muc);
ESP_LOGI(TAG, "Den %s, lan %d", muc ? "bat" : "tat", lan);
vTaskDelay(pdMS_TO_TICKS(500)); // nhường CPU 500 ms cho task khác
}
}
ESP_LOGI(TAG, …)in một dòng nhật ký mức thông tin, có thời gian và nhãn; tương tự cóESP_LOGW(cảnh báo),ESP_LOGE(lỗi). Mức nào được in ra chỉnh trong menuconfig.gpio_reset_pin(),gpio_set_direction(),gpio_set_level()thay chopinMode(),digitalWrite()của Arduino.CONFIG_IDF_TARGETlà hằng doset-targetsinh ra, chứa tên chip đang biên dịch.
4. Lệnh flash nạp những gì

idf.py build tạo ba tệp: bootloader, bảng phân vùng và chương trình; idf.py flash nạp mỗi tệp vào đúng địa chỉ. Bảng phân vùng mặc định của ESP-IDF chỉ có một ô ứng dụng 1 MB, khác bảng mặc định của Arduino; đổi trong menuconfig (mục Partition Table) khi cần OTA hoặc hệ thống file.
5. Kết quả mong đợi

Trước các dòng của chương trình, monitor còn in nhật ký khởi động của bootloader và hệ thống (phiên bản ESP-IDF, bảng phân vùng, bộ nhớ): đọc các dòng này giúp biết chip khởi động thế nào khi gặp lỗi.
6. Khi nào dùng Arduino, khi nào dùng ESP-IDF
| Arduino (gói esp32) | ESP-IDF | |
|---|---|---|
| Bắt đầu | Rất nhanh, nhiều ví dụ, nhiều thư viện cảm biến | Cài đặt lâu hơn, phải hiểu CMake, menuconfig |
| Cấu hình chip | Theo bộ cấu hình dựng sẵn | Đổi được mọi tùy chọn trong menuconfig |
| Tính năng mới của chip | Có sau một thời gian | Có ngay khi Espressif phát hành |
| Hợp với | Học tập, nguyên mẫu, dự án vừa và nhỏ | Sản phẩm, dự án cần tối ưu điện, bộ nhớ, bảo mật |
Hai cách không loại trừ nhau: trong chương trình Arduino vẫn gọi được hầu hết hàm của ESP-IDF (như các bài FreeRTOS, watchdog, bảng phân vùng trong loạt ESP32 nâng cao đã làm), và trong dự án ESP-IDF có thể thêm Arduino làm một thành phần.
7. Xử lý lỗi thường gặp
| Hiện tượng | Nguyên nhân thường gặp | Cách xử lý |
|---|---|---|
| "idf.py is not recognized" | Gõ lệnh trong cửa sổ Command Prompt thường | Mở ESP-IDF Command Prompt (biến môi trường đã đặt sẵn) |
| Lỗi CMake khó hiểu, không tìm thấy tệp | Đường dẫn có dấu cách hoặc dấu tiếng Việt | Chuyển dự án về thư mục kiểu C:\esp\... |
| Nạp báo "Failed to connect" | Sai cổng COM; bo không tự vào chế độ nạp | Kiểm tra cổng; giữ nút BOOT khi bắt đầu nạp |
| "Detected size(4096k) larger than the size in the binary image header(2048k)" | Cấu hình flash mặc định 2 MB | Đổi Flash size thành 4 MB trong menuconfig (Serial flasher config) |
| Nhật ký ra ký tự lạ | Tốc độ monitor khác cấu hình | Giữ mặc định 115200; dùng idf.py monitor thay vì phần mềm khác |
8. Xem thêm
- ESP32 DevKit V1 30 chân, 38 chân và dây USB nạp code.
- Bài PlatformIO trong cùng loạt công cụ: PlatformIO cũng hỗ trợ ESP-IDF (
framework = espidf). - Các bài FreeRTOS, bảng phân vùng, watchdog trong loạt ESP32 nâng cao: phần lớn kiến thức dùng chung với ESP-IDF.
Xem thêm