This tutorial walks you through:
hello_world sample for an ESP32‑C6 targetZephyr’s official Getting Started Guide is the source of truth for host setup (Ubuntu/macOS/Windows), Python environment, west, and SDK installation. Reference: https://docs.zephyrproject.org/latest/develop/getting_started/index.html
Below is a practical “do this in order” setup that follows that guide.
Follow the Install dependencies step for your OS in Zephyr’s Getting Started Guide (Ubuntu/macOS/Windows). Guide: https://docs.zephyrproject.org/latest/develop/getting_started/index.html
Typical things you’ll need include: Python 3, CMake, Ninja, Git, and system build tools.
Pick a workspace folder. In this tutorial I’ll use ~/zephyrproject on Linux/macOS.
(Windows users can use something like C:\zephyrproject.)
# Linux/macOS mkdir -p ~/zephyrproject cd ~/zephyrproject python3 -m venv .venv source .venv/bin/activate
On Windows PowerShell (example):
mkdir C:\zephyrproject cd C:\zephyrproject py -m venv .venv .\.venv\Scripts\Activate.ps1
Zephyr’s official west install guide: https://docs.zephyrproject.org/latest/develop/west/install.html
pip install -U west
# Still inside ~/zephyrproject (or your chosen folder) west init -m https://github.com/zephyrproject-rtos/zephyr --mr main west update
Export Zephyr’s CMake package (so CMake can find Zephyr):
west zephyr-export
Install Python requirements for Zephyr and its modules:
west packages pip --install
(That exact command appears in the Getting Started flow and is commonly the next step after west update.)
Zephyr SDK documentation: https://docs.zephyrproject.org/latest/develop/toolchains/zephyr_sdk.html
Install the Zephyr SDK for your OS, then ensure your environment can find it (either via the SDK setup script registering it, or via environment variables like ZEPHYR_SDK_INSTALL_DIR / ZEPHYR_TOOLCHAIN_VARIANT=zephyr).
Note: ESP32‑C6 is RISC‑V based, so you’ll need the RISC‑V toolchain that’s included with the Zephyr SDK.
Zephyr’s Espressif HAL requires binary blobs (RF calibration, etc.). Zephyr board docs for Espressif boards call this out and recommend fetching after west update.
Example (ESP32 DevKitC doc): it explicitly instructs west blobs fetch hal_espressif.
Run:
# From your workspace root (~/zephyrproject)
west blobs fetch hal_espressif
If you skip this, you may see build or runtime failures for ESP32 targets.
Sparrow is not (yet) an upstream Zephyr board, so we need a compatible Zephyr board definition to build/flash a first image.
You have two reasonable approaches:
This tutorial focuses on A to get you a successful first boot quickly, and then outlines B.
Zephyr includes the Seeed Studio XIAO ESP32C6 board, which is explicitly documented as an ESP32‑C6 board with 4MB of flash and a USB‑C port for programming/debugging. Board doc: https://docs.zephyrproject.org/latest/boards/seeed/xiao_esp32c6/doc/index.html
Important: this board has two cores (HP + LP). A Zephyr issue notes you must specify the core qualifier, e.g.:
xiao_esp32c6/esp32c6/hpcore (High‑Performance core)xiao_esp32c6/esp32c6/lpcore (Low‑Power core)
Source: Zephyr issue describing valid targets for xiao_esp32c6.
For “Hello World”, use HP core.
Why this is good for Sparrow:
Limitations:
Zephyr’s ESP32‑C6‑DevKitC documentation states the module has 8 MB flash. Doc: https://docs.zephyrproject.org/latest/boards/espressif/esp32c6_devkitc/doc/index.html
If you build with that board unmodified, you risk generating a partition layout that assumes 8 MB.
Zephyr supports applying build “snippets” to override common settings. Snippets can be applied with the -S option to west build.
Docs: https://docs.zephyrproject.org/latest/build/snippets/using.html
Many Espressif boards support snippet variants like flash-4M / flash-8M (the XIAO ESP32C6 page lists these variants).
So you *can* build with DevKitC + -S flash-4M — but for Sparrow, using a 4 MB native board definition (XIAO) is usually cleaner.
This section is where the Sparrow‑specific “special care” matters:
We will:
1. create a small application folder 2. add a devicetree overlay that selects the USB serial device for console 3. build and flash
From your Zephyr workspace root:
cd ~/zephyrproject mkdir -p sparrow_hello cd sparrow_hello
Create these files:
CMakeLists.txtprj.confsrc/main.cboards/You can copy the sample hello_world, but I recommend creating a tiny app so you fully control the console configuration.
CMakeLists.txt
cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(sparrow_hello) target_sources(app PRIVATE src/main.c)
src/main.c
#include <zephyr/kernel.h> #include <zephyr/sys/printk.h> int main(void) { printk("Hello World from Sparrow (ESP32-C6)!\n"); while (1) { k_sleep(K_SECONDS(1)); } return 0; }
prj.conf (minimal logging/console)
# Serial/console CONFIG_SERIAL=y CONFIG_CONSOLE=y CONFIG_PRINTK=y CONFIG_UART_CONSOLE=y # Useful for seeing logs immediately CONFIG_LOG=y CONFIG_LOG_MODE_IMMEDIATE=y
On ESP32 chips with a USB Serial/JTAG device exposed to Zephyr as a UART, you can route the console by changing the devicetree chosen nodes.
A Zephyr issue discussing USB serial output on ESP32 shows an overlay pattern like:
zephyr,console to &usb_serialusb_serial node
(See Zephyr issue #60825 about using usb_serial for console on ESP32-class devices.)
Create the overlay directory:
mkdir -p boards
Because the board target includes qualifiers, Zephyr looks for overlay filenames like:
boards/xiao_esp32c6_esp32c6_hpcore.overlayCreate:
boards/xiao_esp32c6_esp32c6_hpcore.overlay
/ {
chosen {
zephyr,console = &usb_serial;
zephyr,shell-uart = &usb_serial;
zephyr,uart-mcumgr = &usb_serial;
};
};
&usb_serial {
status = "okay";
};
Why this matters for Sparrow:
ESP32‑C6’s USB Serial/JTAG is implemented entirely in hardware (fixed‑function serial+JTAG). (Espressif docs: USB Serial/JTAG controller for ESP32‑C6.)
Activate your Python venv first if it isn’t active:
cd ~/zephyrproject source .venv/bin/activate
Then build:
# Build into a local build folder: west build -b xiao_esp32c6/esp32c6/hpcore -d build_sparrow .
If you get an error about “Board qualifiers not found”, ensure you used the full target name including /esp32c6/hpcore.
(See the Zephyr issue listing valid xiao_esp32c6 targets.)
Connect Sparrow over USB‑C.
Then flash:
west flash -d build_sparrow --runner esp32
If west flash doesn’t pick the correct port automatically, the ESP32 west runner supports options including –esp-device (serial port), –esp-baud-rate, and –esp-flash-size. A Zephyr ESP32 runner option list (mirrored documentation) shows:
–esp-device ESP_DEVICE (serial port to flash; default uses $ESPTOOL_PORT or auto‑scan)–esp-baud-rate–esp-flash-size (default “detect”)Example (Linux):
west flash -d build_sparrow --runner esp32 -- --esp-device /dev/ttyACM0
Example (Windows):
west flash -d build_sparrow --runner esp32 -- --esp-device COM7
Port naming tip (Sparrow’s USB vs DevKitC USB‑UART):
Sparrow uses the native USB mapping (per your note), so expect ttyACM rather than ttyUSB on Linux.
If flashing fails with “could not connect”, try:
–esp-baud-rate 115200You have two common options:
west espressif monitor.screen, minicom, PuTTY, etc.Example with west:
west espressif monitor -d build_sparrow
If you need to choose the port explicitly, note that older Zephyr tooling discussions show the monitor supports a -p (port) style option; if your environment doesn’t, use a standard serial terminal as a fallback.
Fallback example (Linux):
screen /dev/ttyACM0 115200
If everything is wired correctly, you should see:
Hello World from Sparrow (ESP32-C6)!
If you used xiao_esp32c6, you’re already matching a documented 4MB ESP32‑C6 board.
(Zephyr XIAO ESP32C6 board doc.)
If you instead build with an ESP32‑C6 board definition that assumes 8 MB (like DevKitC), use a flash size snippet.
Zephyr’s snippet system is applied with west build -S <snippet>.
Docs: https://docs.zephyrproject.org/latest/build/snippets/using.html
Example (conceptual):
west build -b esp32c6_devkitc/esp32c6/hpcore -S flash-4M samples/hello_world
The XIAO ESP32C6 board documentation lists snippet variants like flash-4M / flash-8M / flash-16M / flash-32M / flash-64M. Use the one that matches your module.
(Zephyr XIAO ESP32C6 board doc.)
Once you move beyond hello_world (I2C sensors, neopixel, display, external SPI flash, etc.), you should create a Sparrow Zephyr board definition.
High-level steps:
1. Create an out‑of‑tree board folder, e.g.: * ''<your_workspace>/modules/your_sparrow_board/boards/espressif/esp32c6_sparrow/'' 2. Start from a close upstream template: * ''boards/seeed/xiao_esp32c6'' (4MB, USB‑C) * or ''boards/espressif/esp32c6_devkitc'' (upstream Espressif board) 3. Update the board devicetree: * set correct GPIOs for I2C (SDA/SCL), neopixel pin, SPI chip selects, etc. * include external SPI NOR flash on the pins listed in the Sparrow README (FLASH_CS GPIO23, MOSI GPIO7, MISO GPIO2, SCK GPIO6, etc.) 4. Keep the console routed to USB Serial/JTAG (as shown in the overlay earlier) if Sparrow has no USB‑UART bridge. 5. Add/adjust partitioning for **4 MB** internal flash (and optionally define external flash partitions for storage).
Sparrow’s README lists the peripheral pin mapping (I2C on GPIO21/22, neopixel on GPIO3, shared SPI bus pins, etc.). Source: https://github.com/FarhadGUL06/esp32-c6-sparrow
When your out‑of‑tree board is ready, you can build with:
west build -b esp32c6_sparrow .
(How you register out‑of‑tree boards depends on whether you keep them in your application tree, a module, or a separate repo; Zephyr’s “Modules” documentation explains module discovery and board discovery concepts.)
If west flash complains about missing esptool.py, it usually means your Espressif HAL/tools were not fully fetched or your environment is inconsistent.
Double-check:
west updatewest blobs fetch hal_espressif (and didn’t ignore errors)west packages pip –install)There are Zephyr discussions where users hit “esptool.py not found” when their module/tools were missing. (Search for that message if you encounter it.)
Symptoms:
Actions:
dmesg | tail -n 50 ls -l /dev/ttyACM* /dev/ttyUSB* 2>/dev/null
west flash -d build_sparrow --runner esp32 -- --esp-device /dev/ttyACM0
&usb_serial.Common causes:
Fixes:
xiao_esp32c6/esp32c6/hpcore → boards/xiao_esp32c6_esp32c6_hpcore.overlaywest build -p always -b xiao_esp32c6/esp32c6/hpcore -d build_sparrow .