Chapter 6: Device Configuration and menuconfig System

Chapter Objectives

By the end of this chapter, you will be able to:

  • Understand the purpose and importance of project configuration in ESP-IDF.
  • Explain what Kconfig is and how it’s used in ESP-IDF to define configuration options.
  • Describe the role of the sdkconfig file in storing project configurations and sdkconfig.defaults for setting initial values.
  • Learn how to launch and navigate the menuconfig interface, both the text-based version (idf.py menuconfig) and the graphical editor in VS Code.
  • Practice modifying common configuration settings such as log levels, task stack sizes, and compiler optimizations.
  • Understand how configuration choices impact the build process and the final application behavior.
  • Effectively search for specific configuration options within menuconfig.
  • Be aware of how different ESP32 variants might present different sets of configuration options.

Introduction

In the preceding chapters, you’ve successfully set up your development environment, created your first “Hello World” project, and learned about the tools for building and flashing firmware. While the default settings often work for basic examples, real-world embedded applications require fine-tuning. You might need to enable specific hardware features, adjust performance parameters, optimize for power consumption, or manage memory resources carefully. This is where project configuration comes into play.

The ESP-IDF provides a powerful and flexible configuration system based on Kconfig, the same system used by the Linux kernel. This system allows you to customize nearly every aspect of the framework and its components. The primary tool you’ll use to interact with this system is menuconfig. This chapter will guide you through understanding and using menuconfig to tailor your ESP32 projects precisely to your needs, ensuring your application runs efficiently and reliably.

Theory

What is Configuration in Embedded Systems?

In embedded systems development, “configuration” refers to the process of setting parameters and selecting options that define how the software (firmware) and hardware components of your system will behave. Unlike desktop applications that might load settings from a file at runtime, embedded systems often bake these configurations directly into the firmware image at compile time. This is done for efficiency, reliability, and to optimize resource usage on constrained devices.

Examples of configurable aspects in ESP-IDF include:

  • Hardware Features: Enabling or disabling peripherals like Wi-Fi, Bluetooth, specific UARTs, or I2C interfaces.
  • Driver Parameters: Setting default baud rates for UART, SPI clock speeds, or I2C addresses.
  • System Behavior: Configuring FreeRTOS task stack sizes, tick rates, or heap allocation strategies.
  • Network Settings: Default Wi-Fi credentials, TCP/IP stack options (like buffer sizes, maximum connections).
  • Logging: Setting the verbosity level for system logs (e.g., Error, Warning, Info, Debug, Verbose).
  • Security Features: Enabling flash encryption or secure boot.
  • Compiler Optimizations: Choosing between optimizing for speed, size, or debugging.

The Kconfig System

ESP-IDF uses the Kconfig system to manage its vast array of configuration options. Kconfig originated from the Linux kernel project and is designed to handle complex hierarchical configurations effectively.

  • Kconfig Files: The configuration options themselves are defined in text files named Kconfig. Each component within ESP-IDF (e.g., freertos, esp_wifi, driver) typically has its own Kconfig file. These files define:
    • Options (Symbols): The actual configuration items, such as CONFIG_ESP_WIFI_ENABLED.
    • Types: Options can be boolean (bool), string (string), integer (int), or hexadecimal (hex).
    • Prompts: The descriptive text displayed to the user in menuconfig.
    • Defaults: Default values for the options.
    • Dependencies: Rules that specify if an option depends on another (e.g., “Bluetooth Classic options” depends on “Bluetooth enabled”). This allows menuconfig to show or hide options based on other selections.
    • Help Text: Detailed explanations for each option.
    • Menus and Choices: Structuring options into logical groups and allowing selection from a set of mutually exclusive choices.

A project can also have a top-level Kconfig.projbuild file to define project-specific configuration options.

