Solution: Using esp_app_desc_t and esp_image_load().
This method manually loads and jumps to the desired partition without changing the bootloader's configuration.
Code: Untitled.c Select all
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_partition.h"
#include "esp_err.h"
#include "esp_image_format.h"
#define TAG "ota0"
#define FORCED_UPDATE_PIN GPIO_NUM_0 // Define the GPIO pin to trigger update mode
#define OTA1_LABEL "ota_1"
#define OTA2_LABEL "ota_2"
bool check_forced_update(void) {
gpio_pad_select_gpio(FORCED_UPDATE_PIN);
gpio_set_direction(FORCED_UPDATE_PIN, GPIO_MODE_INPUT);
return (gpio_get_level(FORCED_UPDATE_PIN) == 1);
}
// Function to directly load and execute another partition
void launch_partition(const char* partition_label) {
const esp_partition_t* partition = esp_partition_find_first(
ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, partition_label);
if (partition == NULL) {
ESP_LOGE(TAG, "Partition %s not found!", partition_label);
return;
}
ESP_LOGI(TAG, "Found partition %s at offset 0x%08X", partition->label, partition->address);
// Read the application descriptor from the partition
esp_app_desc_t app_desc;
if (esp_partition_read(partition, 0x1000, &app_desc, sizeof(app_desc)) != ESP_OK) {
ESP_LOGE(TAG, "Failed to read app descriptor from partition %s", partition->label);
return;
}
ESP_LOGI(TAG, "Application version: %s", app_desc.version);
ESP_LOGI(TAG, "Jumping to %s...", partition_label);
// Execute the partition
esp_err_t err = esp_image_load(ESP_IMAGE_LOAD, partition, &app_desc);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to load image: %s", esp_err_to_name(err));
return;
}
}
void app_main(void) {
ESP_LOGI(TAG, "Booting from ota0");
if (check_forced_update()) {
ESP_LOGI(TAG, "Forced update detected. Entering update mode...");
// Insert your USB MSC update handling code here (if needed)
while (1) {
ESP_LOGI(TAG, "Waiting for firmware update...");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
ESP_LOGI(TAG, "No forced update detected. Checking which partition to launch.");
const esp_partition_t* running_partition = esp_ota_get_running_partition();
if (strcmp(running_partition->label, OTA1_LABEL) == 0) {
ESP_LOGI(TAG, "Currently running: ota1, attempting to boot ota2 for this cycle.");
launch_partition(OTA2_LABEL);
}
else if (strcmp(running_partition->label, OTA2_LABEL) == 0) {
ESP_LOGI(TAG, "Currently running: ota2, attempting to boot ota1 for this cycle.");
launch_partition(OTA1_LABEL);
}
else {
ESP_LOGI(TAG, "Unknown partition running. Defaulting to ota1 for this cycle.");
launch_partition(OTA1_LABEL);
}
}launch_partition() Function:
Finds the desired partition using esp_partition_find_first().
Reads the application descriptor (esp_app_desc_t) to verify the application.
Uses esp_image_load() to load and execute the partition without modifying otadata.
Handling Forced Update:
If the FORCED_UPDATE_PIN is HIGH, you can trigger the MSC update process.
Otherwise, ota0 decides which partition (ota1 or ota2) to launch for the current boot cycle.