如何在闪存中切换多个 ESP32 固件二进制文件

介绍

ESP32 微控制器是一款高度集成且功能丰富的设备,它在物联网 (IoT) 和嵌入式系统应用中扮演着重要角色。这款微控制器的一个显著特性是其能够在内部闪存中存储多个固件镜像,并能够在这些镜像之间灵活切换。这项功能为开发者提供了极大的便利,无论是用于测试不同版本的固件、同时运行多个应用程序 ,还是为了维护一个备份固件以备不时之需。

本文旨在深入探讨如何利用 ESP32 的图形引导加载程序在多个存储于闪存中的固件镜像之间进行切换。该引导程序作为一个主应用程序,赋予用户选择并执行不同固件镜像的能力。此外,我们还将展示每个应用程序如何能够重新切换回引导程序,以便于进行进一步的固件选择或系统维护。

工作方式

图形引导加载程序提供了一个用户友好的图形界面,允许用户从菜单中选择并启动特定的应用程序。用户通过图形菜单选择一个应用程序时,引导加载程序会识别并选择与该应用程序关联的特定闪存分区。随后,设备将执行重启操作,引导加载程序切换到新选择的应用程序。在新应用程序启动的过程中,会运行一段特定的代码,该代码负责将设备的引导分区重新指向包含图形引导加载程序的原始分区。这一关键步骤确保了在下一次设备重启时,引导加载程序能够重新成为启动固件,从而允许用户再次进行应用程序的选择。整个固件切换过程采用了 OTA 机制,但所有应用程序固件均已预先存储在设备的闪存中。

分区表

要启用 ESP32 微控制器上的多个固件映像,我们需要一个自定义分区表。以下是文件 partitions.csv 的示例,该文件可容纳引导加载程序和五个 OTA 分区,专为 ESP32-S3-BOX-3M5Stack-CoreS3 中常用的 16 MB 闪存而设计:

# Name,      Type, Subtype,   Offset,  Size, Flags
nvs,         data, nvs,       0x9000,   24K,
otadata,     data, ota,       ,         8K,
phy_init,    data, phy,       ,         4K,
factory,     app,  factory,   ,         2M,
ota_0,       app,  ota_0,     ,         2816K,
ota_1,       app,  ota_1,     ,         2816K,
ota_2,       app,  ota_2,     ,         2816K,
ota_3,       app,  ota_3,     ,         2816K,
ota_4,       app,  ota_4,     ,         2816K,

此分区表需要在您的项目中定义,并且必须在 sdkconfig 文件中启用以下选项:

CONFIG_PARTITION_TABLE_CUSTOM=y

设置图形引导程序

使用预建固件快速入门

示例应用程序在 Releases 中以二进制固件的形式提供。

它可以从地址 0x0 烧录到设备。

esptool.py --chip esp32s3 write_flash 0x0000 graphical_bootloader_esp32-s3-box-3.bin

您还可以使用 Wokwi 在 Web 浏览器中运行应用程序的模拟。

克隆仓库

如果您想构建自己的版本,请按照本章中的说明进行操作。

从克隆项目仓库开始:

git clone https://github.com/georgik/esp32-graphical-bootloader.git
cd esp32-graphical-bootloader

选择目标板

使用 BUILD_BOARD 变量设置适当的板。例如,要配置 ESP32-S3-BOX-3,请使用:

cmake -DBUILD_BOARD=esp-box-3 -Daction=build_all_apps -P Bootloader.cmake

其他受支持的板列表可以在 boards 目录中找到。

将二进制文件合并为单个固件

上述构建完成后,将二进制文件合并为单个固件:

esptool.py --chip esp32s3 merge_bin  -o build.esp-box-3/combined.bin --flash_mode dio --flash_size 16MB \
    0x0 build.esp-box-3/bootloader/bootloader.bin \
    0x8000 build.esp-box-3/partition_table/partition-table.bin \
    0xf000 build.esp-box-3/ota_data_initial.bin \
    0x20000 build.esp-box-3/esp32-graphical-bootloader.bin \
    0x220000 apps/tic_tac_toe/build.esp-box-3/tic_tac_toe.bin \
    0x4E0000 apps/wifi_list/build.esp-box-3/wifi_list.bin \
    0x7A0000 apps/calculator/build.esp-box-3/calculator.bin \
    0xA60000 apps/synth_piano/build.esp-box-3/synth_piano.bin \
    0xD20000 apps/game_of_life/build.esp-box-3/game_of_life.bin

将合并后的二进制文件烧录到 ESP32 上

最后,将合并后的二进制文件烧录到 ESP32 上:

esptool.py --chip esp32s3 write_flash 0x0 build.esp-box-3/combined.bin

如何使用引导程序