%%{ init: { 'theme': 'base', 'themeVariables': { 'fontFamily': 'Open Sans' } } }%%
graph TD
    subgraph ESP_IDF_Installation
        direction LR
        IDF_ROOT["esp-idf/"]
        COMPONENTS_DIR["components/"]
        IDF_ROOT --> COMPONENTS_DIR

        subgraph ComponentA ["component_A/ (e.g., wifi)"]
            KCONFIG_A["Kconfig"]
        end
        subgraph ComponentB ["component_B/ (e.g., freertos)"]
            KCONFIG_B["Kconfig"]
        end
        subgraph ComponentC ["component_C/ (e.g., driver)"]
            KCONFIG_C["Kconfig"]
        end
        COMPONENTS_DIR --> ComponentA
        COMPONENTS_DIR --> ComponentB
        COMPONENTS_DIR --> ComponentC
    end

    subgraph Your_ESP_IDF_Project
        direction LR
        PROJECT_ROOT["my_project/"]
        PROJ_KCONFIG["Kconfig.projbuild <br> (Optional project-specific options)"]
        SDKCONFIG_DEFAULTS["sdkconfig.defaults <br> (Optional default values)"]
        PROJECT_ROOT --> PROJ_KCONFIG
        PROJECT_ROOT --> SDKCONFIG_DEFAULTS
    end

    MENUCONFIG_TOOL["menuconfig Tool <br> (idf.py menuconfig or VS Code UI)"]

    KCONFIG_A --> MENUCONFIG_TOOL
    KCONFIG_B --> MENUCONFIG_TOOL
    KCONFIG_C --> MENUCONFIG_TOOL
    PROJ_KCONFIG -- Defines options for --> MENUCONFIG_TOOL
    SDKCONFIG_DEFAULTS -- Provides initial values to --> MENUCONFIG_TOOL

    MENUCONFIG_TOOL -- Saves user selections to --> SDKCONFIG_FILE["sdkconfig <br> (Project's final configuration)"]
    PROJECT_ROOT --> SDKCONFIG_FILE


    classDef idfStyle fill:#EDE9FE,stroke:#5B21B6,stroke-width:1px,color:#5B21B6;
    classDef projectStyle fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF;
    classDef toolStyle fill:#FEF3C7,stroke:#D97706,stroke-width:2px,color:#92400E;
    classDef outputStyle fill:#D1FAE5,stroke:#059669,stroke-width:2px,color:#065F46;

    class IDF_ROOT,COMPONENTS_DIR,ComponentA,ComponentB,ComponentC,KCONFIG_A,KCONFIG_B,KCONFIG_C idfStyle;
    class PROJECT_ROOT,PROJ_KCONFIG,SDKCONFIG_DEFAULTS projectStyle;
    class MENUCONFIG_TOOL toolStyle;
    class SDKCONFIG_FILE outputStyle;

    style ESP_IDF_Installation fill:#f0f0f0,stroke:#333,stroke-width:1px
    style Your_ESP_IDF_Project fill:#f0f0f0,stroke:#333,stroke-width:1px

The sdkconfig File: Your Project’s Configuration Snapshot

When you configure your project using menuconfig and save the changes, all your selections are stored in a file named sdkconfig located in the root directory of your project.

  • Content: The sdkconfig file contains lines that define C preprocessor macros or other build system variables. For example:CONFIG_ESP_WIFI_ENABLED=y CONFIG_LOG_DEFAULT_LEVEL_INFO=y CONFIG_FREERTOS_HZ=100 CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
  • Role in Build Process: During compilation, the build system automatically processes sdkconfig and generates a C header file (typically build/config/sdkconfig.h). This header file is then implicitly included in all source files compiled for your project. This makes the CONFIG_... macros available in your C code, allowing for conditional compilation and parameterization.#ifdef CONFIG_ESP_WIFI_ENABLED // Code to initialize Wi-Fi #endif int tick_rate = CONFIG_FREERTOS_HZ;
  • Version Control: The sdkconfig file is crucial as it defines the specific build and behavior of your application. It is highly recommended to commit your sdkconfig file to your version control system (e.g., Git) alongside your source code.
  • Warning: You should almost never edit the sdkconfig file directly. Always use menuconfig (or the VS Code SDK Configuration editor) to modify your project’s configuration. Manual edits can be overwritten or lead to an inconsistent project state.

