Bootstrap

ESP32基于IDF框架OTA学习记录

ESP32基于IDF框架OTA学习记录

参考:

1.分区表

分区表将esp32的flash作了划分,不同类型的区域作不同功能使用。我们进行OTA时,需要将程序写入flash,需要先配置部分flash区域,标识为OTA使用。

官方的分区表介绍很详细:分区表 - ESP32 - — ESP-IDF 编程指南 v5.1.2 文档 (espressif.com)

2.native_ota_example上手

这个示例是官方的例程,路径:esp-idf-v5.1.2\examples\system\ota\native_ota_example

2.1配置分区表

官方例程貌似已经配置了,没配置的话需要配置2个OTA分区。

配置方法:

idf.py menuconfig打开配置界面,对Partition Table项进行配置:

(Top) → Partition Table → Partition Table                                                                                                                                                            Espressif IoT Development Framework Configuration                                                  ( ) Single factory app, no OTA
( ) Single factory app (large), no OTA
(X) Factory app, two OTA definitions
( ) Custom partition table CSV

                                                                                                                                                                                                                                                                                                  

2.2配置OTA的bin文件

这里使用get-started里面的blink点灯例程,编译出一个blink.bin文件。

服务器使用gitee,建了一个测试仓库,上传blink.bin,下载链接:https://gitee.com/nameisboy/esp32-https-ota/raw/master/blink.bin

idf.py menuconfig配置固件升级的URL,使用上面的链接:

