Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .astyle-rules.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ submodules:
check: false
include:
- "/esp-stub-lib/"

libraries:
check: false
include:
- "src/miniz.*"
1 change: 1 addition & 0 deletions .check_copyright_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ ignore:
perform_check: false
include:
- src/ld
- src/miniz.*
88 changes: 88 additions & 0 deletions .github/workflows/build_and_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
name: Build and release

on: [push, pull_request]

jobs:
build_stubs:
runs-on: ubuntu-24.04

steps:
- name: Checkout ref commit
uses: actions/checkout@v4
with:
submodules: 'recursive'

- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: 3.13

- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install esptool

- name: Install toolchains
shell: bash
run: |
mkdir -p toolchains
pushd toolchains
../tools/setup_toolchains.sh
popd

- name: Build stub
shell: bash
run: |
source ./tools/export_toolchains.sh
./tools/build_all_chips.sh

- name: Upload stub JSONs
uses: actions/upload-artifact@v4
with:
path: build*/esp*.json
if-no-files-found: error
retention-days: 3

create_release:
name: Create GitHub release
needs: build_stubs
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- name: Get version
id: get_version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
shell: bash
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: 3.13
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install commitizen czespressif
- name: Generate changelog
run: |
cz changelog ${{ steps.get_version.outputs.VERSION }} --file-name changelog_body.md
cat changelog_body.md
- name: Download stub JSONs
uses: actions/download-artifact@v4
- name: Create release
id: create_release
uses: softprops/action-gh-release@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
body_path: changelog_body.md
name: Version ${{ steps.get_version.outputs.VERSION }}
draft: true
prerelease: false
fail_on_unmatched_files: true
files: artifact/esp*.json
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
src/build/
build*/
toolchains/
57 changes: 57 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
cmake_minimum_required(VERSION 3.28)

project(flasher-stub CXX)

option(TARGET_CHIP "Target ESP chip" "OFF")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there are no change requests in the review of the initial structure, esp-stub-lib will require the variable ESP_TARGET for the same purpose.

Copy link
Copy Markdown
Collaborator Author

