diff --git a/.github/workflows/esp32-mkimage.yaml b/.github/workflows/esp32-mkimage.yaml index f7baaf2a36..1735718eb3 100644 --- a/.github/workflows/esp32-mkimage.yaml +++ b/.github/workflows/esp32-mkimage.yaml @@ -125,7 +125,7 @@ jobs: shell: bash working-directory: ./src/platforms/esp32/ run: | - cp sdkconfig.release-defaults sdkconfig.defaults + cp sdkconfig.release-defaults.in sdkconfig.defaults.in - name: "Build ${{ matrix.soc }}${{ matrix.flavor }} with idf.py" shell: bash @@ -138,19 +138,14 @@ jobs: mv partitions${{ matrix.flavor }}.csv partitions.csv fi idf.py set-target ${{ matrix.soc }} - idf.py reconfigure idf.py build - name: "Create a ${{ matrix.soc }}${{ matrix.flavor }} image" working-directory: ./src/platforms/esp32/build run: | - if [ -z "${{ matrix.flavor }}" ] + ./mkimage.sh + if [ -n "${{ matrix.flavor }}" ] then - ./mkimage.sh - else - FLAVOR_SUFFIX=$(echo "${{ matrix.flavor }}" | sed 's/-//g') - BOOT_FILE="../../../../build/libs/esp32boot/${FLAVOR_SUFFIX}_esp32boot.avm" - ./mkimage.sh --boot "$BOOT_FILE" mv atomvm-${{ matrix.soc }}.img atomvm-${{ matrix.soc }}${{ matrix.flavor }}.img fi ls -l *.img diff --git a/CHANGELOG.md b/CHANGELOG.md index 87918e9643..4ad064754c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added `proc_lib` - Added gen_server support for timeout tuples in callback return actions introduced in OTP-28. - Added `sys` +- Added ESP32 `-DATOMVM_ELIXIR_SUPPORT=on` configuration option +- Added support for ESP32 development builds to include NVS partition data at build time ### Changed @@ -81,6 +83,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `binary_to_integer/1` no longer accepts binaries such as `<<"0xFF">>` or `<<" 123">>` - `binary_to_integer` and `list_to_integer` do not raise anymore `overflow` error, they raise instead `badarg`. +- ESP32 cmake build options are now also exposed in `idf.py menuconfig`. +- ESP32 Elixir support is determined automatically from the offset of `boot.avm` in the partiton +table. +- ESP32 ports now flash a complete working image using the `idf.py flash` task. +- ESP32 platform now uses reproducible builds. ### Fixed diff --git a/CMakeModules/GetVersion.cmake b/CMakeModules/GetVersion.cmake index 4ec7fe95a3..971b8d0e43 100644 --- a/CMakeModules/GetVersion.cmake +++ b/CMakeModules/GetVersion.cmake @@ -18,7 +18,9 @@ # SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later # -include(${CMAKE_SOURCE_DIR}/version.cmake) +if (!ATOMVM_BASE_VERSION) + include(${CMAKE_SOURCE_DIR}/version.cmake) +endif() if (ATOMVM_DEV) set(ATOMVM_GIT_REVISION "") diff --git a/UPDATING.md b/UPDATING.md index f905f1681c..f3bcb35f82 100644 --- a/UPDATING.md +++ b/UPDATING.md @@ -19,6 +19,17 @@ bitshifts: e.g. `(16#FFFF band 0xF) bsl 252`. - `binary_to_integer` and `list_to_integer` do not raise `overflow` error anymore, they instead raise `badarg` when trying to parse an integer that exceeds 256 bits. Update any relevant error handling code. +- ESP32 builds with Elixir support may be configured without making changes to git tracked files +using `idf.py -DATOMVM_ELIXIR_SUPPORT=on set-target ${CHIP}` instead of copying +partitions-elixir.csv to partitions.csv. This configures the build to use partitions-elixir.csv for +the partition table. The `main.avm` offset in the partition table will determine which flavor of +esp32boot libraries to include for the `idf.py flash` task and the image assembled by +`build/mkimage.sh`. +- ESP32 release builds may be configured with `idf.py -DATOMVM_RELEASE=on set-target ${CHIP}` +rather than copy sdkconfig.release-defaults.in to sdkconfig.defaults.in (which still requires a +`reconfigure` or `set-target` to be run to pick up the changes), this may also be combined with the +`ATOMVM_ELIXIR_SUPPORT` option. For example, an Elixir supported release build is configured using: +`idf.py -DATOMVM_ELIXIR_SUPPORT=on -DATOMVM_RELEASE=on set-target ${CHIP}` ## v0.6.4 -> v0.6.5 diff --git a/doc/src/build-instructions.md b/doc/src/build-instructions.md index ea1251a126..3ff1cbfe77 100644 --- a/doc/src/build-instructions.md +++ b/doc/src/build-instructions.md @@ -207,7 +207,10 @@ Tests for the following libraries are supported: Building AtomVM for ESP32 must be done on either a Linux or MacOS build machine. -In order to build a complete AtomVM image for ESP32, you will also need to build AtomVM for the Generic UNIX platform (typically, the same build machine you are suing to build AtomVM for ESP32). +In order to build a complete AtomVM image for ESP32, you will also need to build AtomVM for the Generic UNIX platform (typically, the same build machine you are suing to build AtomVM for ESP32). This is expected to +be done before building an ESP32 port, since the BEAM libraries packed into the esp32boot.avm (or +elixir_esp32boot.avm for Elixir supported builds) are created at the same time as the atomvmlib.avm +libraries as part of the generic UNIX build. ### ESP32 Build Requirements @@ -239,29 +242,31 @@ $ cd $ cd src/platforms/esp32 ``` -If you want to build an image with Elixir modules included you must first have a version of Elixir installed that is compatible with your OTP version, then add the following line to sdkconfig.defaults: +Start by configuring the default build configuration of local `sdkconfig` for your target device: + ```shell -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-elixir.csv" +$ idf.py set-target ${CHIP} ``` -Start by updating the default build configuration of local `sdkconfig` file via the `idf.py reconfigure` command: +If you want to build a deployment with Elixir modules included you must first have a version of Elixir +installed that is compatible with your OTP version, and instead use the command: ```shell -$ idf.py set-target esp32 -$ idf.py reconfigure +idf.py -DATOMVM_ELIXIR_SUPPORT=on set-target ${CHIP}` ``` ```{tip} -For those familiar with esp-idf the build can be customized using `menuconfig` instead of -`reconfigure`: +For those familiar with esp-idf the build can be customized using `menuconfig`: + $ idf.py set-target ${CHIP} $ idf.py menuconfig This command will bring up a curses dialog box where you can make adjustments such as not including AtomVM components that are not desired in a particular build. You can also change the behavior of a -crash in the VM to print the error and reboot, or halt after the error is printed. Extreme caution -should be used when changing any non AtomVM settings. You can quit the program by typing `Q`. -Save the changes, and the program will exit. +crash in the VM to print the error and reboot, or halt after the error is printed. To configure an +Elixir supported build under the "Partition Table" setting select the Custom partitions CSV file and +set this to `partitions-elixir.csv`. Extreme caution should be used when changing any non AtomVM +settings. You can quit the program by typing `Q`. Save the changes, and the program will exit. ``` You can now build AtomVM using the build command: @@ -270,19 +275,99 @@ You can now build AtomVM using the build command: $ idf.py build ``` -This command, once completed, will create the Espressif bootloader, partition table, and AtomVM binary. The last line of the output should read something like the following: +This command, once completed, will create the Espressif bootloader, partition table, and AtomVM binary. The last line of the output should read something like the following example: + +``` +Project build complete. To flash, run: + idf.py flash +or + idf.py -p PORT flash +or + python -m esptool --chip esp32 -b 921600 --before default_reset --after hard_reset write_flash --flash_mode dio --flash_size 4MB --flash_freq 40m 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/atomvm-esp32.bin 0x1d0000 ../../../build/libs/esp32boot/esp32boot.avm +or from the "/home/joe/AtomVM/src/platforms/esp32/build" directory + python -m esptool --chip esp32 -b 921600 --before default_reset --after hard_reset write_flash "@flash_args" +``` + +```{important} +When using the `@flash_args` method be sure to execute from +/src/platforms/esp32/build. +``` + +At this point, you can run `idf.py flash` and have a complete working image. In some development +scenarios is may be helpful to use `idf.py app-flash` (to only flash a new AtomVM binary to the +`factory` partition) to avoid re-flashing the entire image if no changes were made to the Erlang or +Elixir libraries, and the partition table has not been altered. If you have made changes to the +sdkconfig file (using `idf.py menuconfig` or by other means) it may be necessary to also update the +bootloader using `idf.py bootloader-flash`. As with most other `idf.py` commands these may be +combined (for example: `idf.py bootloader-flash app-flash`). For more information about these +partitions and the flash partitions layout see [Flash Layout](#flash-layout) below. + +To build a single binary image file see [Building a Release Image](#building-a-release-image), below. + +#### NVS Partition Provisioning + +For streamlining deployment of images for an environment developers may pre-provision NVS partition +data. This is done by creating a file in the AtomVM/src/platforms/esp32 directory named +`nvs_partition.csv`, an example called `nvs_partition.csv-example` is provided in the same +directory. If this file exists it will be included by the mkimage.sh script in the build directory. +The partition is not included in the `idf.py flash` task so that settings made by applications can +be retained. To update changes or restore to the defaults defined in `nvs_partition.csv` delete the +generated `build/nvs.bin` file (if present) and execute the command `idf.py nvs-flash`. + +This is a more detailed example, with explanations of the structure: + +```{csv} +key,type,encoding,value +network,namespace,, +ssid,data,binary,"NETWORK_NAME" +psk,data,binary,"PASSWORD" +settings,namespace,, +feature0,data,binary,"1" +extra_feature,data,binary,"0" +token,file,binary,/path/to/file +``` + +Let's break this down line by line: - Project build complete. To flash, run this command: - ~/.espressif/python_env/idf5.1_py3.11_env/bin/python ~/esp/esp-idf-v5.1/components - /esptool_py/esptool/esptool.py -p (PORT) -b 921600 --before default_reset - --after hard_reset --chip esp32 write_flash --flash_mode dio --flash_size detect - --flash_freq 40m 0x1000 build/bootloader/bootloader.bin 0x8000 - build/partition_table/partition-table.bin 0x10000 build/atomvm-esp32.bin - or run 'idf.py -p (PORT) flash' +```csv +key,type,encoding,value +``` +This is the header describing the columns. It is important that there is no whitespace at the end of each line +and none separating the commas (`,`) throughout this file. -At this point, you can run `idf.py flash` to upload the 3 binaries up to your ESP32 device, and in some development scenarios, this is a preferable shortcut. +```csv +network,namespace,, +``` +The first entry should have a "key" name and have type "namespace". The namespaces are the same +used to look up the keys with +[esp:nvs_get_binary/2 (or /3)](./apidocs/erlang/eavmlib/esp.md#nvs_get_binary2). Note that the +`encoding` and `value` are empty. -However, first, we will build a single binary image file containing all of the above 3 binaries, as well as the AtomVM core libraries. See [Building a Release Image](#building-a-release-image), below. But first, it is helpful to understand a bit about how the AtomVM partitioning scheme works, on the ESP32. +```csv +ssid,data,binary,"NETWORK_NAME" +... +``` +The keys must use encoding type `binary` as this is the only type currently supported by AtomVM. + +```csv +settings,namespace,, +... +``` +Multiple namespaces may be used for separation, followed by their keys. + +```csv +token,file,binary,/path/to/file +``` +External file contents may be included + +The initial values flashed to the `nvs` partition may be changed by applications using +[esp:nvs_put_binary/3](./apidocs/erlang/eavmlib/esp.md#nvs_put_binary3). If you wish to make +changes to the partition data and re-flash without rebuilding and flashing the entire AtomVM build +you may delete the generated `build/nvs.bin` file and run `idf.py nvs-flash`, this will regenerate +and flash the `nvs` partition. + +For more information about the format of this file see Espressif's +[documentation for the NVS generator file format](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/storage/nvs_partition_gen.html#csv-file-format). ### Running tests for ESP32 @@ -415,18 +500,18 @@ The flash layout is roughly as follows (not to scale): | partition table | 3KB | +-----------------+ | | | | - | NVS | 24KB | + | nvs | 24KB | | | | +-----------------+ | | PHY_INIT | 4KB | +-----------------+ | AtomVM | | | binary | | | image - | | | | AtomVM | | - | Virtual | 1.75MB | - | Machine | | + | Virtual | | + | Machine | 1.75MB | | | | + | (factory) | | | | | +-----------------+ | | boot.avm | 256-512KB v @@ -472,7 +557,7 @@ and `boot.avm` partitions. ### Building a Release Image -The `/tools/release/esp32` directory contains the `mkimage.sh` script that can be used to create a single AtomVM image file, which can be distributed as a release, allowing application developers to develop AtomVM applications without having to build AtomVM from scratch. +The `/src/platforms/esp32/build` directory contains the `mkimage.sh` script that can be used to create a single AtomVM image file, which can be distributed as a release, allowing application developers to develop AtomVM applications without having to build AtomVM from scratch. ```{attention} Before running the `mkimage.sh` script, you must have a complete build of both the esp32 project, as well as a full @@ -482,9 +567,17 @@ core Erlang libraries will be written to the `build/libs` directory in the AtomV you target a different build directory when running CMake. ``` -Running this script will generate a single `atomvm-.img` file in the `build` directory of the esp32 source tree, where `` is the git hash of the current checkout. This image contains the ESP32 bootloader, AtomVM executable, and the `eavmlib` and `estdlib` Erlang libraries in one file, which can then be flashed to address `0x1000` for the esp32. The bootloader address varies for other chip variants. See the [flashing a binary image to ESP32](./getting-started-guide.md#flashing-a-binary-image-to-esp32) section of the [Getting Started Guide](./getting-started-guide.md) for a chart with the bootloader offset address of each model. +Running this script will generate a single `atomvm-.img` file in the `build` directory +of the esp32 source tree, where `` is the device configured with `set-target`. This +image contains the ESP32 bootloader, AtomVM executable, and the `eavmlib` and `estdlib` Erlang +libraries (and `exavmlib` Elixir libraries if configured for Elixir support) in one file, which can +then be flashed to address `0x1000` for the esp32. The bootloader address varies for other chip +variants. See the +[flashing a binary image to ESP32](./getting-started-guidemd#flashing-a-binary-image-to-esp32) +section of the [Getting Started Guide](./getting-started-guide.md) for a chart with the bootloader +offset address of each model. -To build a thin image with only Erlang libraries `mkimage.sh` script is run from the `src/platform/esp32` directory as follows: +To build a complete image use this command from the `src/platform/esp32` directory as follows: ```shell $ ./build/mkimage.sh @@ -496,18 +589,6 @@ Wrote AtomVM Virtual Machine at offset 0x10000 (65536) Wrote AtomVM Core BEAM Library at offset 0x1D0000 (1114112) ``` -To build a full image with Erlang and Elixir libraries the path to the previously (during the generic_unix build) built `elixir_esp32boot.avm` must be passed to the `mkimage.sh` script as follows (Note: this is still run from the AtomVM/src/platforms/esp32 directory for the relative path to work - feel free to use the absolute path to this file): - -```shell -$ ./build/mkimage.sh --boot ../../../build/libs/esp32boot/elixir_esp32boot.avm -Writing output to /home/joe/AtomVM/src/platforms/esp32/build/atomvm-esp32.img -============================================= -Wrote bootloader at offset 0x1000 (4096) -Wrote partition-table at offset 0x8000 (32768) -Wrote AtomVM Virtual Machine at offset 0x10000 (65536) -Wrote AtomVM Core BEAM Library at offset 0x1D0000 (1114112) -``` - Users can then use the `esptool.py` directly to flash the entire image to the ESP32 device, and then flash their applications to the `main.app` partition at address `0x210000`, (or `0x250000` for Elixir images) But first, it is a good idea to erase the flash, e.g., @@ -602,7 +683,7 @@ applications for the AtomVM platform. #### Flashing the core libraries -If you are doing development work on the core Erlang/Elixir libraries and wish to test changes that do not involve the `C` code in the core VM you may flash `esp32boot.avm` (or `elixir_esp32boot.avm` when using an Elixir partition table) to the boot.avm partition (offset 0x1D0000) by using the `flash.sh` script in the esp32 build directory as follows: +If you are doing development work on the core Erlang/Elixir libraries and wish to test changes that do not involve the `C` code in the core VM you may flash `esp32boot.avm` or `elixir_esp32boot.avm` to the boot.avm partition by using the `flash.sh` script in the esp32 build directory as follows: ```shell $ build/flash.sh -l ../../../build/libs/esp32boot.avm @@ -636,6 +717,13 @@ Leaving... Hard resetting via RTS pin... ``` +```{attention} +It is important that you flash the `esp32boot` variant that matches the configuration used to +create the build currently on the device. Flashing `elixir_esp32boot.avm` to a device that was not +flashed with an Elixir support build will not work, AtomVM will still try to load an application +from an address that is now occupied by the `exavmlib` modules. +``` + ### Adding custom Nifs, Ports, and third-party components While AtomVM is a functional implementation of the Erlang virtual machine, it is nonetheless designed to allow developers to extend the VM to support additional integrations with peripherals and protocols that are not otherwise supported in the core virtual machine. @@ -651,7 +739,9 @@ documentation. The instructions for adding custom Nifs and ports differ in slight detail, but are otherwise quite similar. In general, they involve: 1. Adding the custom Nif or Port to the `components` directory of the AtomVM source tree. -1. Run `idf.py reconfigure` to pick up any menuconfig options, many extra drivers have an option to disable them (they are enabled by default). Optionally use `idf.py menuconfig` and confirm the driver is enabled and save when quitting. +1. Run `idf.py set-target ${CHIP}` to pick up any menuconfig options, many extra drivers have an +option to disable them (they are enabled by default). Optionally use `idf.py menuconfig` and +confirm the driver is enabled and save when quitting. 1. Building the AtomVM binary. ```{attention} diff --git a/doc/src/programmers-guide.md b/doc/src/programmers-guide.md index 69932fd3d4..c13d0e7abd 100644 --- a/doc/src/programmers-guide.md +++ b/doc/src/programmers-guide.md @@ -163,6 +163,22 @@ Deployment of the AtomVM virtual machine and an AtomVM application currently req For more information about deploying the AtomVM image and AtomVM applications to your device, see the [Getting Started Guide](./getting-started-guide.md) +```note +The ESP32 platform uses reproducible builds, this has an effect when doing advanced debugging with +GDB because paths are altered to strip away leading paths that are substituted with the following +placeholders: + +* Path to ESP-IDF is replaced with /IDF +* Path to the project is replaced with /IDF_PROJECT +* Path to the build directory is replaced with /IDF_BUILD +* Paths to components are replaced with /COMPONENT_NAME_DIR (where NAME is the name of the +component) + +For information on how to configure GDB for debugging reproducible builds consult the ESP-IDF +documentation about +[Reproducible Builds and Debugging](https://docs.espressif.com/projects/esp-idf/en/v5.5/esp32/api-guides/reproducible-builds.html#reproducible-builds-and-debugging). +``` + ## Applications An AtomVM application is a collection of BEAM files, aggregated into an AtomVM "Packbeam" (`.avm`) file, and typically deployed (flashed) to some device. These BEAM files be be compiled from Erlang, Elixir, or any other language that targets the Erlang VM. @@ -1582,7 +1598,7 @@ The read options take the form of a proplist, if the key `raw` is true (`{raw, t If the key `voltage` is true (or simply appears in the list as an atom), then a calibrated voltage value will be returned in millivolts in the second element of the returned tuple. Otherwise, this element will be the atom `undefined`. -You may specify the number of samples (1 - 100000) to be taken and averaged over using the tuple `{samples, Samples :: 1..100000}`, the default is `64`. +You may specify the number of samples (1 - 100000) to be taken and averaged over using the tuple `{samples, Samples :: 1..100000}`, the default is `64`. ```{warning} Using a large number of samples can significantly increase the amount of time before a response, up to several seconds. diff --git a/src/platforms/esp32/.gitignore b/src/platforms/esp32/.gitignore new file mode 100644 index 0000000000..932b2b26ca --- /dev/null +++ b/src/platforms/esp32/.gitignore @@ -0,0 +1,8 @@ +# Copyright 2017-2025 Davide Bettio +# Copyright 2025 Winford (UncleGrumpy) +# +# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later + +sdkconfig.defaults +sdkconfig.old +nvs_partition.csv diff --git a/src/platforms/esp32/CMakeLists.txt b/src/platforms/esp32/CMakeLists.txt index 9dec6ec5f3..fbdd9abf70 100644 --- a/src/platforms/esp32/CMakeLists.txt +++ b/src/platforms/esp32/CMakeLists.txt @@ -54,6 +54,19 @@ set(AVM_SELECT_IN_TASK ON) # JIT is not available yet on esp32 set(AVM_DISABLE_JIT ON) +## Configure partition table based on boot flavor +if (${ATOMVM_ELIXIR_SUPPORT}) + set(AVM_PARTITION_TABLE_FILENAME "partitions-elixir.csv") +else() + set(AVM_PARTITION_TABLE_FILENAME "partitions.csv") +endif() + +if (${ATOMVM_RELEASE}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sdkconfig.release-defaults.in ${CMAKE_CURRENT_SOURCE_DIR}/sdkconfig.defaults @ONLY) +else() + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sdkconfig.defaults.in ${CMAKE_CURRENT_SOURCE_DIR}/sdkconfig.defaults @ONLY) +endif() + project(atomvm-esp32) # esp-idf does not use compile_feature but instead sets version in @@ -73,3 +86,19 @@ option(AVM_VERBOSE_ABORT "Print module and line number on VM abort" OFF) option(AVM_CREATE_STACKTRACES "Create stacktraces" ON) add_subdirectory(tools) + +include(GetBootAVM.cmake) +message(NOTICE "-- Configuring atomvmlib esp32boot flavor: ${BOOT_LIBS}") +if (NOT ("${BOOT_LIBS}" STREQUAL "NONE")) + set(BOOT_LIB_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../build/libs/esp32boot/${BOOT_LIBS}") + if (NOT EXISTS "${BOOT_LIB_PATH}") + message(ERROR "A generic_unix build must be done first in the top level AtomVM/build directory! \n\ + Consult https://doc.atomvm.org/main/build-instructions.html for build instructions.") + endif() + partition_table_get_partition_info(lib_offset "--partition-name boot.avm" "offset") + esptool_py_flash_target_image(flash boot.avm "${lib_offset}" "${BOOT_LIB_PATH}") +endif() + +if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/nvs_partition.csv) + nvs_create_partition_image(nvs ${CMAKE_CURRENT_SOURCE_DIR}/nvs_partition.csv) +endif() diff --git a/src/platforms/esp32/GetBootAVM.cmake b/src/platforms/esp32/GetBootAVM.cmake new file mode 100644 index 0000000000..0edd2da6ad --- /dev/null +++ b/src/platforms/esp32/GetBootAVM.cmake @@ -0,0 +1,28 @@ +# +# This file is part of AtomVM. +# +# Copyright 2025 Winford (Uncle Grumpy) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later +# + +partition_table_get_partition_info(app_offset "--partition-name main.avm" "offset") +if ("${app_offset}" STREQUAL "0x210000") + set(BOOT_LIBS "esp32boot.avm") +elseif ("${app_offset}" STREQUAL "0x250000") + set(BOOT_LIBS "elixir_esp32boot.avm") +else() + set(BOOT_LIBS "NONE") +endif() diff --git a/src/platforms/esp32/components/libatomvm/CMakeLists.txt b/src/platforms/esp32/components/libatomvm/CMakeLists.txt index 97580dbfea..4130c5383d 100644 --- a/src/platforms/esp32/components/libatomvm/CMakeLists.txt +++ b/src/platforms/esp32/components/libatomvm/CMakeLists.txt @@ -35,3 +35,6 @@ target_link_libraries(${COMPONENT_LIB} INTERFACE libAtomVM "-u platform_nifs_get_nif" "-u platform_defaultatoms_init") target_compile_features(${COMPONENT_LIB} INTERFACE c_std_11) + +include(../../GetBootAVM.cmake) +partition_table_get_partition_info(boot_offset "--partition-name boot.avm" "offset") diff --git a/src/platforms/esp32/main/Kconfig.projbuild b/src/platforms/esp32/main/Kconfig.projbuild index 88bf92aa1a..2992d0a284 100755 --- a/src/platforms/esp32/main/Kconfig.projbuild +++ b/src/platforms/esp32/main/Kconfig.projbuild @@ -40,4 +40,22 @@ menu "AtomVM configuration" help Enable TinyUSB CDC functionality if USE_USB_SERIAL is enabled. + config AVM_CREATE_STACKTRACES + bool "Create BEAM stack traces." + default y + help + Create stacktraces for AtomVM application debugging, when an application crashes a stacktrace will be emitted. + + config AVM_VERBOSE_ABORT + bool "Verbose error when a VM abort occurs." + default n + help + Print the C module and line number when a VM abort occurs. + + config ENABLE_REALLOC_GC + bool "Enable experimental optimized realloc garbage collection." + default n + help + Enable experimental optimized garbage collection mode that makes use of C realloc instead of copying data. + endmenu diff --git a/src/platforms/esp32/nvs_partition.csv-example b/src/platforms/esp32/nvs_partition.csv-example new file mode 100644 index 0000000000..1b2244d21e --- /dev/null +++ b/src/platforms/esp32/nvs_partition.csv-example @@ -0,0 +1,4 @@ +key,type,encoding,value +network,namespace,, +ssid,data,string,"NETWORK_NAME" +psk,data,string,"PASSWORD" diff --git a/src/platforms/esp32/sdkconfig.defaults.license b/src/platforms/esp32/nvs_partition.csv-example.license similarity index 100% rename from src/platforms/esp32/sdkconfig.defaults.license rename to src/platforms/esp32/nvs_partition.csv-example.license diff --git a/src/platforms/esp32/sdkconfig.defaults b/src/platforms/esp32/sdkconfig.defaults deleted file mode 100644 index ac849e02fc..0000000000 --- a/src/platforms/esp32/sdkconfig.defaults +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y -CONFIG_MBEDTLS_ECP_FIXED_POINT_OPTIM=y -CONFIG_LWIP_IPV6=n diff --git a/src/platforms/esp32/sdkconfig.defaults.in b/src/platforms/esp32/sdkconfig.defaults.in new file mode 100644 index 0000000000..f9d2091ca4 --- /dev/null +++ b/src/platforms/esp32/sdkconfig.defaults.in @@ -0,0 +1,8 @@ +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_MBEDTLS_ECP_FIXED_POINT_OPTIM=y +CONFIG_LWIP_IPV6=n +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="@AVM_PARTITION_TABLE_FILENAME@" +CONFIG_PARTITION_TABLE_FILENAME="@AVM_PARTITION_TABLE_FILENAME@" +CONFIG_APP_REPRODUCIBLE_BUILD=y + diff --git a/src/platforms/esp32/sdkconfig.release-defaults.license b/src/platforms/esp32/sdkconfig.defaults.in.license similarity index 100% rename from src/platforms/esp32/sdkconfig.release-defaults.license rename to src/platforms/esp32/sdkconfig.defaults.in.license diff --git a/src/platforms/esp32/sdkconfig.release-defaults b/src/platforms/esp32/sdkconfig.release-defaults.in similarity index 55% rename from src/platforms/esp32/sdkconfig.release-defaults rename to src/platforms/esp32/sdkconfig.release-defaults.in index e58c9c9cb0..186d42b364 100644 --- a/src/platforms/esp32/sdkconfig.release-defaults +++ b/src/platforms/esp32/sdkconfig.release-defaults.in @@ -4,3 +4,6 @@ CONFIG_MBEDTLS_ECP_FIXED_POINT_OPTIM=y CONFIG_COMPILER_OPTIMIZATION_PERF=y CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y CONFIG_LWIP_IPV6=n +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="@AVM_PARTITION_TABLE_FILENAME@" +CONFIG_PARTITION_TABLE_FILENAME="@AVM_PARTITION_TABLE_FILENAME@" +CONFIG_APP_REPRODUCIBLE_BUILD=y diff --git a/src/platforms/esp32/sdkconfig.release-defaults.in.license b/src/platforms/esp32/sdkconfig.release-defaults.in.license new file mode 100644 index 0000000000..b805ab2cac --- /dev/null +++ b/src/platforms/esp32/sdkconfig.release-defaults.in.license @@ -0,0 +1,2 @@ +SPDX-License-Identifier: Apache-2.0 +SPDX-FileCopyrightText: AtomVM Contributors diff --git a/src/platforms/esp32/tools/CMakeLists.txt b/src/platforms/esp32/tools/CMakeLists.txt index 8bc657d38a..1aa0d5b817 100644 --- a/src/platforms/esp32/tools/CMakeLists.txt +++ b/src/platforms/esp32/tools/CMakeLists.txt @@ -20,6 +20,9 @@ cmake_minimum_required (VERSION 3.13) project (ReleaseEsp32) +include(../../../../version.cmake) +include(../../../../CMakeModules/GetVersion.cmake) +include(../GetBootAVM.cmake) ## Build image tools for target chip @@ -43,9 +46,24 @@ elseif(${CONFIG_IDF_TARGET} STREQUAL "esp32p4") set(BOOTLOADER_OFFSET "0x2000") endif() -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/mkimage.config.in ${CMAKE_BINARY_DIR}/mkimage.config) +if ("${BOOT_LIBS}" STREQUAL "NONE") + message(WARNING "This appears to be a custom partition map using application offset: ${app_offset}, no AtomVM libraries will be included.") +else() + if (NOT EXISTS ../../../../build/libs/esp32boot/${BOOT_LIBS}) + message(WARNING "A generic_unix build must be done first in the top level AtomVM/build directory! \n\ + Consult https://doc.atomvm.org/main/build-instructions.html for build instructions.") + endif() +endif() + +set(ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../") -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../../../../tools/dev/flash.sh ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/flash.sh COPYONLY) +if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../nvs_partition.csv) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/mkimage_nvs.config.in ${CMAKE_BINARY_DIR}/mkimage.config) +else() + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/mkimage.config.in ${CMAKE_BINARY_DIR}/mkimage.config) +endif() + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/flash.sh.in ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/flash.sh @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/mkimage.erl ${CMAKE_BINARY_DIR}/mkimage.erl COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/flashimage.sh.in ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/flashimage.sh @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/mkimage.sh.in ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/mkimage.sh @ONLY) @@ -62,7 +80,3 @@ file(COPY ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/flash.sh FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) -if (NOT EXISTS ../../../../build/libs/esp32boot/esp32boot.avm) - message(WARNING "A generic_unix build must be done first in the top level AtomVM/build directory! \n\ - Consult https://doc.atomvm.org/main/build-instructions.html for build instructions.") -endif() diff --git a/tools/dev/flash.sh b/src/platforms/esp32/tools/flash.sh.in similarity index 98% rename from tools/dev/flash.sh rename to src/platforms/esp32/tools/flash.sh.in index ff6f7a5656..6879696078 100644 --- a/tools/dev/flash.sh +++ b/src/platforms/esp32/tools/flash.sh.in @@ -23,7 +23,7 @@ set -e : "${FLASH_BAUD_RATE:=115200}" : "${FLASH_SERIAL_PORT:=/dev/ttyUSB0}" -: "${FLASH_OFFSET:=0x210000}" +: "${FLASH_OFFSET:=@AVM_APP_OFFSET@}" ESP_TOOL=`which esptool.py` if [ -z ${ESP_TOOL} ]; then diff --git a/src/platforms/esp32/tools/mkimage.config.in b/src/platforms/esp32/tools/mkimage.config.in index 8856f72a16..bd85d0f5c3 100644 --- a/src/platforms/esp32/tools/mkimage.config.in +++ b/src/platforms/esp32/tools/mkimage.config.in @@ -33,12 +33,12 @@ #{ name => "AtomVM Virtual Machine", offset => "0x10000", - path => ["${BUILD_DIR}/atomvm-esp32.bin", "${ROOT_DIR}/src/platforms/esp32/build/atomvvm-esp32.bin"] + path => ["${BUILD_DIR}/atomvm-esp32.bin", "${ROOT_DIR}/src/platforms/esp32/build/atomvm-esp32.bin"] }, #{ name => "AtomVM Boot and Core BEAM Library", offset => "0x1D0000", - path => ["$[BOOT_FILE]"] + path => ["${ROOT_DIR}/build/libs/esp32boot/${BOOT_LIBS}"] } ] }. diff --git a/src/platforms/esp32/tools/mkimage.erl b/src/platforms/esp32/tools/mkimage.erl index e6518ee5d4..cee805dff3 100644 --- a/src/platforms/esp32/tools/mkimage.erl +++ b/src/platforms/esp32/tools/mkimage.erl @@ -43,7 +43,9 @@ do_main(Argv) -> try Config = load_config(maps:get(config, Opts, "mkimage.config")), BuildDir = get_build_dir(Opts, RootDir), - BootFile = BuildDir ++ "/libs/esp32boot/esp32boot.avm", + BootFile = maps:get( + boot, Opts, BuildDir ++ "/libs/esp32boot/esp32boot.avm" + ), mkimage( RootDir, BuildDir, diff --git a/src/platforms/esp32/tools/mkimage.sh.in b/src/platforms/esp32/tools/mkimage.sh.in index 2cfa9598d6..98a0a4eb90 100644 --- a/src/platforms/esp32/tools/mkimage.sh.in +++ b/src/platforms/esp32/tools/mkimage.sh.in @@ -23,10 +23,16 @@ escript "@CMAKE_BINARY_DIR@/mkimage.erl" \ --root_dir "@CMAKE_BINARY_DIR@/../../../.." \ --config "@CMAKE_BINARY_DIR@/mkimage.config" \ --out "@CMAKE_BINARY_DIR@/atomvm-@CONFIG_IDF_TARGET@.img" \ + --boot "@CMAKE_BINARY_DIR@/../../../../build/libs/esp32boot/@BOOT_LIBS@" \ "$@" +if (test ${@} = "--help"); then + echo "" + exit 0; +fi + echo "=============================================" echo "" -echo "AtomVM @CONFIG_IDF_TARGET@ version @ATOMVM_VERSION@ image written to:" +echo "AtomVM @CONFIG_IDF_TARGET@ version @ATOMVM_VERSION@ image with @BOOT_LIBS@ libraries written to:" echo "@CMAKE_BINARY_DIR@/atomvm-@CONFIG_IDF_TARGET@.img" diff --git a/src/platforms/esp32/tools/mkimage_nvs.config.in b/src/platforms/esp32/tools/mkimage_nvs.config.in new file mode 100644 index 0000000000..00c9c42841 --- /dev/null +++ b/src/platforms/esp32/tools/mkimage_nvs.config.in @@ -0,0 +1,50 @@ +% +% This file is part of AtomVM. +% +% Copyright 2020-2021 Fred Dushin +% Copyright 2025 Winford (UncleGrumpy) +% +% Licensed under the Apache License, Version 2.0 (the "License"); +% you may not use this file except in compliance with the License. +% You may obtain a copy of the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, +% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +% See the License for the specific language governing permissions and +% limitations under the License. +% +% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later +% + +#{ + segments => [ + #{ + name => "bootloader", + offset => "${BOOTLOADER_OFFSET}", + path => ["${BUILD_DIR}/bootloader/bootloader.bin"] + }, + #{ + name => "partition-table", + offset => "0x8000", + path => ["${BUILD_DIR}/partition_table/partition-table.bin", "${BUILD_DIR}/partitions.bin"] + }, + #{ + name => "nvs", + offset => "0x9000", + path => ["${BUILD_DIR}/nvs.bin"] + }, + #{ + name => "AtomVM Virtual Machine", + offset => "0x10000", + path => ["${BUILD_DIR}/atomvm-esp32.bin", "${ROOT_DIR}/src/platforms/esp32/build/atomvm-esp32.bin"] + }, + #{ + name => "AtomVM Boot and Core BEAM Library", + offset => "0x1D0000", + path => ["${ROOT_DIR}/build/libs/esp32boot/${BOOT_LIBS}"] + } + ] +}.