(Top) → Example Configuration                                                                                                                                                                        Espressif IoT Development Framework Configuration                                                  (https://gitee.com/nameisboy/esp32-https-ota/raw/master/blink.bin) Firmware Upgrade URL
[ ] Skip server certificate CN fieldcheck
[ ] Skip firmware version check
(4) Number of the GPIO input for diagnostic
(5000) OTA Receive Timeout


                                                                                                                                                  

2.3修改esp32的https证书验证方法

例程使用的是服务器的自签名证书做SSL/TLS验证,gitee服务器的证书不知道怎么搞,这里直接修改使用esp32自带的 ESP x509 Certificate Bundle进行验证,该功能覆盖了大多数受信任的根证书。

具体修改方法:

找到代码中配置https的结构体,修改初始化参数:

crt_bundle_attach成员赋值 esp_crt_bundle_attach,关闭 cert_pem的初始化。

    esp_http_client_config_t config = {
        .url = CONFIG_EXAMPLE_FIRMWARE_UPG_URL,
//        .cert_pem = (char *)server_cert_pem_start,
        .crt_bundle_attach = esp_crt_bundle_attach,
        .timeout_ms = CONFIG_EXAMPLE_OTA_RECV_TIMEOUT,
        .keep_alive_enable = true,
    };

需要包含头文件:

#include "esp_crt_bundle.h"/*使用ESP x509 Certificate Bundle*/

2.4修改当前固件版本

因为OTA代码中做了版本判断,如果版本相同,不会进行OTA。而blink例程编译出来的固件版本默认是1,OTA例程的版本也默认为1,这里直接修改OTA例程的版本,使其不一致即可。

修改方法:

修改工程目录下的version.txt文件中数字,这里直接修改为2。

2.5配置WiFi连接参数

idf.py menuconfig配置WiFi连接的SSID密码。

2.6编译、下载

确保WiFi可以连接、上网,观察串口输出即可看到OTA升级的过程,成功后ESP32会重启运行新的blink代码。

PS D:\Coding\Embedded\MCU\ESP32\esp-idf\native_ota_example> idf.py -p COM3 flash monitor
Executing action: flash
Running ninja in directory D:\Coding\Embedded\MCU\ESP32\esp-idf\native_ota_example\build
Executing "ninja flash"...
[1/5] cmd.exe /C "cd /D D:\Coding\Embedded\MCU\ESP32\esp-idf\native_ota_example\build\esp-idf\esptool_py && D:\Coding\Embedded\MCU\espressif\Tools\Espressif\python_env\idf5.1_py3.11_env\Scripts\python.exe D:/Coding/Embedded/MCU/espressif/esp-idf-v5.1.2/components/partition_table/check_sizes.py --offset 0x8000 partition --type app D:/Coding/Embedded/MCU/ESP32/esp-idf/native_ota_example/build/partition_table/partition-table.bin D:/Coding/Embedded/MCU/ESP32/esp-idf/native_ota_example/build/native_ota.bin"
native_ota.bin binary size 0xeda90 bytes. Smallest app partition is 0x100000 bytes. 0x12570 bytes (7%) free.
[2/5] Performing build step for 'bootloader'
[1/1] cmd.exe /C "cd /D D:\Coding\Embedded\MCU\ESP32\esp-idf\native_ota_example\build\bootloader\esp-idf\esptool_py && D:\Coding\Embedded\MCU\espressif\Tools\Espressif\python_env\idf5.1_py3.11_env\Scripts\python.exe D:/Coding/Embedded/MCU/espressif/esp-idf-v5.1.2/components/partition_table/check_sizes.py --offset 0x8000 bootloader 0x1000 D:/Coding/Embedded/MCU/ESP32/esp-idf/native_ota_example/build/bootloader/bootloader.bin"
Bootloader binary size 0x6810 bytes. 0x7f0 bytes (7%) free.
[2/3] cmd.exe /C "cd /D D:\Coding\Embedded\MCU\espressif\esp-idf-v5.1.2\components\esptool_py && D:\Coding\Embedded\MCU\espressif\Tools\Espressif\tools\cmake\3.24.0\bin\cmake.exe -D IDF_PATH=D:/Coding/Embedded/MCU/espressif/esp-idf-v5.1.2 -D SERIAL_TOOL=D:/Coding/Embedded/MCU/espressif/Tools/Espressif/python_env/idf5.1_py3.11_env/Scripts/python.exe;;D:/Coding/Embedded/MCU/espressif/esp-idf-v5.1.2/components/esptool_py/esptool/esptool.py;--chip;esp32 -D SERIAL_TOOL_ARGS=--before=default_reset;--after=hard_reset;write_flash;@flash_args -D WORKING_DIRECTORY=D:/Coding/Embedded/MCU/ESP32/esp-idf/native_ota_example/build -P D:/Coding/Embedded/MCU/espressif/esp-idf-v5.1.2/components/esptool_py/run_serial_tool.cmake"
esptool.py --chip esp32 -p COM3 -b 460800 --before=default_reset --after=hard_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 4MB 0x1000 bootloader/bootloader.bin 0x10000 native_ota.bin 0x8000 partition_table/partition-table.bin 0xd000 ota_data_initial.bin
esptool.py v4.7.dev3
Serial port COM3
Connecting.....
Chip is ESP32-D0WD (revision v1.0)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: e8:68:e7:23:58:1c
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Flash will be erased from 0x00001000 to 0x00007fff...
Flash will be erased from 0x00010000 to 0x000fdfff...
Flash will be erased from 0x00008000 to 0x00008fff...
Flash will be erased from 0x0000d000 to 0x0000efff...
Compressed 26640 bytes to 16691...
Writing at 0x00001000... (50 %)
Writing at 0x0000768d... (100 %)
Wrote 26640 bytes (16691 compressed) at 0x00001000 in 0.9 seconds (effective 239.8 kbit/s)...
Hash of data verified.
Compressed 973456 bytes to 634536...
Writing at 0x00010000... (2 %)
Writing at 0x00018908... (5 %)
Writing at 0x0001d5d4... (7 %)
Writing at 0x000229e0... (10 %)
Writing at 0x0002a261... (12 %)
Writing at 0x00031225... (15 %)
Writing at 0x000365a4... (17 %)
Writing at 0x00041e08... (20 %)
Writing at 0x0004c12a... (23 %)
Writing at 0x00051d7c... (25 %)
Writing at 0x0005759a... (28 %)
Writing at 0x0005d066... (30 %)
Writing at 0x00062b1d... (33 %)
Writing at 0x000683eb... (35 %)
Writing at 0x0006df8d... (38 %)
Writing at 0x00074378... (41 %)
Writing at 0x00079e9f... (43 %)
Writing at 0x0007f70f... (46 %)
Writing at 0x00084a40... (48 %)
Writing at 0x00089e2c... (51 %)
Writing at 0x0008f394... (53 %)
Writing at 0x00094682... (56 %)
Writing at 0x00099cf4... (58 %)
Writing at 0x0009f597... (61 %)
Writing at 0x000a5474... (64 %)
Writing at 0x000aab92... (66 %)
Writing at 0x000b0275... (69 %)
Writing at 0x000b5946... (71 %)
Writing at 0x000bb341... (74 %)
Writing at 0x000c09fd... (76 %)
Writing at 0x000c6385... (79 %)
Writing at 0x000cc699... (82 %)
Writing at 0x000d21d5... (84 %)
Writing at 0x000d7980... (87 %)
Writing at 0x000e0612... (89 %)
Writing at 0x000e8d55... (92 %)
Writing at 0x000ee9dd... (94 %)
Writing at 0x000f4378... (97 %)
Writing at 0x000f9a04... (100 %)
Wrote 973456 bytes (634536 compressed) at 0x00010000 in 15.3 seconds (effective 510.4 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 138...
Writing at 0x00008000... (100 %)
Wrote 3072 bytes (138 compressed) at 0x00008000 in 0.1 seconds (effective 274.2 kbit/s)...
Hash of data verified.
Compressed 8192 bytes to 31...
Writing at 0x0000d000... (100 %)
Wrote 8192 bytes (31 compressed) at 0x0000d000 in 0.2 seconds (effective 395.2 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...
Executing action: monitor
Running idf_monitor in directory D:\Coding\Embedded\MCU\ESP32\esp-idf\native_ota_example
Executing "D:\Coding\Embedded\MCU\espressif\Tools\Espressif\python_env\idf5.1_py3.11_env\Scripts\python.exe D:\Coding\Embedded\MCU\espressif\esp-idf-v5.1.2\tools/idf_monitor.py -p COM3 -b 115200 --toolchain-prefix xtensa-esp32-elf- --target esp32 --revision 0 D:\Coding\Embedded\MCU\ESP32\esp-idf\native_ota_example\build\native_ota.elf --force-color -m 'D:\Coding\Embedded\MCU\espressif\Tools\Espressif\python_env\idf5.1_py3.11_env\Scripts\python.exe' 'D:\Coding\Embedded\MCU\espressif\esp-idf-v5.1.2\tools\idf.py' '-p' 'COM3'"...
--- WARNING: GDB cannot open serial ports accessed as COMx
--- Using \\.\COM3 instead...
--- esp-idf-monitor 1.3.3 on \\.\COM3 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
I (531) cpu_start: Pro cpu ����ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:7084
ho 0 tail 12 room 4
load:0x40078000,len:15584
load:0x40080400,len:4
0x40080400: _init at ??:?

load:0x40080404,len:3876
entry 0x4008064c
I (31) boot: ESP-IDF v5.1.2-dirty 2nd stage bootloader
I (31) boot: compile time Nov 26 2023 22:37:12
I (31) boot: Multicore bootloader
I (36) boot: chip revision: v1.0
I (40) boot.esp32: SPI Speed      : 40MHz
I (44) boot.esp32: SPI Mode       : DIO
I (49) boot.esp32: SPI Flash Size : 4MB
I (53) boot: Enabling RNG early entropy source...
I (59) boot: Partition Table:
I (62) boot: ## Label            Usage          Type ST Offset   Length
I (70) boot:  0 nvs              WiFi data        01 02 00009000 00004000
I (77) boot:  1 otadata          OTA data         01 00 0000d000 00002000
I (84) boot:  2 phy_init         RF data          01 01 0000f000 00001000
I (92) boot:  3 factory          factory app      00 00 00010000 00100000
I (99) boot:  4 ota_0            OTA app          00 10 00110000 00100000
I (107) boot:  5 ota_1            OTA app          00 11 00210000 00100000
I (114) boot: End of partition table
I (119) boot: Defaulting to factory image
I (123) esp_image: segment 0: paddr=00010020 vaddr=3f400020 size=36160h (221536) map
I (212) esp_image: segment 1: paddr=00046188 vaddr=3ffb0000 size=03b44h ( 15172) load
I (218) esp_image: segment 2: paddr=00049cd4 vaddr=40080000 size=06344h ( 25412) load
I (229) esp_image: segment 3: paddr=00050020 vaddr=400d0020 size=9e144h (647492) map
I (463) esp_image: segment 4: paddr=000ee16c vaddr=40086344 size=0f8f8h ( 63736) load
I (501) boot: Loaded app from partition at offset 0x10000
I (501) boot: Disabling RNG early entropy source...
I (512) cpu_start: Multicore app
I (513) cpu_start: Pro cpu up.
I (513) cpu_start: Starting app cpu, entry point is 0x40081390
0x40081390: call_start_cpu1 at D:/Coding/Embedded/MCU/espressif/esp-idf-v5.1.2/components/esp_system/port/cpu_start.c:157

I (0) cpu_start: App cpu up.
I (531) cpu_start: Pro cpu start user code
I (531) cpu_start: cpu freq: 160000000 Hz
I (531) cpu_start: Application information:
I (535) cpu_start: Project name:     native_ota
I (541) cpu_start: App version:      2
I (545) cpu_start: Compile time:     Nov 26 2023 22:36:55
I (551) cpu_start: ELF file SHA256:  7166a216a7cfb5c9...
I (557) cpu_start: ESP-IDF:          v5.1.2-dirty
I (562) cpu_start: Min chip rev:     v0.0
I (567) cpu_start: Max chip rev:     v3.99
I (572) cpu_start: Chip rev:         v1.0
I (577) heap_init: Initializing. RAM available for dynamic allocation:
I (584) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (590) heap_init: At 3FFB8780 len 00027880 (158 KiB): DRAM
I (596) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (603) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (609) heap_init: At 40095C3C len 0000A3C4 (40 KiB): IRAM
I (617) spi_flash: detected chip: generic
I (620) spi_flash: flash io: dio
I (625) app_start: Starting scheduler on CPU0
I (629) app_start: Starting scheduler on CPU1
I (629) main_task: Started on CPU0
I (639) main_task: Calling app_main()
I (639) native_ota_example: OTA example app_main start
I (649) native_ota_example: SHA-256 for the partition table: : d1c0e9d02fa9d26cd2e1984e7b5dd20157204f501ddc83ce82229e5f3175ee8b
I (669) native_ota_example: SHA-256 for bootloader: : 8c6551e255cf261e7f61ca415b440a25e380d9bfcec7f4bbd67ed4ae526dfb7d
I (909) native_ota_example: SHA-256 for current firmware: : f568ba42cbef29927eb44e5239d5cc01e6aacceb4431ea57a086f116c834617c
I (929) example_connect: Start example_connect.
I (949) wifi:wifi driver task: 3ffc0440, prio:23, stack:6656, core=0
I (959) wifi:wifi firmware version: 91b9630
I (959) wifi:wifi certification version: v7.0
I (959) wifi:config NVS flash: enabled
I (959) wifi:config nano formating: disabled
I (959) wifi:Init data frame dynamic rx buffer num: 32
I (969) wifi:Init static rx mgmt buffer num: 5
I (969) wifi:Init management short buffer num: 32
I (979) wifi:Init dynamic tx buffer num: 32
I (979) wifi:Init static rx buffer size: 1600
I (979) wifi:Init static rx buffer num: 10
I (989) wifi:Init dynamic rx buffer num: 32
I (989) wifi_init: rx ba win: 6
I (999) wifi_init: tcpip mbox: 32
I (999) wifi_init: udp mbox: 6
I (999) wifi_init: tcp mbox: 6
I (1009) wifi_init: tcp tx win: 5744
I (1009) wifi_init: tcp rx win: 5744
I (1019) wifi_init: tcp mss: 1440
I (1019) wifi_init: WiFi IRAM OP enabled
I (1019) wifi_init: WiFi RX IRAM OP enabled
I (1029) phy_init: phy_version 4780,16b31a7,Sep 22 2023,20:42:16
I (1109) wifi:mode : sta (e8:68:e7:23:58:1c)
I (1109) wifi:enable tsf
I (1109) example_connect: Connecting to ap...
I (1119) example_connect: Waiting for IP(s)
I (3529) example_connect: Wi-Fi disconnected, trying to reconnect...
I (5939) wifi:new:<11,0>, old:<1,0>, ap:<255,255>, sta:<11,0>, prof:1
I (6189) wifi:state: init -> auth (b0)
I (6219) wifi:state: auth -> assoc (0)
I (6229) wifi:state: assoc -> run (10)
I (6239) wifi:connected with ap, aid = 13, channel 11, BW20, bssid = ce:5e:f8:f0:ec:a7
I (6239) wifi:security: WPA2-PSK, phy: bgn, rssi: -15
I (6239) wifi:pm start, type: 1

I (6479) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (6899) wifi:<ba-add>idx:0 (ifx:0, ce:5e:f8:f0:ec:a7), tid:0, ssn:4, winSize:64
I (7749) esp_netif_handlers: example_netif_sta ip: 192.168.137.31, mask: 255.255.255.0, gw: 192.168.137.1
I (7749) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 192.168.137.31
I (7929) example_connect: Got IPv6 event: Interface "example_netif_sta" address: fe80:0000:0000:0000:ea68:e7ff:fe23:581c, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (7929) example_common: Connected to example_netif_sta
I (7939) example_common: - IPv4 address: 192.168.137.31,
I (7939) example_common: - IPv6 address: fe80:0000:0000:0000:ea68:e7ff:fe23:581c, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (7959) wifi:Set ps type: 0, coexist: 0

I (7959) native_ota_example: Starting OTA example task
I (7969) native_ota_example: Running partition type 0 subtype 0 (offset 0x00010000)
I (7979) main_task: Returned from app_main()
I (9739) esp-x509-crt-bundle: Certificate validated
I (11819) native_ota_example: Writing to partition subtype 16 at offset 0x110000
I (11819) native_ota_example: New firmware version: 1
I (11819) native_ota_example: Running firmware version: 2
I (11829) native_ota_example: esp_ota_begin succeeded
I (27089) native_ota_example: Connection closed
I (27089) native_ota_example: Total Write binary data length: 182368
I (27089) esp_image: segment 0: paddr=00110020 vaddr=3f400020 size=09be8h ( 39912) map
I (27119) esp_image: segment 1: paddr=00119c10 vaddr=3ffb0000 size=02158h (  8536)
I (27119) esp_image: segment 2: paddr=0011bd70 vaddr=40080000 size=042a8h ( 17064)
I (27129) esp_image: segment 3: paddr=00120020 vaddr=400d0020 size=14abch ( 84668) map
I (27159) esp_image: segment 4: paddr=00134ae4 vaddr=400842a8 size=07d54h ( 32084)
I (27169) esp_image: segment 0: paddr=00110020 vaddr=3f400020 size=09be8h ( 39912) map
I (27179) esp_image: segment 1: paddr=00119c10 vaddr=3ffb0000 size=02158h (  8536)
I (27189) esp_image: segment 2: paddr=0011bd70 vaddr=40080000 size=042a8h ( 17064)
I (27199) esp_image: segment 3: paddr=00120020 vaddr=400d0020 size=14abch ( 84668) map
I (27229) esp_image: segment 4: paddr=00134ae4 vaddr=400842a8 size=07d54h ( 32084)
I (27319) native_ota_example: Prepare to restart system!
I (27319) wifi:state: run -> init (0)
I (27319) wifi:pm stop, total sleep time: 322820 us / 21073032 us

I (27319) wifi:<ba-del>idx:0, tid:0
I (27319) wifi:new:<11,0>, old:<11,0>, ap:<255,255>, sta:<11,0>, prof:1
E (27329) wifi:NAN WiFi stop
I (27339) wifi:flush txq
I (27339) wifi:stop sw txq
I (27339) wifi:lmac stop hw txq
I (27339) wifi:Deinit lldesc rx mblock:10
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:7084
ho 0 tail 12 room 4
load:0x40078000,len:15584
load:0x40080400,len:4
0x40080400: _init at ??:?

load:0x40080404,len:3876
entry 0x4008064c
I (31) boot: ESP-IDF v5.1.2-dirty 2nd stage bootloader
I (31) boot: compile time Nov 26 2023 22:37:12
I (31) boot: Multicore bootloader
I (36) boot: chip revision: v1.0
I (40) boot.esp32: SPI Speed      : 40MHz
I (44) boot.esp32: SPI Mode       : DIO
I (49) boot.esp32: SPI Flash Size : 4MB
I (53) boot: Enabling RNG early entropy source...
I (59) boot: Partition Table:
I (62) boot: ## Label            Usage          Type ST Offset   Length
I (70) boot:  0 nvs              WiFi data        01 02 00009000 00004000
I (77) boot:  1 otadata          OTA data         01 00 0000d000 00002000
I (84) boot:  2 phy_init         RF data          01 01 0000f000 00001000
I (92) boot:  3 factory          factory app      00 00 00010000 00100000
I (99) boot:  4 ota_0            OTA app          00 10 00110000 00100000
I (107) boot:  5 ota_1            OTA app          00 11 00210000 00100000
I (114) boot: End of partition table
I (119) esp_image: segment 0: paddr=00110020 vaddr=3f400020 size=09be8h ( 39912) map
I (142) esp_image: segment 1: paddr=00119c10 vaddr=3ffb0000 size=02158h (  8536) load
I (145) esp_image: segment 2: paddr=0011bd70 vaddr=40080000 size=042a8h ( 17064) load
I (155) esp_image: segment 3: paddr=00120020 vaddr=400d0020 size=14abch ( 84668) map
I (187) esp_image: segment 4: paddr=00134ae4 vaddr=400842a8 size=07d54h ( 32084) load
I (206) boot: Loaded app from partition at offset 0x110000
I (206) boot: Disabling RNG early entropy source...
I (218) cpu_start: Multicore app
I (218) cpu_start: Pro cpu up.
I (218) cpu_start: Starting app cpu, entry point is 0x400810f0
I (206) cpu_start: App cpu up.
I (236) cpu_start: Pro cpu start user code
I (236) cpu_start: cpu freq: 160000000 Hz
I (236) cpu_start: Application information:
I (241) cpu_start: Project name:     blink
I (246) cpu_start: App version:      1
I (250) cpu_start: Compile time:     Nov 26 2023 10:10:34
I (256) cpu_start: ELF file SHA256:  44615b9489a1ce4c...
Warning: checksum mismatch between flashed and built applications. Checksum of built application is 7166a216a7cfb5c9e6af6148f9cd73bc2b16493a53a63bbe900ce54c1cc5afce
I (262) cpu_start: ESP-IDF:          v5.1.2-dirty
I (268) cpu_start: Min chip rev:     v0.0
I (272) cpu_start: Max chip rev:     v3.99
I (277) cpu_start: Chip rev:         v1.0
I (282) heap_init: Initializing. RAM available for dynamic allocation:
I (289) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (295) heap_init: At 3FFB29D0 len 0002D630 (181 KiB): DRAM
I (302) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (308) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (314) heap_init: At 4008C000 len 00014000 (80 KiB): IRAM
I (322) spi_flash: detected chip: generic
I (325) spi_flash: flash io: dio
I (330) app_start: Starting scheduler on CPU0
I (334) app_start: Starting scheduler on CPU1
I (334) main_task: Started on CPU0
I (344) main_task: Calling app_main()
I (344) example: Example configured to blink GPIO LED!
I (344) gpio: GPIO[2]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (354) example: Turning the LED OFF!
I (864) example: Turning the LED ON!
I (1364) example: Turning the LED OFF!
I (1864) example: Turning the LED ON!
I (2364) example: Turning the LED OFF!
I (2864) example: Turning the LED ON!
I (3364) example: Turning the LED OFF!
I (3864) example: Turning the LED ON!
I (4364) example: Turning the LED OFF!
I (4864) example: Turning the LED ON!
I (5364) example: Turning the LED OFF!
I (5864) example: Turning the LED ON!
I (6364) example: Turning the LED OFF!
I (6864) example: Turning the LED ON!
I (7364) example: Turning the LED OFF!
I (7864) example: Turning the LED ON!
I (8364) example: Turning the LED OFF!
I (8864) example: Turning the LED ON!
I (9364) example: Turning the LED OFF!
I (9864) example: Turning the LED ON!
I (10364) example: Turning the LED OFF!
I (10864) example: Turning the LED ON!
I (11364) example: Turning the LED OFF!
I (11864) example: Turning the LED ON!
I (12364) example: Turning the LED OFF!
I (12864) example: Turning the LED ON!
I (13364) example: Turning the LED OFF!
I (13864) example: Turning the LED ON!

3.native_ota_example代码解读

主要逻辑在 ota_example_task任务中。基本逻辑其实就是使用ESP_HTTP_CLIENT相关接口,从https服务器上下载需要OTA的bin文件,将下载数据写入到相应的flash中。

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 task");

    const esp_partition_t *configured = esp_ota_get_boot_partition();
    const esp_partition_t *running = esp_ota_get_running_partition();

    if (configured != running) {
        ESP_LOGW(TAG, "Configured OTA boot partition at offset 0x%08"PRIx32", but running from offset 0x%08"PRIx32,
                 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%08"PRIx32")",
             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,
        .crt_bundle_attach = esp_crt_bundle_attach,
        .timeout_ms = CONFIG_EXAMPLE_OTA_RECV_TIMEOUT,
        .keep_alive_enable = true,
    };

#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] = '\0';
        config.url = url_buf;
    } else {
        ESP_LOGE(TAG, "Configuration mismatch: wrong firmware upgrade image url");
        abort();
    }
#endif

#ifdef CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK
    config.skip_cert_common_name_check = true;
#endif

    esp_http_client_handle_t client = esp_http_client_init(&config);
    if (client == NULL) {
        ESP_LOGE(TAG, "Failed to initialise HTTP connection");
        task_fatal_error();
    }
    err = esp_http_client_open(client, 0);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
        esp_http_client_cleanup(client);
        task_fatal_error();
    }
    esp_http_client_fetch_headers(client);

    update_partition = esp_ota_get_next_update_partition(NULL);
    assert(update_partition != NULL);
    ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%"PRIx32,
             update_partition->subtype, update_partition->address);

    int binary_file_length = 0;
    /*deal with all receive packet*/
    bool image_header_was_checked = false;
    while (1) {
        int data_read = esp_http_client_read(client, ota_write_data, BUFFSIZE);
        if (data_read < 0) {
            ESP_LOGE(TAG, "Error: SSL data read error");
            http_cleanup(client);
            task_fatal_error();
        } else if (data_read > 0) {
            if (image_header_was_checked == false) {
                esp_app_desc_t new_app_info;
                if (data_read > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) {
                    // check current version with downloading
                    memcpy(&new_app_info, &ota_write_data[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);
                    }

                    // check current version with last invalid partition
                    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.");
                            http_cleanup(client);
                            infinite_loop();
                        }
                    }
#ifndef CONFIG_EXAMPLE_SKIP_VERSION_CHECK
                    if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version)) == 0) {
                        ESP_LOGW(TAG, "Current running version is the same as a new. We will not continue the update.");
                        http_cleanup(client);
                        infinite_loop();
                    }
