Skip to main content

Working with ESP-IDF

This chapter includes the following sections, please read as needed:

ESP-IDF Getting Started

New to ESP32 ESP-IDF development and looking to get started quickly? We have prepared a general Getting Started Tutorial for you.

Please Note: This tutorial uses the ESP32-S3-Zero as a teaching example, and all hardware code is based on its pinout. Before you start, it is recommended that you check the pinout of your development board to ensure the pin configuration is correct.

Setting Up Development Environment

note

The following guide uses Windows as an example, demonstrating development using VS Code + the ESP-IDF extension. macOS and Linux users should refer to the official documentation.

Version Selection

The screenshots in this section use ESP-IDF V5.5.2 as an example. When installing, please select the ESP-IDF version that matches your board's example.

Install the ESP-IDF Development Environment

  1. Download the installation manager from the ESP-IDF Installation Manager page. This is Espressif's latest cross-platform installer. The following steps demonstrate how to use its offline installation feature.

    Click the Offline Installer tab on the page, then select Windows as the operating system and the ESP-IDF version you need (the version shown in the screenshot is for reference only — choose the version that fits your actual needs).

    Download EIM and offline package

    After confirming your selection, click the download button. The browser will automatically download two files: the ESP-IDF Offline Package (.zst) and the ESP-IDF Installer (.exe).

    Download EIM and offline package 2

    Please wait for both files to finish downloading.

  2. Once the download is complete, double-click to run the ESP-IDF Installer (eim-gui-windows-x64.exe).

    The installer will automatically detect if the offline package exists in the same directory. Click Install from archive.

    Auto-detect offline package

    Next, select the installation path. We recommend using the default path. If you need to customize it, ensure the path does not contain Chinese characters or spaces. Click Start installation to proceed.

    Select installation path
  3. When you see the following screen, the ESP-IDF installation is successful.

    Installation successful
  4. We recommend installing the drivers as well. Click Finish installation, then select Install driver.

    Install drivers via ESP-IDF Installation Manager

Install Visual Studio Code and the ESP-IDF Extension

  1. Download and install Visual Studio Code.

  2. During installation, it is recommended to check Add "Open with Code" action to Windows Explorer file context menu to facilitate opening project folders quickly.

  3. In VS Code, click the Extensions icon Extensions Icon in the Activity Bar on the side (or use the shortcut Ctrl + Shift + X) to open the Extensions view.

  4. Enter ESP-IDF in the search box, locate the ESP-IDF extension, and click Install.

    Search and install ESP-IDF extension in VS Code

  5. For ESP-IDF extension versions ≥ 2.0, the extension will automatically detect and recognize the ESP-IDF environment installed in the previous steps, requiring no manual configuration.

Example

The ESP-IDF examples are located in the ESP-IDF directory of the example package.

ExampleBasic Description
01_GPIOControl the logic level of the exposed GPIO pins
02_BlinkRGBImplement a breathing LED effect on the RGB LED
03_GetchipIDObtain and print hardware information of the ESP32-C5-Zero chip, including model, revision, core count, and chip ID
04_BLEUse the ESP32-C5-Zero development board to connect to BLE beacons and receive broadcast data
05_UARTImplement UART communication using the ESP32-C5-Zero development board
06_WIFI_APConfigure the ESP32-C5-Zero development board as an AP hotspot (2.4G), allowing other Wi‑Fi devices to connect
07_WIFI_STAConnect to a specified Wi‑Fi network and print connection information
08_WIFI_StaticIPUse the ESP32-C5-Zero development board to connect to Wi-Fi with a static IP address
09_ZIGBEEUse Zigbee on the ESP32-C5-Zero development board to control the onboard LED on/off
10_Mem_SecurityDemonstrate memory security features on the ESP32-C5-Zero development board

01_GPIO


Code

01_GPIO.ino
void app_main(void)
{
// Configure all selected GPIOs as push-pull outputs
gpio_config_t io_conf = {
.intr_type = GPIO_INTR_DISABLE,
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = GPIO_OUTPUT_PIN_SEL,
.pull_down_en = 0,
.pull_up_en = 0,
};
ESP_ERROR_CHECK(gpio_config(&io_conf));

int output_level = 0;
size_t gpio_count = sizeof(gpio_pins) / sizeof(gpio_pins[0]);

ESP_LOGI(log_tag, "Initialization done. Start toggling GPIO pins synchronously...");

while (true) {
// Set all selected pins to the same level
for (size_t i = 0; i < gpio_count; i++) {
ESP_ERROR_CHECK(gpio_set_level(gpio_pins[i], output_level));
}

// Flip output level for next cycle
output_level = !output_level;
vTaskDelay(pdMS_TO_TICKS(500));
}
}