The menuconfig Tool: Your Configuration Interface

menuconfig is the interactive tool that allows you to browse, search, and modify the Kconfig options for your project.

  • Launching:
    • From the ESP-IDF Terminal: idf.py menuconfig
    • From VS Code: Click the “gear” icon (SDK Configuration editor) in the status bar, or use the Command Palette (Ctrl+Shift+P or Cmd+Shift+P) and search for ESP-IDF: SDK Configuration editor.
  • Interface:
    • Text-Based UI (TUI): The idf.py menuconfig command launches a TUI that you navigate using keyboard shortcuts.[Insert screenshot of the idf.py menuconfig text-based interface, showing a menu structure.]
    • Graphical UI (VS Code): The VS Code extension provides a graphical wrapper around menuconfig, making it more mouse-friendly, but it presents the same options and structure.[Insert screenshot of the VS Code SDK Configuration editor graphical interface.]
  • Navigation (TUI):
    • Arrow Keys (Up/Down): Move between options.
    • Enter: Select a menu or edit an option.
    • Spacebar: Toggle boolean options ([*], [ ]) or select choices.
    • Esc Esc (Escape twice): Go back to the previous menu or exit.
    • Y: Select a boolean option (set to Yes/True).
    • N: Deselect a boolean option (set to No/False).
    • ?: View help for the selected option.
    • /: Search for an option by keyword.
  • Option Symbols:
    • [ ]: Boolean option, currently disabled.
    • [*]: Boolean option, currently enabled.
    • (text): String or integer option, value is text.
    • < >: Option that, when selected, saves current config and exits.
    • --->: Sub-menu.

sdkconfig.defaults: Setting Project Defaults

You can provide a set of default configuration values for your project by creating a file named sdkconfig.defaults in the root directory of your project.

  • Purpose:
    • To establish a baseline configuration for a new project checkout. If sdkconfig does not exist when menuconfig is run or the project is built, it will be created using the values from sdkconfig.defaults as a starting point.
    • To define different build profiles (e.g., sdkconfig.defaults.debug, sdkconfig.defaults.release). You can specify which defaults file to use with idf.py -D SDKCONFIG_DEFAULTS="filename" build.
  • Format: Same format as the sdkconfig file (e.g., CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y).
  • Behavior: Values in sdkconfig.defaults are overridden by any values explicitly set and saved in sdkconfig via menuconfig.
%%{ init: { 'theme': 'base', 'themeVariables': { 'fontFamily': 'Open Sans' } } }%%
graph TD
    A["Project Checkout / Initial State"] --> B{sdkconfig file exists?};
    B -- No --> C["Create new sdkconfig"];
    C --> D{sdkconfig.defaults exists?};
    D -- Yes --> E["Load values from sdkconfig.defaults into new sdkconfig"];
    E --> F["Load ESP-IDF default values for remaining options"];
    D -- No --> F;
    F --> G["menuconfig / Build Process uses this sdkconfig"];

    B -- Yes --> H["Use existing sdkconfig"];
    H --> I{Run menuconfig?};
    I -- Yes --> J["User modifies settings in menuconfig"];
    J -- Saves changes to --> H;
    I -- No (Direct Build) --> G;


    subgraph Legend
        direction LR
        L_START[Start/Decision]
        L_PROCESS[Process Step]
        L_FILE[File]
    end

    classDef startStyle fill:#FEF3C7,stroke:#D97706,stroke-width:1px,color:#92400E;
    classDef processStyle fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF;
    classDef fileStyle fill:#D1FAE5,stroke:#059669,stroke-width:1px,color:#065F46;

    class A,B,D,I startStyle;
    class C,E,F,G,J processStyle;
    class H fileStyle;
    class SDKCONFIG_DEFAULTS fileStyle;


    %% Invisible node for sdkconfig.defaults to link to D
    SDKCONFIG_DEFAULTS_NODE[sdkconfig.defaults]:::fileStyle
    subgraph ProjectFiles [Project Files]
        SDKCONFIG_DEFAULTS_NODE
    end
    SDKCONFIG_DEFAULTS_NODE -.-> D

    style Legend fill:#f9f9f9,stroke:#ccc,stroke-width:1px
    class L_START startStyle;
    class L_PROCESS processStyle;
    class L_FILE fileStyle;