#endif

                    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));
                        http_cleanup(client);
                        esp_ota_abort(update_handle);
                        task_fatal_error();
                    }
                    ESP_LOGI(TAG, "esp_ota_begin succeeded");
                } else {
                    ESP_LOGE(TAG, "received package is not fit len");
                    http_cleanup(client);
                    esp_ota_abort(update_handle);
                    task_fatal_error();
                }
            }
            err = esp_ota_write( update_handle, (const void *)ota_write_data, data_read);
            if (err != ESP_OK) {
                http_cleanup(client);
                esp_ota_abort(update_handle);
                task_fatal_error();
            }
            binary_file_length += data_read;
            ESP_LOGD(TAG, "Written image length %d", binary_file_length);
        } else if (data_read == 0) {
           /*
            * As esp_http_client_read never returns negative error code, we rely on
            * `errno` to check for underlying transport connectivity closure if any
            */
            if (errno == ECONNRESET || errno == ENOTCONN) {
                ESP_LOGE(TAG, "Connection closed, errno = %d", errno);
                break;
            }
            if (esp_http_client_is_complete_data_received(client) == true) {
                ESP_LOGI(TAG, "Connection closed");
                break;
            }
        }
    }
    ESP_LOGI(TAG, "Total Write binary data length: %d", binary_file_length);
    if (esp_http_client_is_complete_data_received(client) != true) {
        ESP_LOGE(TAG, "Error in receiving complete file");
        http_cleanup(client);
        esp_ota_abort(update_handle);
        task_fatal_error();
    }

    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));
        }
        http_cleanup(client);
        task_fatal_error();
    }

    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));
        http_cleanup(client);
        task_fatal_error();
    }
    ESP_LOGI(TAG, "Prepare to restart system!");
    esp_restart();
    return ;
}

通过 调用esp_ota_beginOTA写入分区操作,使用 esp_ota_write写入数据到分区,调用 esp_ota_end写入完成。

接着调用 esp_ota_set_boot_partition设置启动分区为刚刚写入的分区,最后通过 esp_restart重启即可运行刚刚的分区。

;