Code Analysis

  • The code first iterates through selected GPIO pins, setting them to the same output level, then toggles the level synchronously using output_level = !output_level.
  • vTaskDelay(pdMS_TO_TICKS(500)) controls the blink period for easy observation of GPIO output changes.

02_BlinkRGB


Code

02_BlinkRGB.ino
while (true) {
// Calculate current color
led_strip_set_wheel(led_strip, wheel_pos);

// Refresh LED
led_strip_refresh(led_strip);

// Increment position (uint8_t automatically wraps to 0 after 255)
wheel_pos++;

vTaskDelay(pdMS_TO_TICKS(20));
}

Code Analysis

  • led_strip_set_wheel() computes the current color based on wheel_pos, ideal for creating a rainbow cycle effect.
  • A 20 ms delay after each led_strip_refresh() makes the color transitions appear smoother.

Operation Result

ESP32-C5-Zero
ESP32-C5-Zero
ESP32-C5-Zero

03_GetchipID


Code

03_GetchipID.ino
void app_main(void)
{
ESP_LOGI(log_tag, "--- Chip information example ---");

/* Get chip information */
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);

/* Print target and core count */
ESP_LOGI(log_tag, "Target: %s", CONFIG_IDF_TARGET);
ESP_LOGI(log_tag, "Cores: %d", chip_info.cores);

/* Get and print flash size */
uint32_t flash_size;
esp_flash_get_size(NULL, &flash_size);
ESP_LOGI(log_tag, "Flash size: %" PRIu32 " MB (%s)",
flash_size / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");

/* Print revision */
ESP_LOGI(log_tag, "Revision: %d", chip_info.revision);

/* Use default MAC address as a unique ID */
uint8_t mac[6];
esp_efuse_mac_get_default(mac);
ESP_LOGI(log_tag, "Unique ID (MAC): %02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

ESP_LOGI(log_tag, "------------------------");

/* Run forever */
while (true) {
vTaskDelay(pdMS_TO_TICKS(5000));
}
}

Code Analysis

  • esp_chip_info() reads basic hardware information such as core count and chip revision.
  • esp_efuse_mac_get_default() retrieves the default MAC address, which can be used as a unique device identifier.

Operation Result

ESP32-C5-Zero

04_BLE


Code

04_BLE.ino
void app_main(void) {
// 1. Initialize NVS (required for Bluetooth stack)
if (nvs_flash_init() != ESP_OK) {
nvs_flash_erase();
nvs_flash_init();
}

// 2. Initialize Bluetooth Controller
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
esp_bt_controller_init(&bt_cfg);
esp_bt_controller_enable(ESP_BT_MODE_BLE);

// 3. Initialize Bluedroid Stack
esp_bluedroid_init();
esp_bluedroid_enable();

// 4. Register GAP callback and configure advertising data
esp_ble_gap_register_callback(gap_event_handler);
esp_ble_gap_config_adv_data_raw(adv_data, sizeof(adv_data));

ESP_LOGI(TAG, "BLE stack initialized, setting up advertising...");
}

Code Analysis

  • The code first initializes NVS, the Bluetooth controller, and the Bluedroid stack – all prerequisites for BLE advertising.
  • esp_ble_gap_config_adv_data_raw() configures raw advertising data, after which the device becomes discoverable by external scanners.

Operation Result

ESP32-C5-Zero

05_UART


Code

05_UART.ino
void app_main(void) {
uart_config_t uart_cfg = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};

ESP_ERROR_CHECK(uart_param_config(UART_PORT, &uart_cfg));

ESP_ERROR_CHECK(uart_driver_install(UART_PORT, BUF_SIZE * 2, BUF_SIZE * 2, 0, NULL, 0));

ESP_ERROR_CHECK(uart_set_pin(UART_PORT, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));

xTaskCreate(rx_task, "uart_rx", 4096, NULL, 10, NULL);
xTaskCreate(tx_task, "uart_tx", 4096, NULL, 9, NULL);
}

Code Analysis

  • uart_param_config(), uart_driver_install() and uart_set_pin() configure the UART parameters, driver, and pin mapping respectively.
  • Finally, xTaskCreate() starts separate receive and transmit tasks, allowing UART reception and transmission to run concurrently.

Operation Result

ESP32-C5-Zero

06_WIFI_AP


Code

06_WIFI_AP.ino
void app_main(void) {
// 1. Initialize NVS (required for AP mode as well).
if (nvs_flash_init() != ESP_OK) {
nvs_flash_erase();
nvs_flash_init();
}

// 2. Initialize network stack and create the default AP netif.
esp_netif_init();
esp_event_loop_create_default();
esp_netif_create_default_wifi_ap();

// 3. Initialize WiFi driver and register event handler.
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&cfg);
esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_handler, NULL, NULL);

