一、概述
- 最近做了一下ESP32的IAP升级(基于Ymodem),所以需要剥离一下ESP32的OTA
二、SDK准备工作
-
SDK版本:esp-idf-4.4.x -
修改分区表,我这里采用OTA0+OTA1,各1.5M,无Factory区域 # Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, , 0x4000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000,
ota_0, app, ota_0, , 0x180000,
ota_1, app, ota_1, , 0x180000,
-
设置板子的FLASH为4M(这里需要根据硬件和分区表在menuconfig进行调整) # CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
三、整体流程
-
需要用到的变量 volatile esp_ota_handle_t update_handle = 0 ;
volatile const esp_partition_t *update_partition = NULL;
volatile int binary_file_length = 0;
volatile bool image_header_was_checked = false;
-
初始化时需要调用(准备开始OTA了)
update_partition = esp_ota_get_next_update_partition(NULL);
assert(update_partition != NULL);
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x",
update_partition->subtype, update_partition->address);
binary_file_length = 0;
image_header_was_checked = false;
-
每接收到一包数据,进行调用 esp_err_t err;
if (image_header_was_checked == false) {
esp_app_desc_t new_app_info;
if (dat_len > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) {
memcpy(&new_app_info, &dat[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t));
ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version);
esp_app_desc_t running_app_info;
if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) {
ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version);
}
const esp_partition_t* last_invalid_app = esp_ota_get_last_invalid_partition();
esp_app_desc_t invalid_app_info;
if (esp_ota_get_partition_description(last_invalid_app, &invalid_app_info) == ESP_OK) {
ESP_LOGI(TAG, "Last invalid firmware version: %s", invalid_app_info.version);
}
if (last_invalid_app != NULL) {
if (memcmp(invalid_app_info.version, new_app_info.version, sizeof(new_app_info.version)) == 0) {
ESP_LOGW(TAG, "New version is the same as invalid version.");
ESP_LOGW(TAG, "Previously, there was an attempt to launch the firmware with %s version, but it failed.", invalid_app_info.version);
ESP_LOGW(TAG, "The firmware has been rolled back to the previous version.");
}
}
image_header_was_checked = true;
err = esp_ota_begin(update_partition, OTA_WITH_SEQUENTIAL_WRITES, &update_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
esp_ota_abort(update_handle);
return COM_ERROR;
}
ESP_LOGI(TAG, "esp_ota_begin succeeded");
} else {
ESP_LOGE(TAG, "received package is not fit len");
esp_ota_abort(update_handle);
return COM_ERROR;
}
}
err = esp_ota_write( update_handle, (const void *)dat, dat_len);
if (err != ESP_OK) {
esp_ota_abort(update_handle);
}
binary_file_length += dat_len;
ESP_LOGI(TAG, "Written image length %d|%d", binary_file_length);
-
OTA结束后调用
esp_err_t err;
ESP_LOGI(TAG, "Total Write binary data length: %d", binary_file_length);
err = esp_ota_end(update_handle);
if (err != ESP_OK) {
if (err == ESP_ERR_OTA_VALIDATE_FAILED) {
ESP_LOGE(TAG, "Image validation failed, image is corrupted");
} else {
ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err));
}
}
err = esp_ota_set_boot_partition(update_partition);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));
}
ESP_LOGI(TAG, "Prepare to restart system!");
esp_restart();
四、注意事项
- 获取头包时,注意适当增加长度,通常1K字节是没问题的,否则上面的实现中,检查头包长度时,会不过,若是收数据单包比较少,建议组包后才调用上面函数进行处理
|