How Configuration Affects the Build

The choices you make in menuconfig (and save to sdkconfig) directly influence the compilation and linking process:

  1. Conditional Compilation: C preprocessor directives like #ifdef CONFIG_FEATURE_X, #if CONFIG_VALUE > 10 are used throughout ESP-IDF and your application code to include or exclude blocks of code.
  2. Macro Expansion: CONFIG_ values are used as constants or parameters in the code.
  3. Component Inclusion: Some components might only be compiled and linked if a specific CONFIG_ option is enabled.
  4. Linker Scripts: Configuration can affect how memory regions are defined and used by the linker.

This powerful system allows ESP-IDF to be highly adaptable, enabling you to create firmware images that are optimized for your specific application by including only the necessary features and configuring them appropriately.

Practical Examples

Let’s get hands-on with menuconfig using the hello_world project from Chapter 4.

Prerequisites:

  • Your hello_world project open in VS Code.
  • ESP32 board connected.
  • Correct target and serial port selected in VS Code.

1. Launching menuconfig

  • Using the ESP-IDF Terminal:
    1. Open the ESP-IDF Terminal in VS Code (Command Palette: ESP-IDF: Open ESP-IDF Terminal).
    2. Type idf.py menuconfig and press Enter.
    3. The text-based menuconfig interface will appear in the terminal.
  • Using the VS Code GUI:
    1. Click the SDK Configuration editor icon (looks like a gear) in the VS Code status bar.
    2. A new tab will open with the graphical menuconfig interface.

For the following examples, you can use either method. The navigation and options are the same.

2. Navigating and Understanding the Interface

  • Explore: Use arrow keys (TUI) or your mouse (GUI) to navigate through the main menu items like SDK tool configuration, Serial flasher config, Component config, etc.
  • Help: In the TUI, select an option and press ? to see its help text. In the GUI, help text is often displayed alongside the option.
  • Search: In the TUI, press /, type a keyword (e.g., “log”), and press Enter. menuconfig will show all options matching that keyword. In the GUI, there’s usually a search bar at the top.

3. Modifying Common Configuration Settings

Let’s change a few settings in your hello_world project.

A. Change Default Log Verbosity:

Logs are essential for debugging. Let’s increase the default verbosity.

  1. Navigate to: Component config —> Log output —>
  2. Select Default log verbosity.
  3. Change it from Info to Debug or Verbose. (In TUI, press Enter, use arrow keys to select, press Enter again. In GUI, use the dropdown).
  4. Observe: Notice how other related options might become visible or change.

B. Change Main Task Stack Size:

The app_main function runs in a FreeRTOS task. Its stack size can be configured.

  1. Navigate to: Component config —> ESP System Settings —>
  2. Select Main task stack size.
  3. Note the current value (e.g., 3584).
  4. Change it to a slightly different value, for example, 4096. (In TUI, press Enter, type the new value, press Enter. In GUI, edit the text box).

C. Change Compiler Optimization Level:

This affects code size and performance.

  1. Navigate to: Compiler options —>
  2. Select Optimization Level.
  3. The default is often Debug (-Og). Change it to Optimize for size (-Os).