// 4. Configure AP parameters with designated initializer.
wifi_config_t ap_cfg = {
.ap = {
.ssid = SSID,
.password = PWD,
.ssid_len = 0, // Use null-terminated SSID string length.
.channel = 1,
.max_connection = 4,
.authmode = WIFI_AUTH_WPA2_PSK
},
};

// Switch to open mode when password is empty.
if (PWD[0] == '\0') ap_cfg.ap.authmode = WIFI_AUTH_OPEN;

esp_wifi_set_mode(WIFI_MODE_AP);
esp_wifi_set_config(WIFI_IF_AP, &ap_cfg);
esp_wifi_start();

ESP_LOGI(TAG, "AP Mode started. SSID: %s", SSID);
}

Code Analysis

  • This code configures the board as an AP (Access Point) using esp_wifi_set_mode(WIFI_MODE_AP) and esp_wifi_set_config().
  • If the password is empty, it automatically switches to open‑mode hotspot for quick connection testing.

Operation Result

ESP32-C5-Zero

07_WIFI_STA


Code

07_WIFI_STA.ino
void app_main(void) {
// 1. Initialize NVS (WiFi configuration needs to be stored in NVS)
if (nvs_flash_init() != ESP_OK) {
nvs_flash_erase();
nvs_flash_init();
}

// 2. Initialize network stack and underlying drivers
esp_netif_init();
esp_event_loop_create_default();
esp_netif_create_default_wifi_sta();

wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&cfg);

// 3. Register event handlers (handle all WiFi and IP related events)
esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID,
&wifi_handler, NULL, NULL);
esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
&wifi_handler, NULL, NULL);

// 4. Initialize GPIO26 as output
gpio_reset_pin(GPIO_NUM_26);
gpio_set_direction(GPIO_NUM_26, GPIO_MODE_OUTPUT);

GPIO26_ON();
// 4. Configure and start WiFi
wifi_config_t wifi_cfg = {
.sta =
{
.ssid = SSID,
.password = PWD,
},
};
esp_wifi_set_mode(WIFI_MODE_STA);
esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg);
esp_wifi_start();

ESP_LOGI(TAG, "WiFi station started.");
}

Code Analysis

  • esp_netif_create_default_wifi_sta() creates the default STA network interface for connecting to a router.
  • After registering Wi‑Fi and IP event callbacks, the program can execute corresponding logic upon successful connection or disconnection.

Operation Result

ESP32-C5-Zero

08_WIFI_StaticIP


Code

08_WIFI_StaticIP.ino
esp_netif_ip_info_t ip_info = {
.ip.addr = ipaddr_addr("192.168.1.77"),
.gw.addr = ipaddr_addr("192.168.1.1"),
.netmask.addr = ipaddr_addr("255.255.255.0")
};

Code Analysis

  • The esp_netif_ip_info_t structure is used to set a static IP address, gateway, and subnet mask in one go.
  • This approach is suitable for scenarios where a fixed device address is required, making it easy to access the board via a known IP address on the local network.

Operation Result

ESP32-C5-Zero

09_ZIGBEE


    1. Prepare two ESP32-C5-Zero development boards, ensuring they are powered correctly and ready for program flashing.
    1. Connect the first development board to the computer. Use the flashing tool to flash the HA_on_off_light program onto this board (this program controls the RGB LED). After flashing, keep the board powered on.
    1. Connect the second development board to the computer. Use the flashing tool to flash the HA_on_off_switch program onto this board (this program implements the control function via the BOOT button). After flashing, keep the board powered on.

Code

09_ZIGBEE.ino
void app_main(void)
{
esp_zb_platform_config_t config = {
.radio_config = ESP_ZB_DEFAULT_RADIO_CONFIG(),
.host_config = ESP_ZB_DEFAULT_HOST_CONFIG(),
};
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_zb_platform_config(&config));

xTaskCreate(esp_zb_task, "Zigbee_main", 4096, NULL, 5, NULL);
}

Code Analysis

  • esp_zb_platform_config() initializes the Zigbee platform layer, preparing the radio and host configuration.
  • xTaskCreate(esp_zb_task, ...) runs the Zigbee main task independently, facilitating network control logic expansion.

Operation Result

10_Mem_Security


Code

10_Mem_Security.ino
print_status();
print_privilege();
test_hw_crypto();
test_tee_apm();

Code Analysis

  • These lines display the current security status, privilege information, and test hardware cryptography as well as TEE/APM related functions.
  • Useful for quickly verifying whether the chip's security features are initialized correctly.