OTA and Partitions - mriksman/esp-idf-homekit GitHub Wiki
OTA and Partitions
Flash Layout
Pre v3.0 ESP8266 RTOS SDK and ESP8266 NONOS SDK (Arduino)
The flash layout for ESP8266 is defined in the ld files \ld\eagle.flash.1m*.ld
. In the Arduino IDE, it can be selected via a menu item.
Flash Split for 1M chips
----------------------------------------- -----------------------------------------
256KB 64KB
sketch @0x40200000 (~743KB) (761840B) sketch @0x40200000 (~935KB) (958448B)
empty @0x402B9FF0 (~4KB) (4112B) empty @0x402E9FF0 (~4KB) (4112B)
spiffs @0x402BB000 (~256KB) (262144B) spiffs @0x402EB000 (~64KB) (65536B)
eeprom @0x402FB000 (4KB) eeprom @0x402FB000 (4KB)
rfcal @0x402FC000 (4KB) rfcal @0x402FC000 (4KB)
wifi @0x402FD000 (12KB) wifi @0x402FD000 (12KB)
ESP-IDF and ESP8266 RTOS v3.x
ESP-IDF and ESP8266 RTOS SDK v3.x and higher now uses the same partition/build strategy. You create a csv
file describing the flash partitions and configure the project to use it in menuconfig
.
HomeKit
HomeKit stores its data in flash, so I created a custom partition labelled homekit
. The Type should be set between 0x40-0xFE
which is for custom partition types. The minimum size for any partition is 4096 bytes. The NVS is recommended to be between 12 and 24KB. Note the app partitions need to start on a 0x10000
offset.
Name Type SubType Offset Size
------------- ---------- ------------- ------------ ----------
nvs data nvs 0x9000 16K
homekit 0x40 0 0xd000 4K
otadata data ota 0xe000 8K
app0 app ota_0 0x10000 384K
app1 app ota_1 0x70000 576K
Using idf.py menuconfig | Component Configuration
you can set the 'SPI Flash Address for Storing HomeKit Data'
Changing NVS Partition Size -- Erase and Initialise
A lot of example code for ESP-IDF has the following NVS initialisation code at the top of app_main()
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
However, when I changed the NVS partition size and compiled under ESP8266 RTOS SDK, the program would crash before even reaching app_main()
. In components/esp8266/source/startup.c
, it calls assert(nvs_flash_init() == 0)
which fails. I had to comment out this code, perform a nvs_flash_erase()
and then remove the comment. Thus, there is no need to call nvs_flash_init()
in ESP8266 RTOS SDK as it has already been called.
Building OTA Binary Apps
For ESP-IDF, you can build a binary application bound for ota_1
as per normal and upload the projectname.bin
to any ota partition.
- Create a partition with
ota_0
andota_1
- Load (via serial) an application into
ota_0
- Create the
hello_world
example, and simplyidf build
to create the bin file - Use the application in
ota_0
to load thehello_world.bin
intoota_1
But for ESP8266 RTOS SDK, it doesn't work. eps_ota_end()
complains;
D (48942) esp_image: reading image header @ 0x70000
D (48949) esp_image: image header: 0xe9 0x05 0x02 0x01 40210a9c
D (49040) esp_ota_ops: OTA binary start entry 0x10a8c, partition start from 0x70000 to 0x100000
E (49050) esp_ota_ops: **Important**: The OTA binary link data is error, please refer to document <<ESP8266_RTOS_SDK/examples/system/ota/README.md>> for how to generate OTA binaries
E (49076) httpd: Image validation failed, image is corrupted
Looking at the function esp_ota_verify_binary()
in esp_ota_ops.c
, it checks to make sure the entry address is between pos->offset
and pos->offset + pos->size
(start and finish). However, the entry address was set to 0x10a8c
-- assuming that it would be flashed to app0
.
More peculiar is that it only checks this if flash chip is 1MB or less
if (pos‑\>offset + pos‑\>size \<= 0x100000)
When I set the partition to be larger and expand past 1MB (but leaving offset at 0x7000
), the error wasn't generated but the subsequent boot into ota_1
would crash. The only way it would work is if I made ota_1
start at address 0x110000
;
exactly 1MB after ota_0
. This is vaguely mentioned in their documentation.
The examples online suggest you can run make ota
and it will configure two binary files; one bound for ota_0
and one bound for ota_1
. Looking at components/esp8266/Makefile.projbuild
it has the functions to create the two OTA bin files with the correct app_offset
, but the CMakeLists.txt
does not have this ability.
For CMakeLists.txt
I edited lines 96 and 97 from
partition_table_get_partition_info(app_offset "--partition-boot-default" "offset")
partition_table_get_partition_info(app_size "--partition-boot-default" "size")
to
partition_table_get_partition_info(app_offset "-- partition-name app1" "offset")
partition_table_get_partition_info(app_size "-- partition-name app1" "size")
I built the program and uploaded it via the HTTP OTA Server I had running in ota_0
.
D (2778245) esp_ota_ops: OTA binary start entry 0x70a8c, partition start from 0x70000 to 0x100000
D (2778255) esp_image: reading image header @ 0x70000
As I suspected. It works, and the entry is where I thought it would be. To manage this for different projects, I have changed the lines to be;
if (DEFINED PARTITION_NAME)
partition_table_get_partition_info(app_offset "--partition-name ${PARTITION_NAME}" "offset")
partition_table_get_partition_info(app_size "--partition-name ${PARTITION_NAME}" "size")
else()
partition_table_get_partition_info(app_offset "--partition-boot-default" "offset")
partition_table_get_partition_info(app_size "--partition-boot-default" "size")
endif()
message(STATUS "Using partition located at offset " ${app_offset} " with size " ${app_size})
And in the main project CmakeLists.txt
;
# used in components/esp8266/CMakeLists.txt to select which partition this
# .bin file will be loaded; sets entry address accordingly
set(PARTITION_NAME app1)