4. Saving Configuration and Observing Effects

  1. Save Changes:
    • TUI: Navigate to < Save > at the bottom of the main menu and press Enter. Confirm saving to sdkconfig. Then navigate to < Exit > and press Enter (or press Esc multiple times).
    • GUI: There’s usually a “Save” button or it might save automatically when you close the menuconfig tab. Check for prompts.
  2. Rebuild the Project:
    • Click the “Build” icon in the VS Code status bar or run idf.py build in the ESP-IDF Terminal.
    • The build system will detect changes in sdkconfig and recompile necessary files.
  3. Flash and Monitor:
    • Flash the newly built firmware to your ESP32.
    • Open the serial monitor.
    • Observe: If you changed the log level to Debug or Verbose, you should see significantly more output from the ESP-IDF system components during boot-up and potentially from your application if it uses different log levels. The hello_world example itself primarily uses printf, which is not directly affected by ESP-IDF log levels, but system messages will change.
  4. Check sdkconfig File:
    • Open the sdkconfig file in your project’s root directory using the VS Code editor.
    • Search for the options you changed, e.g., CONFIG_LOG_DEFAULT_LEVEL, CONFIG_MAIN_TASK_STACK_SIZE, CONFIG_COMPILER_OPTIMIZATION_SIZE. You should see their new values reflected.

5. Searching for an Option

Imagine you want to find settings related to Wi-Fi power save modes but don’t know where they are.

  1. Open menuconfig.
  2. Search:
    • TUI: Press /, type wifi power save, and press Enter. A list of matching symbols and their locations will appear. Select one to jump to it.
    • GUI: Use the search bar at the top. Type wifi power save. Matching options will be highlighted or filtered.
  3. Explore the found options.

Variant Notes

The Kconfig system is designed to be target-aware. The options presented in menuconfig can and will change based on the specific ESP32 variant you have selected for your project (idf.py set-target <chip_name> or via the VS Code target selector).

  • Hardware-Specific Options:
    • ESP32 vs. ESP32-S3: If your target is ESP32-S3, you’ll see options related to its dual-core LX7 processors, AI acceleration capabilities, and USB OTG. These won’t be present if the target is the original ESP32 (LX6). Conversely, Bluetooth Classic (BR/EDR) options are available for ESP32 but not for ESP32-S3 (which only has BLE).
    • ESP32-C3 (RISC-V): Options specific to the RISC-V architecture or its single-core nature will appear.
    • ESP32-C6 (Wi-Fi 6, 802.15.4): You will find configuration sections for Wi-Fi 6 (802.11ax) and the IEEE 802.15.4 radio (for Thread/Zigbee), which are absent for older variants.
    • ESP32-H2 (802.15.4, BLE, No Wi-Fi): Wi-Fi configuration sections will be missing entirely. Options will focus on BLE and IEEE 802.15.4.
  • Peripheral Availability: The number of available UARTs, ADC channels, or specific timers can differ between variants, and menuconfig might reflect this by enabling/disabling or limiting the range of certain configuration options.
  • Kconfig Dependencies: Component Kconfig files use depends on SOC_SUPPORTS_BT or depends on SOC_RISCV_CORE (these are illustrative, actual Kconfig symbols might vary) to conditionally include options. The build system defines these SOC_... symbols based on the selected target.

Tip: Always ensure your project target is correctly set before running menuconfig to see the accurate and relevant set of options for your hardware. If you switch targets, it’s a good practice to run menuconfig again to review and adjust settings, as some previous settings might become invalid or new defaults might apply.

Common Mistakes & Troubleshooting Tips

  1. Mistake: Manually editing the sdkconfig file.
    • Fix: Never do this. Always use idf.py menuconfig or the VS Code SDK Configuration editor. If sdkconfig becomes corrupted, delete it. The build system will regenerate it (using sdkconfig.defaults if it exists, or ESP-IDF defaults otherwise), and you can then re-apply your custom settings via menuconfig.
  2. Mistake: Forgetting to save changes in menuconfig before exiting.
    • Fix: Be mindful when exiting menuconfig. The TUI will prompt if there are unsaved changes. Ensure you explicitly save if you want to keep your modifications.
  3. Mistake: Configuration changes not taking effect in the application.
    • Fix: You must rebuild the project (idf.py build or VS Code build button) after saving changes in menuconfig. The build process uses the updated sdkconfig to recompile code and generate new firmware.
  4. Mistake: An option seems to be missing or is greyed out in menuconfig.
    • Fix:
      • Ensure the correct ESP32 target is selected for your project. Some options are target-specific.
      • The option might depend on another parent option being enabled. Check the help text (? in TUI) for the option or its parent menu for dependencies. For example, specific Wi-Fi features might only be configurable if “Wi-Fi” itself is enabled.
  5. Mistake: Project fails to build after a git pull from a repository or after updating ESP-IDF, due to sdkconfig changes or new required options.
    • Fix: The build system often prompts you to run idf.py menuconfig to resolve new symbols or conflicts. Do this. Review any new options (often marked with (NEW)). Save the configuration. Sometimes, a idf.py fullclean followed by setting the target and running menuconfig from scratch (using sdkconfig.defaults if you have one) is the most straightforward way to resolve complex configuration mismatches.