烧录完成后,ESP32 将启动进入图形引导加载程序。该引导程序允许您选择要运行的应用程序。用户界面十分直观,您可以直接浏览存储在 OTA 分区中的不同应用程序。

创建自定义应用程序

以下步骤将解释如何为 ESP32-S3-BOX-3 创建与图形引导加载程序配合使用的自定义 ESP-IDF 应用程序。

idf.py create-project hello_app
cd hello_app
idf.py set-target esp32s3
idf.py add-dependency "espressif/esp-box-3^1.2.0"
idf.py add-dependency "espressif/esp_codec_dev==1.1.0"
cp ../calculator/sdkconfig.defaults .
cp ../calculator/sdkconfig.defaults.esp-box-3 .

切换到存储在 OTA 分区中的应用程序

引导程序中的以下代码片段显示了如何切换到另一个应用程序。这对于管理存储在不同 OTA 分区中的多个应用程序十分有效:

// For button 1, next_partition will not change, thus pointing to 'ota_0'
if (next_partition && esp_ota_set_boot_partition(next_partition) == ESP_OK) {
    printf("Setting boot partition to %s\\n", next_partition->label);
    esp_restart();  // Restart to boot from the new partition
} else {
    printf("Failed to set boot partition\\n");
}

返回工厂分区中的原始应用程序

每个应用程序都可以包含一个切换回原始应用程序(图形引导加载程序)的机制。以下是其中一个子应用程序的示例功能:

#include "esp_ota_ops.h"

void reset_to_factory_app() {
    // Get the partition structure for the factory partition
    const esp_partition_t *factory_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
    if (factory_partition != NULL) {
        if (esp_ota_set_boot_partition(factory_partition) == ESP_OK) {
            printf("Set boot partition to factory, restarting now.\\n");
        } else {
            printf("Failed to set boot partition to factory.\\n");
        }
    } else {
        printf("Factory partition not found.\\n");
    }

    fflush(stdout);
}

该函数可以在应用程序开始时调用此功能,以确保设备在发生崩溃时能够恢复到出厂固件(引导程序)。完成此操作后,任何重置都将启动到原始固件中。

在您应用程序的 CMakeLists.txt 中,请确保包含所需的依赖项:

idf_component_register(SRCS "hello_app.c"
                    INCLUDE_DIRS "."
                    REQUIRES app_update)

应用代码

更新 main/hello_app.c 的代码,以切换到出厂应用程序并在屏幕上显示信息。

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "lvgl.h"
#include "bsp/esp-bsp.h"
#include "esp_ota_ops.h"

void reset_to_factory_app() {
    // Get the partition structure for the factory partition
    const esp_partition_t *factory_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
    if (factory_partition != NULL) {
        if (esp_ota_set_boot_partition(factory_partition) == ESP_OK) {
            printf("Set boot partition to factory, restarting now.\\n");
        } else {
            printf("Failed to set boot partition to factory.\\n");
        }
    } else {
        printf("Factory partition not found.\\n");
    }

    fflush(stdout);
}

void app_main(void) {
    reset_to_factory_app();

    // Initialize the BSP
    bsp_i2c_init();
    bsp_display_start();

    // Create a label and set its text
    lv_obj_t *label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Hello ESP32-S3-BOX-3");
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);

    // Start the display backlight
    bsp_display_backlight_on();

    printf("Hello ESP32-S3-BOX-3\n");

    // Handle LVGL tasks
    while (1) {
        lv_task_handler();
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

刷新应用程序

您可以将应用程序直接构建并烧录到 OTA 分区。

idf.py @../../boards/esp-box-3.cfg build
esptool.py --chip esp32s3 write_flash 0x220000 build.esp-box-3/hello_app.bin

更改应用程序图标

图形引导加载程序中显示的图标是图形加载引导程序固件的一部分,并非应用程序的一部分。图标存储在 resources/images 中。

您只需要替换其中一个现有的 png 文件。

如果您想使用您自己的图标名称,请更新引导加载程序 mainmain/bootloader_ui.c:

LV_IMG_DECLARE(icon_hello_app)

并将您的图标在 main/CMakeLists.txt 中进行注册。IDF 构建过程会将该图标转换为正确的格式。

lvgl_port_create_c_image("../resources/images/icon_hello_app.png" "images/gen/" "ARGB8888" "NONE")

更改图标后,您需要重建并烧录主应用程序:

idf.py @boards/esp-box-3 fullclean
idf.py @boards/esp-box-3 app-flash

相关链接:

结论

ESP32 的图形引导加载程序为在单一设备上管理多个应用程序提供了一种优越的方式。通过利用 OTA 分区,您可以轻松地存储和切换不同的应用程序。无论您是希望尝试不同项目的创客,还是需要多个应用环境的专业人士,这款引导程序都简化了这一过程。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值