@dobairoland dobairoland Apr 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understood your comment correctly then probably there will be a clash. I think we can address this as part of the follow-up task (#8).

We will adjust this project based on espressif/esp-stub-lib#3. No need to do it the other way.


if("${TARGET_CHIP}" STREQUAL "OFF")
message(FATAL_ERROR "Please set target chip via -DTARGET_CHIP.")
endif()

# CXX standard set based on the GCC version of the toolchain for ESP8266 (oldest one)
set(CUSTOM_FLAGS --std=gnu++17 -Wall -Wextra -Werror -Wshadow -Wundef -Wconversion -Os -fno-common -nostdlib -fno-builtin -Wl,-static -g -ffunction-sections -Wl,--gc-sections)
set(EXTRA_RISCV_FLAGS -march=rv32imc -mabi=ilp32 -msmall-data-limit=0)
set(EXTRA_XTENSA_FLAGS -mtext-section-literals -mlongcalls)

set(ESP8266_FLAGS "-DESP8266" ${EXTRA_XTENSA_FLAGS})
set(XTENSA_FLAGS "-DXTENSA" ${EXTRA_XTENSA_FLAGS})
set(RISCV_FLAGS "-DRISCV" ${EXTRA_RISCV_FLAGS})

message(STATUS "Building for ${TARGET_CHIP}")
add_executable(${TARGET_CHIP})

set(ESP32_XTENSA_CHIPS esp32 esp32s2 esp32s3)

if(TARGET_CHIP IN_LIST ESP32_XTENSA_CHIPS)
set(TOOLCHAIN_EXECUTABLE_PREFIX "xtensa-${TARGET_CHIP}-elf-")
set(CHIP_FLAGS "${XTENSA_FLAGS}")
elseif(TARGET_CHIP STREQUAL "esp8266")
set(TOOLCHAIN_EXECUTABLE_PREFIX "xtensa-lx106-elf-")
set(CHIP_FLAGS "${ESP8266_FLAGS}")
# The lx106 toolchain is of version 8.4 which doesn't support the --dependency-file linker option.
set(CMAKE_LINK_DEPENDS_USE_LINKER FALSE) # requires CMake 3.27 or higher
else()
set(TOOLCHAIN_EXECUTABLE_PREFIX "riscv32-esp-elf-")
set(CHIP_FLAGS "${RISCV_FLAGS}")
endif()

set(LINKER_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/src/ld")
set(CHIP_LINKER_SCRIPT "${LINKER_SCRIPTS_DIR}/${TARGET_CHIP}.ld")

target_compile_options(${TARGET_CHIP} PRIVATE
${CUSTOM_FLAGS}
${CHIP_FLAGS}
)

target_link_options(${TARGET_CHIP} PRIVATE
${CUSTOM_FLAGS}
${CHIP_FLAGS}
"-T${CHIP_LINKER_SCRIPT}"
-Wl,-Map=${CMAKE_BINARY_DIR}/${TARGET_CHIP}.map
)

set(CMAKE_CXX_COMPILER ${TOOLCHAIN_EXECUTABLE_PREFIX}g++)
set(CMAKE_LINKER ${TOOLCHAIN_EXECUTABLE_PREFIX}g++)
set(CMAKE_EXECUTABLE_SUFFIX_CXX ".elf")

add_subdirectory(${CMAKE_SOURCE_DIR}/src)
51 changes: 48 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,58 @@ This project is experimental and not yet ready for production use.

The project's goal is to replace the legacy [flasher stub of esptool](https://github.com/espressif/esptool-legacy-flasher-stub/) in the near future.

# How To Use
# Build Dependencies

### Submodules

The project depends on [esp-stub-lib](https://github.com/espressif/esp-stub-lib/) in the form of git submodule. Don't forget to get/update the submodule as well before building:

```sh
git submodule update --init --recursive
```

### Toolchains

You will need the following toolchains set up and available in your PATH:
1. [`xtensa-lx106-elf-*`](https://docs.espressif.com/projects/esp8266-rtos-sdk/en/latest/get-started/index.html#setup-toolchain)
2. [`xtensa-*-elf-*`](https://github.com/espressif/crosstool-NG)
3. [`riscv32-esp-elf-*`](https://github.com/espressif/crosstool-NG)

There is a convenience script for AMD64 Linux machines to download and install them into the `toolchains` directory:
```sh
mkdir -p toolchains
cd toolchains
../tools/setup_toolchains.sh
```

Then run the following export script in every terminal where the project is used:
```sh
. ./tools/export_toolchains.sh
```

# How to Build

### Build for one selected chip target

```sh
mkdir -p build
cmake . -B build -G Ninja -DTARGET_CHIP=esp32s2 # Replace with your desired chip, e.g. esp32, esp8266
ninja -C build
```

### Build for all supported chip targets

```sh
./tools/build_all.sh
```

# How To Use With Esptool

1. Install esptool in [development mode](https://docs.espressif.com/projects/esptool/en/latest/esp32/contributing.html#development-setup).
2. Obtain the flasher stub binaries as JSON files either from the [releases page](https://github.com/espressif/esp-flasher-stub) or from the artifacts of your pull request.
3. Replace the esptool's JSONs files in the `esptool/targets/stub_flasher` directory with the obtained JSON files.

## Contributing
# Contributing

Please install the [pre-commit](https://pre-commit.com/) hooks to ensure that your commits are properly formatted:

Expand All @@ -34,6 +79,6 @@ git push --tags
```
Create a pull request and edit the automatically created draft [release notes](https://github.com/espressif/esp-flasher-stub/releases).

## License
# License

This document and the attached source code are released as Free Software under either the [Apache License Version 2](LICENSE-APACHE) or [MIT License](LICENSE-MIT) at your option.
15 changes: 15 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
set(COMMON_SOURCES "main.cpp")

target_sources(${TARGET_CHIP} PRIVATE ${COMMON_SOURCES})

if(${TARGET_CHIP} STREQUAL "esp8266")
# zlib library will be available in esp-stub-lib. So miniz probably won't be needed

# -Wconversion produces a warning in miniz.cpp
get_target_property(comp_opts esp8266 COMPILE_OPTIONS)
list(REMOVE_ITEM comp_opts -Wconversion)

add_library(miniz_obj OBJECT miniz.cpp)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can remove miniz files.
OpenOCD will also need zlib library. You will be able to call it from the library.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for pointing this out. I added a comment here for the future.

I'd like to keep this for now. It took me a while to figure out how to change the flags for source files individually. I'd like to keep it here as example. We will try to keep miniz for now, test the new stub and then possible switch if it will be reasonably. But it is also possible that we will keep using miniz until the approaching end-of-life of ESP8266 as the stub for it rarely needs update these days.

target_compile_options(miniz_obj PRIVATE ${comp_opts})
target_sources(esp8266 PRIVATE $<TARGET_OBJECTS:miniz_obj>)
endif()
27 changes: 27 additions & 0 deletions src/ld/esp32.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* Note: stub is deliberately loaded close to the very top
of available RAM, to reduce change of colliding with anything
else... */
MEMORY {
iram : org = 0x400BE000, len = 0x1000
dram : org = 0x3ffcc000, len = 0x14000
}

ENTRY(esp_main)

SECTIONS {
.text : ALIGN(4) {
*(.literal)
*(.text .text.*)
} > iram

.bss : ALIGN(4) {
_bss_start = ABSOLUTE(.);
*(.bss)
_bss_end = ABSOLUTE(.);
} > dram

.data : ALIGN(4) {
*(.data)
*(.rodata .rodata.*)
} > dram
}
24 changes: 24 additions & 0 deletions src/ld/esp32c3.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
MEMORY {
iram : org = 0x40380000, len = 0x4000
dram : org = 0x3FC84000, len = 0x18000
}

ENTRY(esp_main)

SECTIONS {
.text : ALIGN(4) {
*(.literal)
*(.text .text.*)
} > iram

.bss : ALIGN(4) {
_bss_start = ABSOLUTE(.);
*(.bss)
_bss_end = ABSOLUTE(.);
} > dram

.data : ALIGN(4) {
*(.data)
*(.rodata .rodata.*)
} > dram
}
30 changes: 30 additions & 0 deletions src/ld/esp8266.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* Note: stub is deliberately loaded close to the very top
of available RAM, to reduce change of colliding with anything
else... */
MEMORY {
iram : org = 0x4010D000, len = 0x2100
dram : org = 0x3FFE8100, len = 0x13f00
}

ENTRY(esp_main_esp8266)

SECTIONS {
.text : ALIGN(4) {
*(.literal)
*(.text .text.*)
} > iram

.bss : ALIGN(4) {
_bss_start = ABSOLUTE(.);
*(.bss)
_bss_end = ABSOLUTE(.);
} > dram

.data : ALIGN(4) {
*(.data)
*(.rodata .rodata.*)
} > dram
}

PROVIDE(SPIFlashModeConfig = 0x40004568);
PROVIDE(SPIParamCfg = 0x40004c2c);
21 changes: 21 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/

extern "C" void esp_main(void) __attribute__((used));

#ifdef ESP8266
__asm__(
".global esp_main_esp8266\n"
".literal_position\n"
".align 4\n"
"esp_main_esp8266:\n"
"movi a0, 0x400010a8;"
"j esp_main;");
#endif //ESP8266

extern "C" void esp_main(void)
{
}
Loading
Loading