Exercises

  1. Using sdkconfig.defaults:
    1. In your hello_world project, create a new file named sdkconfig.defaults.
    2. Add the following line to sdkconfig.defaults: CONFIG_LOG_DEFAULT_LEVEL_VERBOSE=y
    3. If an sdkconfig file already exists in your project root, delete it.
    4. Open menuconfig (either idf.py menuconfig or the VS Code editor).
    5. Navigate to Component config --> Log output --> Default log verbosity. What is the selected level? Does it reflect the setting from sdkconfig.defaults?
    6. Save the configuration from menuconfig (this will create a new sdkconfig file). Verify its content.
  2. Impact of Optimization on Firmware Size:
    1. Ensure your hello_world project is configured with Compiler options --> Optimization Level set to Debug (-Og).
    2. Build the project and run idf.py size. Note down the “Total Sketch Sise” (or “Total image size”).
    3. Open menuconfig and change Compiler options --> Optimization Level to Optimize for size (-Os).
    4. Save the configuration, rebuild the project, and run idf.py size again.
    5. Compare the total firmware size with the previous one. Did it change as expected?
  3. Target-Specific Option Investigation (e.g., ESP32-C6 vs. ESP32):
    1. If you have an ESP32-C6 board (or can just set the target):
      • Set your project target to esp32c6 (idf.py set-target esp32c6).
      • Open menuconfig. Look for options under Component config related to Wi-Fi 6 (802.11ax) or IEEE802.15.4 (Thread/Zigbee).
    2. Now, set your project target to esp32 (the original ESP32).
    3. Open menuconfig again. Are the Wi-Fi 6 or IEEE802.15.4 options still present in the same way? Explain why they might differ or be absent.
    • (If you don’t have a C6, pick another distinct feature: e.g., for ESP32-S3, look for “AI Acceleration” options under ESP System Settings, and compare with ESP32 target.)
  4. Finding and Understanding a Deeply Nested Option:
    1. Suppose you want to configure the NVS (Non-Volatile Storage) library’s page size.
    2. Open menuconfig. Use the search function (/ in TUI, or search bar in GUI) to find “NVS page size”.
    3. Navigate to this option. What is its full path in the menu structure? (e.g., Component config --> NVS Flash --> ...)
    4. View the help text for this option (? in TUI). What are the available choices or range for this setting? What does the help text suggest about its usage?

Summary

  • Project configuration is vital for tailoring ESP-IDF applications to specific needs and hardware.
  • ESP-IDF uses the Kconfig system, with options defined in Kconfig files within components.
  • The sdkconfig file in your project root stores your chosen configurations and should be version-controlled. It should not be edited manually.
  • menuconfig (idf.py menuconfig or the VS Code SDK Configuration editor) is the tool used to interactively modify these settings.
  • sdkconfig.defaults can be used to provide a baseline project configuration.
  • Configuration choices (stored as CONFIG_... macros) directly influence the build process through conditional compilation and parameterization.
  • The set of available options in menuconfig is target-dependent, adapting to the capabilities of the selected ESP32 variant.
  • Always rebuild your project after changing sdkconfig for the modifications to take effect.

Further Reading

Mastering menuconfig is a key skill for any ESP32 developer. It unlocks the full power and flexibility of the ESP-IDF. In the following chapters, as we explore various peripherals and features, you’ll frequently return to menuconfig to enable and configure them.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top