This repository shows the simplest way to setup a dual boot on ESP32 using PlatformIO. With this method it is possible to upload two different applications on a single ESP32 and switch between them using a GPIO pin.
Actually, it is possible to upload more than two applications on the same ESP32. For more detailed infos Epressif - Partition Table.
Note: This repository uses the same code for both the partitions, differenciating the functionalities using two macros OTA_0
and OTA_1
defined in the platformio.ini
, but it is also possible to upload different files.
In order to have two partitions on the same ESP32 must be created a file partitions.csv
that specify the type and the dimensions of each partition. This code uses the following partition table:
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 20k,
otadata, data, ota, 0xe000, 8k,
ota_0, app, ota_0, 0x10000, 1M,
ota_1, app, ota_1, 0x110000,1M,
coredump, data, coredump,,64k,
ota_0
: is the first partition, which starts at the0x10000
address of memory;ota_1
: is the second partition, which starts at the0x110000
adress of memory.
Both the partitions are 1M of memory. Note that the address depends on the size of the partition, so be carefull to change both this values in accordance.
The plaformio.ini
should be set in the following way:
[platformio]
[common]
platform = espressif32
board = esp32dev
framework = arduino
upload_port = /dev/ttyUSB0
monitor_speed = 115200
board_build.partitions = partitions.csv
[env:ota_0]
extends = common
board_upload.offset_address = 0x10000
build_flags = -D OTA_0
[env:ota_1]
extends = common
board_upload.offset_address = 0x110000
build_flags = -D OTA_1
where:
common
:plaform
: is the framework of the ESP32 platformboard
: is the type of the boardframework
: is the type of the framework used for this project (in this case Arduino)upload_port
: is the port of the computer used to upload the firmware on ESP32 (use the command ls /dev/tty* to check the port at which the ESP32 is connected to)monitor_speed
: the baud ratio of the serial communicationboard_build.partitions
: the file that describe the partition table
env:ota_0
extends
: specify which enviroment is extendedboard_upload.offset_address
: specify which is the address at which starts this partition. This address must match the one specified in thepartition.csv
for the same partition.build_flags
: it is used to create a macroOTA_0
, which is defined exclusivly for this partition. This macro is then used to differenciate the code used for the first application.
env:ota_1
extends
: specify which enviroment is extendedboard_upload.offset_address
: specify which is the address at which starts this partition. This address must match the one specified in thepartition.csv
for the same partition.build_flags
: it is used to create a macroOTA_1
, which is defined exclusivly for this partition. This macro is then used to differenciate the code used for the second application.
Using the macros OTA_0
and OTA_1
it is possible to reuse the same code for multiple applications, by differenciating small portions of code with the construct:
#ifdef OTA_0
...
#endif
#ifdef OTA_1
...
#endif
Otherwise, it is also possible to upload different files on each partition, using the follwing option in the platformio.ini
:
build_src_filter = +<filename_1> -<filename_2>
In the app.h
are defined the following macros:
SWITCH_PARTITION_PIN
: is the GPIO pin used to switch between the two applications, by directly connecting or disconnecting it to GND.PARTITION_TYPE
: is the type of the partition specified in thepartition.csv
.SWITCH_PIN_STATE
: is the state of theSWITCH_PARTITION_PIN
(low
if connected two GND,high
otherwise).
#define SWITCH_PARTITION_PIN 16
#ifdef OTA_0
#define PARTITION_TYPE ESP_PARTITION_SUBTYPE_APP_OTA_1
#define SWITCH_PIN_STATE LOW
#endif
#ifdef OTA_1
#define PARTITION_TYPE ESP_PARTITION_SUBTYPE_APP_OTA_0
#define SWITCH_PIN_STATE HIGH
#endif
The code used to swith between the two application is the following:
if (digitalRead(SWITCH_PARTITION_PIN) == SWITCH_PIN_STATE) {
const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, PARTITION_TYPE, NULL);
if (partition != nullptr){
esp_err_t ret = esp_ota_set_boot_partition(partition);
if (ret != ESP_OK) Serial.printf("Failed to set boot partition");
else {
Serial.println("Boot partition set, restarting");
esp_restart();
}
}
else Serial.println("Failed to find the application partition");
}
which is based on the library <esp_ota_ops.h>
.
git clone https://github.com/ValerioSpagnoli/dual-boot-ESP32-PlatformIO-Arduino.git
Use the VS Code extention Platformio to setup the project and upload the firmware. If the firmware will be uploaded successfully you should see something like that:
Once the firmware is uploaded on the ESP32 open the serial monitor and use a FF jumper to connect and disconnect the SWITCH_PARTITION_PIN
to GND in order to switch between the two applications.