一、概述
ESP32应用程序可以在运行时通过Wi-Fi或以太网从特定的服务器下载新映像,然后将其闪存到某些分区中,从而进行升级。
在ESP-IDF中有两种方式可以进行空中(OTA)升级:
使用 app_update 组件提供的原生API
使用 esp_https_ota 组件提供的简化API,它在原生OTA API上添加了一个抽象层,以便使用HTTPS协议进行升级。
分别在 native_ota_example 和 simple_ota_example 下的OTA示例中演示了这两种方法。
1.1 OTA工作流程

1.2 OTA数据分区
ESP32 SPI Flash 内有与升级相关的(至少)四个分区:OTA data、Factory App、OTA_0、OTA_1。其中 FactoryApp 内存有出厂时的默认固件。
首次进行 OTA 升级时,OTA Demo 向 OTA_0 分区烧录目标固件,并在烧录完成后,更新 OTA data 分区数据并重启。
系统重启时获取 OTA data 分区数据进行计算,决定此后加载 OTA_0 分区的固件执行(而不是默认的 Factory App 分区内的固件),从而实现升级。
同理,若某次升级后 ESP32 已经在执行 OTA_0 内的固件,此时再升级时 OTA Demo 就会向 OTA_1 分区写入目标固件。再次启动后,执行 OTA_1 分区实现升级。以此类推,升级的目标固件始终在 OTA_0、OTA_1 两个分区之间交互烧录,不会影响到出厂时的 Factory App 固件。

为了简单起见,OTA示例通过在menuconfig中启用CONFIG_PARTITION_TABLE_TWO_OTA选项来选择预定义的分区表,该选项支持三个应用程序分区:工厂分区、OTA_0分区和OTA_1分区。有关分区表的更多信息,请参阅分区表.
二、API说明
以下原生 OTA 接口位于 app_update/include/esp_ota_ops.h。
2.1 esp_ota_begin

2.2 esp_ota_write

2.3 esp_ota_end

2.4 esp_ota_set_boot_partition

2.5 esp_ota_get_boot_partition

2.6 esp_ota_get_running_partition

2.7 esp_ota_get_next_update_partition

三、编程流程
3.1 OTA详细过程逻辑

3.2 OTA分区操作流程

节选自 esp-idfexamplessystemotanative_ota_example 中的例程
static void ota_example_task(void *pvParameter){
esp_err_t err;
/* update handle : set by esp_ota_begin(), must be freed via esp_ota_end() */
esp_ota_handle_t update_handle = 0 ;
const esp_partition_t *update_partition = NULL;
ESP_LOGI(TAG, 'Starting OTA example');
//获取OTA app存放的位置
const esp_partition_t *configured = esp_ota_get_boot_partition();
//获取当前系统执行的固件所在的Flash分区
const esp_partition_t *running = esp_ota_get_running_partition();
if (configured != running) {
ESP_LOGW(TAG, 'Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x',
configured->address, running->address);
ESP_LOGW(TAG, '(This can happen if either the OTA boot data or preferred boot image become corrupted somehow.)');
}
ESP_LOGI(TAG, 'Running partition type %d subtype %d (offset 0x%08x)',
running->type, running->subtype, running->address);
esp_http_client_config_t config = {
.url = CONFIG_EXAMPLE_FIRMWARE_UPG_URL,
.cert_pem = (char *)server_cert_pem_start,
.timeout_ms = CONFIG_EXAMPLE_OTA_RECV_TIMEOUT,
};#ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL_FROM_STDIN
char url_buf[OTA_URL_SIZE];
if (strcmp(config.url, 'FROM_STDIN') == 0) {
example_configure_stdin_stdout();
fgets(url_buf, OTA_URL_SIZE, stdin);
int len = strlen(url_buf);
url_buf[len - 1] = '
