Skip to content

Entry Point Module

The entry point module is the single-file bridge between the ESP-IDF runtime and the entire ESP3D-X firmware. It consists of main/main.cpp, which contains only the mandatory app_main() function required by ESP-IDF. All real boot logic is delegated immediately to ESP3DX::begin(), making this module a thin but architecturally significant gateway.

// main/main.cpp — the complete file
static ESP3DX myTft;
extern "C" void app_main(void) { myTft.begin(); }

The ESP3DX class (defined in main/core/includes/esp3d_x.h, implemented in main/core/esp3d_x.cpp) orchestrates every subsystem startup in a strict, dependency-ordered sequence. Understanding this sequence is essential for anyone working on boot behavior, feature gating, or memory budgeting.


ESP-IDF Runtime

(FreeRTOS scheduler starts)

main/main.cpp

app_main()

ESP3DX::begin()

main/core/esp3d_x.cpp

BSP: board_init()

boards/<target>/components/bsp/

NVS Flash

Settings persistence

ESP3DSettings

NVS-backed config

Flash Filesystem

Flash + optional SD

ESP3DValues

Observable system state

ESP3DXUi → tft_ui_task

LVGL on Core 1

ESP3DXStream

GCode pipeline

ESP3DXNetwork → networkTask

WiFi / BT on Core 0

app_main() is called once by the ESP-IDF scheduler on Core 0 after all hardware peripherals are ready. It is a C-linkage symbol (extern "C") because the ESP-IDF startup code is C, while the firmware is C++.


instantiates &

calls begin()

#if ESP3D_BUZZER_FEATURE

#if ESP3D_SENSOR_FEATURE

#if ESP3D_LUA_INTERPRETER_FEATURE

#if ESP3D_CAMERA_FEATURE

main/main.cpp

esp3d_x.h / esp3d_x.cpp

ESP3DX

esp3d_log

Serial logging backend

board_init.h

BSP (board-specific)

nvs_flash (ESP-IDF)

esp3d_settings.h

ESP3DSettings

esp3d_flash.h / esp3d_sd.h

Filesystem

esp3d_update_service.h

OTA + resource update

esp3d_values.h

ESP3DValues

esp3d_translation_service.h

Translations

esp3d_x_ui.h

ESP3DXUi

esp3d_x_stream.h

ESP3DXStream

esp3d_x_network.h

ESP3DXNetwork

esp3d_sound.h

esp3d_sensor.h

EspLuaEngine

camera.h

Dashed lines represent compile-time optional subsystems controlled by CMake feature flags.


ESP3DX::begin() executes on the main task (Core 0) and follows a strict, sequential order. Steps marked [optional] are compiled in only when the corresponding CMake feature flag is enabled.

ESP3DXNetworkESP3DXStreamESP3DXUiESP3DValuesUpdateServiceFlash / SD FSESP3DSettingsnvs_flashboard_init()ESP3DX::begin()app_main()ESP-IDF RuntimeESP3DXNetworkESP3DXStreamESP3DXUiESP3DValuesUpdateServiceFlash / SD FSESP3DSettingsnvs_flashboard_init()ESP3DX::begin()app_main()ESP-IDF RuntimeESP3DX constructor → esp3d_log_init()[optional] Buzzer, Lua, Sensor, USB, CameraScans SD for firmware/config/resources - does NOT apply yetSpawns tft_ui_task on Core 1 (LVGL loop)Returns false - system rebootsSpawns networkTask on Core 0alt[Update pending [UPDATE_FEATURE]][No update]app_main() [Core 0]myTft.begin()nvs_flash_init() [erase if corrupt]board_init() [LCD, touch, LVGL tick]isValidSettingsNvs() → read or reset()flashFs.begin()sd.begin() [optional: SD_CARD_FEATURE]detect() [optional: UPDATE_FEATURE]esp3dXValues.initialize()esp3dTranslationService.begin() + esp3dXui.begin() [optional: DISPLAY_FEATURE]waitFirstFrameRendered(3000ms)begin() → apply update + rebootesp3dXstream.begin() [GCode pipeline]esp3dXnetwork.begin() [optional: WIFI or BT]return true
StepNotes
esp3d_log_init()Called in the ESP3DX constructor, before begin(). The serial log backend is active from the very first line.
board_init()BSP-specific. Initializes the display panel, touch controller, LVGL tick timer, and any board-specific GPIO. See Board Support Packages documentation.
NVS validationIf NVS is corrupt or version-mismatched, ESP3DSettings::reset() is called to restore factory defaults before anything else reads from settings.
esp3dXValues.initialize()Always runs regardless of the display feature flag. Network and CNC code may call set_value / get_value even on headless builds.
esp3dXui.begin()Returns immediately after spawning tft_ui_task. The UI runs independently on Core 1. The calling task only blocks when an update is pending.
Update pathIf an update is detected, begin() waits for the update screen to become visible (waitFirstFrameRendered), applies the update, then returns false. The system reboots. The normal boot path never executes.
esp3dXnetwork.begin()Spawns networkTask, which initializes the TCP/IP stack (esp_netif_init) and starts WiFi or Bluetooth depending on build configuration. WiFi and Bluetooth are mutually exclusive (hardware constraint).

