Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 158 additions & 0 deletions ports/risc-v32/gnu/example_build/esp32c6/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#
# Copyright (c) 2026 Eclipse ThreadX contributors
#
# This program and the accompanying materials are made available under the
# terms of the MIT License which is available at
# https://opensource.org/licenses/MIT.
#
# SPDX-License-Identifier: MIT
#

cmake_minimum_required(VERSION 3.16)

# Generate compile_commands.json for clangd and IDE language servers
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Enforce Cross-Compilation Toolchain if not explicitly specified
if(NOT CMAKE_TOOLCHAIN_FILE)
set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/esp32c6-toolchain.cmake")
endif()

project(esp32c6_threadx_example C ASM)

# ------------------------------------------------------------------------------
# 1. ESP-IDF SDK Path Resolution (Cross-Platform: Windows & Linux)
# ------------------------------------------------------------------------------
if(ESP_IDF_PATH)
# User specified -DESP_IDF_PATH=/path/to/esp-idf on CMake command line
set(ESP_IDF_PATH "${ESP_IDF_PATH}")
elseif(DEFINED ENV{IDF_PATH})
# Standard Espressif environment variable set via export.sh / export.ps1
set(ESP_IDF_PATH "$ENV{IDF_PATH}")
else()
# Search standard Espressif installation directories across OSes without hardcoding version numbers
file(GLOB ESP_IDF_DEFAULT_PATHS
"C:/esp/*/esp-idf"
"C:/esp/esp-idf"
"$ENV{USERPROFILE}/esp/*/esp-idf"
"$ENV{USERPROFILE}/esp/esp-idf"
"$ENV{HOME}/esp/*/esp-idf"
"$ENV{HOME}/esp/esp-idf"
)
list(LENGTH ESP_IDF_DEFAULT_PATHS PATH_COUNT)
if(PATH_COUNT GREATER 0)
list(GET ESP_IDF_DEFAULT_PATHS 0 ESP_IDF_PATH)
else()
message(FATAL_ERROR "ESP-IDF SDK path not found. Please set the IDF_PATH environment variable or pass -DESP_IDF_PATH=/path/to/esp-idf.")
endif()
endif()

message(STATUS "Using ESP-IDF hardware headers from: ${ESP_IDF_PATH}")

# ------------------------------------------------------------------------------
# 2. Include Directories
# ------------------------------------------------------------------------------
# ESP32-C6 Hardware & SoC Component Headers
set(ESP32C6_IDF_INCLUDES
"${ESP_IDF_PATH}/components/soc/esp32c6/include"
"${ESP_IDF_PATH}/components/soc/esp32c6/register"
"${ESP_IDF_PATH}/components/soc/include"
"${ESP_IDF_PATH}/components/hal/include"
"${ESP_IDF_PATH}/components/hal/esp32c6/include"
"${ESP_IDF_PATH}/components/hal/platform_port/include"
"${ESP_IDF_PATH}/components/esp_hal_uart/include"
"${ESP_IDF_PATH}/components/esp_hal_uart/esp32c6/include"
"${ESP_IDF_PATH}/components/esp_rom/include"
"${ESP_IDF_PATH}/components/esp_rom/esp32c6/include"
"${ESP_IDF_PATH}/components/esp_common/include"
"${ESP_IDF_PATH}/components/esp_app_format/include"
"${ESP_IDF_PATH}/components/bootloader_support/include"
"${ESP_IDF_PATH}/components/riscv/include"
)

# ThreadX Core & Port Include Directories
set(THREADX_INCLUDES
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../../common/inc"
"${CMAKE_CURRENT_SOURCE_DIR}/../../inc"
"${CMAKE_CURRENT_SOURCE_DIR}/include"
)

include_directories(
${ESP32C6_IDF_INCLUDES}
${THREADX_INCLUDES}
)