The entry point’s behavior changes significantly depending on compile-time flags set in CMakeLists.txt:

CMake Feature Flags

ESP3D_DISPLAY_FEATURE

→ UI task, translations,

update screen

ESP3D_UPDATE_FEATURE

→ SD update detection &

application before normal boot

ESP3D_WIFI_FEATURE

→ networkTask with TCP/IP stack

ESP3D_BT_SERIAL_FEATURE /

ESP3D_BT_BLE_FEATURE

→ networkTask with Bluetooth

(mutually exclusive with WiFi)

ESP3D_SD_CARD_FEATURE

→ SD FS init, update detection

ESP3D_USB_SERIAL_FEATURE

→ USB OTG host init/deinit

ESP3D_BUZZER_FEATURE

→ sound module (esp3d_sound)

ESP3D_SENSOR_FEATURE

→ sensor.begin()

ESP3D_LUA_INTERPRETER_FEATURE

→ lua_interpreter.begin()

ESP3D_CAMERA_FEATURE

→ camera.begin()

See cmake/features.cmake for macro definitions and cmake/sanity_check.cmake for mutual-exclusion rules (e.g., WiFi + BT, socket client + WebUI).

main/CMakeLists.txt sources (a14):

  • TFT_UI_SERVICE with UI_TIER = SMALL compiles only display/small_ui (self-contained dashboard of the 1.47” boards, nothing from the pendant UI); any other tier compiles the full pendant UI.
  • USB_CDC_DEVICE_SERVICE adds modules/usb_cdc_device (USB CDC device client, see Communication_Transports.md).
  • ESP3D_LOG_BACKEND = 5 adds modules/log/usb_cdc (see logging_backends.md).

Once begin() completes successfully, the system stabilizes into the following task layout:

Shared State

Core 1

Core 0

main task

(app_main returns,

task is deleted)

networkTask

(ESP3DXNetwork)

streamTask

(ESP3DXStream)

esp3d_serial_rx_task

(optional)

usb_lib_task

(optional)

Camera task

(optional)

tft_ui_task

(LVGL handler)

ESP3DValues

(mutex-protected)

ESP3DSettings

(NVS)

⚠️ Critical constraint: LVGL is single-threaded and runs exclusively on Core 1 inside tft_ui_task. All other tasks must never call LVGL APIs directly. Shared data is exchanged through ESP3DValues (observable, mutex-protected). See UI Framework & Screens documentation for the full LVGL threading model.


When a firmware or resource update is detected on the SD card, the boot sequence diverges from normal operation:

No

Yes

No

Yes

Yes

No

begin() starts

FS + SD init

SD available?

Skip update detection

UpdateService::detect()

Update found?

esp3dXValues.initialize()

esp3dXui.begin()

esp3dXstream.begin()

esp3dXnetwork.begin()

return true - normal operation

esp3dXValues.initialize()

esp3dXui.begin()

shows update_screen

waitFirstFrameRendered 3000ms

UpdateService::begin()

apply firmware / resources / config

Success?

waitUpdateCompletionRendered

+ fixed delay

System reboot


ModuleRelationship
Core Platform & InfrastructureDefines ESP3DX, ESP3DSettings, ESP3DValues, ESP3DCommands, and the logging system initialized at boot
Board Support Packagesboard_init() called directly in begin() — provides display, touch, and LVGL tick for each hardware target
UI Framework & ScreensESP3DXUi::begin() starts the LVGL task; the entry point gates the update flow on waitFirstFrameRendered
CNC Firmware IntegrationESP3DXStream::begin() starts the GCode pipeline task after the update check
Network & Web ServicesESP3DXNetwork::begin() spawns the network task (WiFi or Bluetooth, build-exclusive)
Storage & ConfigurationFlash and SD filesystems initialized early in begin() before any service that reads files
Hardware Peripheral DriversLow-level drivers consumed by board_init() for display, touch, encoder, buzzer