# ------------------------------------------------------------------------------
# 3. ThreadX Static Library Target
# ------------------------------------------------------------------------------
file(GLOB THREADX_COMMON_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../common/src/*.c")
file(GLOB THREADX_PORT_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/../../src/*.S")

add_library(threadx STATIC
${THREADX_COMMON_SOURCES}
${THREADX_PORT_SOURCES}
)

target_include_directories(threadx PUBLIC ${THREADX_INCLUDES})

# ------------------------------------------------------------------------------
# 4. ESP32-C6 Board Support Object Library (Assembly Startup & Pinned HAL)
# ------------------------------------------------------------------------------
set(ESP32C6_BOARD_BSP_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/entry.S"
"${CMAKE_CURRENT_SOURCE_DIR}/vectors.S"
"${CMAKE_CURRENT_SOURCE_DIR}/tx_initialize_low_level.S"
"${CMAKE_CURRENT_SOURCE_DIR}/platform/console.c"
"${CMAKE_CURRENT_SOURCE_DIR}/platform/interrupt.c"
"${CMAKE_CURRENT_SOURCE_DIR}/platform/systimer.c"
"${CMAKE_CURRENT_SOURCE_DIR}/platform/startup.c"
"${ESP_IDF_PATH}/components/hal/systimer_hal.c"
)

add_library(esp32c6_bsp OBJECT
${ESP32C6_BOARD_BSP_SOURCES}
)
target_include_directories(esp32c6_bsp PUBLIC ${THREADX_INCLUDES} ${ESP32C6_IDF_INCLUDES})

# ------------------------------------------------------------------------------
# 5. Linker Configuration
# ------------------------------------------------------------------------------
set(ESP32C6_LINKER_SEARCH_PATHS
"${ESP_IDF_PATH}/components/soc/esp32c6/ld"
"${ESP_IDF_PATH}/components/esp_rom/esp32c6/ld"
)

set(ESP32C6_LINK_FLAGS "-T${CMAKE_CURRENT_SOURCE_DIR}/link.ld")
foreach(LD_PATH ${ESP32C6_LINKER_SEARCH_PATHS})
string(APPEND ESP32C6_LINK_FLAGS " -L${LD_PATH}")
endforeach()

# ------------------------------------------------------------------------------
# 6. Executable Firmware Target & Image Generation (.elf -> .bin)
# ------------------------------------------------------------------------------
add_executable(esp32c6_demo.elf
"${CMAKE_CURRENT_SOURCE_DIR}/demo_threadx.c"
$<TARGET_OBJECTS:esp32c6_bsp>
)

target_include_directories(esp32c6_demo.elf PUBLIC ${THREADX_INCLUDES} ${ESP32C6_IDF_INCLUDES})

target_link_options(esp32c6_demo.elf PRIVATE
"-T${CMAKE_CURRENT_SOURCE_DIR}/link.ld"
"-L${ESP_IDF_PATH}/components/soc/esp32c6/ld"
"-L${ESP_IDF_PATH}/components/esp_rom/esp32c6/ld"
)

target_link_libraries(esp32c6_demo.elf PRIVATE threadx)

# Locate Python interpreter for esptool.py image conversion
find_package(Python3 COMPONENTS Interpreter REQUIRED)

add_custom_command(TARGET esp32c6_demo.elf POST_BUILD
COMMAND ${Python3_EXECUTABLE} "${ESP_IDF_PATH}/components/esptool_py/esptool/esptool.py"
--chip esp32c6 elf2image -o "${CMAKE_CURRENT_BINARY_DIR}/esp32c6_demo.bin"
"${CMAKE_CURRENT_BINARY_DIR}/esp32c6_demo.elf"
COMMENT "Generating bootable ESP32-C6 binary image: esp32c6_demo.bin"
)

message(STATUS "ESP32-C6 ThreadX complete build system ready.")
40 changes: 40 additions & 0 deletions ports/risc-v32/gnu/example_build/esp32c6/NOTICE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Notices for Eclipse ThreadX ESP32-C6 Port & Example

This component contains software, hardware register definitions, linker scripts, and architectural patterns derived from third parties under open-source licenses.

---

## 1. Eclipse ThreadX

* **Copyright**: Copyright (c) 2024-present Microsoft Corporation; Copyright (c) 2026 Eclipse ThreadX contributors
* **License**: [MIT License](https://opensource.org/licenses/MIT)
* **Homepage**: https://github.com/eclipse-threadx/threadx

---

## 2. Espressif Systems (ESP-IDF)

This component incorporates hardware headers, linker script sections, ROM API definitions, and HAL drivers developed by Espressif Systems (Shanghai) CO LTD.

* **Copyright**: Copyright (c) 2018-2024 Espressif Systems (Shanghai) CO LTD
* **License**: [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
* **Homepage**: https://github.com/espressif/esp-idf

---

## 3. 10xEngineers (RISC-V32 ThreadX Port)

This component incorporates RISC-V32 port assembly templates and initialization hooks developed by 10xEngineers.

* **Copyright**: Copyright (c) 2025 10xEngineers
* **License**: [MIT License](https://opensource.org/licenses/MIT)

---

## 4. Zephyr RTOS Project

Architectural patterns and RISC-V PLIC claim/complete dispatch design concepts were informed by the Zephyr RTOS project.

* **Copyright**: Copyright (c) 2016-2024 Zephyr Project Contributors
* **License**: [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
* **Homepage**: https://zephyrproject.org
109 changes: 109 additions & 0 deletions ports/risc-v32/gnu/example_build/esp32c6/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<!--
Copyright (c) 2026 Eclipse ThreadX contributors

This program and the accompanying materials are made available under the
terms of the MIT License which is available at
https://opensource.org/licenses/MIT.

SPDX-License-Identifier: MIT
-->

# ESP32-C6 (RISC-V32) Bare-Metal ThreadX Example Build

This directory contains the **Eclipse ThreadX** bare-metal bring-up example for the **Espressif ESP32-C6** microcontroller board (`ESP32-C6-DevKitC-1`).

---

> [!WARNING]
> ### Current Project Status & Known Issues
>
> **This example build is currently INCOMPLETE and has active hardware bring-up issues:**
>
> 1. **Serial Output & Reset Loop**: When flashed to physical hardware (`write_flash 0x10000 build/esp32c6_demo.bin`), the serial monitor shows **no console output** and the board continuously resets every few seconds (watchdog / trap reset loop).
> 2. **Timer Interrupt Freeze**: When stepping through JTAG with OpenOCD/GDB, execution successfully reaches `thread_0_entry`. However, after calling `tx_thread_sleep()`, the ThreadX scheduler gets **stuck inside `_tx_thread_schedule_loop()`** at `wfi` because the 100 Hz SYSTIMER hardware tick interrupt is not advancing `_tx_timer_system_clock`.
>
> **Where to start for the next developer**:
> * Refer to [`threadx_ESP32C6_native_WIFI_plan.md`](threadx_ESP32C6_native_WIFI_plan.md) for the architectural blueprint.

---

## Architecture Overview

* **Target CPU**: ESP32-C6 High-Performance RISC-V32 Core (`rv32imac_zicsr_zifencei`, 160 MHz)
* **RTOS Kernel**: Eclipse ThreadX RISC-V32 GNU Port
* **Boot Chain**: Espressif Mask ROM $\rightarrow$ 2nd-Stage Bootloader $\rightarrow$ ThreadX Application Entry (`_start`)
* **Drivers Included**:
* Console UART Output (`esp_rom_output_tx_one_char`)
* RISC-V PLIC & ESP32-C6 Interrupt Matrix Router (`interrupt.c`)
* Hardware SYSTIMER 100 Hz Kernel Tick Driver (`systimer.c` using pinned `systimer_hal.c`)

---

## Build Prerequisites

Ensure the following tools are installed and present in your system `PATH`:

1. **Toolchain**: `riscv32-esp-elf-gcc` (Espressif RISC-V GCC 14+)
2. **Build System**: CMake 3.16+ and Ninja (or Make)
3. **Flash Tool**: `esptool.py` (Installed via `pip install esptool`)

---

## Building the Example Firmware

Run the following commands from this directory:

```bash
# Configure CMake build system
cmake -B build -DCMAKE_TOOLCHAIN_FILE=cmake/esp32c6-toolchain.cmake

# Build executable ELF and bootable binary image
cmake --build build
```

Upon successful compilation, the output artifacts will be placed under `build/`:
* `build/esp32c6_demo.elf`: Symbol-rich executable for OpenOCD/GDB debugging.
* `build/esp32c6_demo.bin`: Bootable binary image formatted for Espressif 2nd-stage bootloader.

---

## Flashing to ESP32-C6 Hardware

Connect your ESP32-C6 board via USB and run `esptool.py`:

```bash
esptool.py --chip esp32c6 -p COM3 -b 460800 write_flash 0x10000 build/esp32c6_demo.bin
```

*(Replace `COM3` with your operating system's serial port path, e.g. `/dev/ttyUSB0` on Linux).*

---

## Monitoring Serial Diagnostics

Open any serial terminal emulator (such as PuTTY, TeraTerm, or `idf_monitor`) configured for:
* **Baudrate**: 115200
* **Data bits**: 8
* **Stop bits**: 1
* **Parity**: None

---

## Hardware JTAG Debugging with OpenOCD & GDB

1. **Launch OpenOCD**:
```bash
openocd -f board/esp32c6-builtin.cfg
```
2. **Launch GDB**:
```bash
riscv32-esp-elf-gdb build/esp32c6_demo.elf
```
3. **Connect and Debug in GDB**:
```gdb
target remote :3333
mon reset halt
load
hbreak thread_0_entry
continue
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#
# Copyright (c) 2026 Eclipse ThreadX contributors
#
# This program and the accompanying materials are made available under the
# terms of the MIT License which is available at
# https://opensource.org/licenses/MIT.
#
# SPDX-License-Identifier: MIT
#

set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR riscv32)

# Prevent CMake from executing default compiler test executables during configuration
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

# Cross-Compilation Toolchain Binary Names
set(CMAKE_C_COMPILER "riscv32-esp-elf-gcc")
set(CMAKE_CXX_COMPILER "riscv32-esp-elf-g++")
set(CMAKE_ASM_COMPILER "riscv32-esp-elf-gcc")
set(CMAKE_AR "riscv32-esp-elf-ar")
set(CMAKE_OBJCOPY "riscv32-esp-elf-objcopy")
set(CMAKE_OBJDUMP "riscv32-esp-elf-objdump")
set(CMAKE_SIZE "riscv32-esp-elf-size")

# Target Architecture Flags for ESP32-C6 (RV32IMAC Zicsr Zifencei)
set(ESP32C6_TARGET_FLAGS "-march=rv32imac_zicsr_zifencei -mabi=ilp32 -mcmodel=medany -ffunction-sections -fdata-sections")

set(CMAKE_C_FLAGS_INIT "${ESP32C6_TARGET_FLAGS} -Wall -Wextra")
set(CMAKE_CXX_FLAGS_INIT "${ESP32C6_TARGET_FLAGS} -Wall -Wextra")
set(CMAKE_ASM_FLAGS_INIT "${ESP32C6_TARGET_FLAGS}")

# Search mode policies for bare-metal toolchains
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
Loading