Partition table migration
This guidance applies to esp8266 devices only.
Sming after v4.2 requires a valid partition table. If existing devices running previous versions of Sming require updating via OTA then an intermediate firmware should be created which installs this partition table.
After rBoot hands control to the SDK entrypoint, the user_pre_init()
function is called.
This function is documented in the NON-OS-SDK guide and was introduced in version 3.
It is called by the SDK before user_init() so nothing else in the framework has yet been initialised,
including any C++ static initialisers.
Sming uses this function to read the partition table and pass the required information to the SDK
(via partition_table_regist()
).
By overriding (wrapping
) this function, applications have the opportunity to perform any
additional checks or upgrades on the partition table before proceeding.
Add to application’s component.mk:
EXTRA_LDFLAGS := $(call Wrap,user_pre_init)
USER_CFLAGS += -DPARTITION_TABLE_OFFSET=$(PARTITION_TABLE_OFFSET)
Add this to your application:
// Support updating legacy devices without partition tables (Sming 4.2 and earlier)
#ifdef ARCH_ESP8266
namespace
{
// Note: This file won't exist on initial build!
IMPORT_FSTR(partitionTableData, PROJECT_DIR "/out/Esp8266/debug/firmware/partitions.bin")
// Optionally include updated bootloader
// IMPORT_FSTR(rbootData, PROJECT_DIR "/out/Esp8266/debug/firmware/rboot.bin")
}
// Called by SDK
extern "C" void __wrap_user_pre_init(void)
{
// Make sure code is compiled with expected partition table offset - adjust as required
static_assert(PARTITION_TABLE_OFFSET == 0x3fa000, "Bad PTO");
// Attempt to load the partition table
Storage::initialize();
auto& flash = *Storage::spiFlash;
if(!flash.partitions()) {
/*
* No partitions were found, which implies this device was previously
* running with a pre Sming 4.3 firmware.
*/
// Write our partition table data to flash
{
LOAD_FSTR(data, partitionTableData)
flash.erase_range(PARTITION_TABLE_OFFSET, flash.getBlockSize());
flash.write(PARTITION_TABLE_OFFSET, data, partitionTableData.size());
}
// Load the newly written partition information
flash.loadPartitions(PARTITION_TABLE_OFFSET);
// Optionally update bootloader
// LOAD_FSTR(data, rbootData)
// flash.erase_range(0, flash.getBlockSize());
// flash.write(0, data, rbootData.size());
}
// Pass control back to Sming
extern void __real_user_pre_init(void);
__real_user_pre_init();
}
#endif // ARCH_ESP8266
Note
You will get a ‘file not found’ error because the partition table gets built after compiling the application.
You can run make partmap-build
manually first to get around this.
An alternative method is to build the partition table layout in code, so there are no external file dependencies:
// Support updating legacy devices without partition tables (Sming 4.2 and earlier)
#ifdef ARCH_ESP8266
// Need low-level definition for the on-flash `esp_partition_info_t` structure
#include <Storage/partition_info.h>
extern "C" void __wrap_user_pre_init(void)
{
static_assert(PARTITION_TABLE_OFFSET == 0x3fa000, "Bad PTO");
Storage::initialize();
auto& flash = *Storage::spiFlash;
if(!flash.partitions()) {
using FullType = Storage::Partition::FullType;
using SubType = Storage::Partition::SubType;
#define PT_ENTRY(name, fulltype, offset, size) \
{ Storage::ESP_PARTITION_MAGIC, FullType(fulltype).type, FullType(fulltype).subtype, offset, size, name, 0 }
// Amend this layout as required so it corresponds with your existing device
static constexpr Storage::esp_partition_info_t partitionTableData[] PROGMEM{
PT_ENTRY("spiFlash", Storage::Device::Type::flash, 0, 0x400000),
PT_ENTRY("rom0", SubType::App::ota0, 0x2000, 0xf8000),
PT_ENTRY("spiffs0", SubType::Data::spiffs, 0x100000, 0xc0000),
PT_ENTRY("rom1", SubType::App::ota1, 0x202000, 0xf8000),
PT_ENTRY("spiffs1", SubType::Data::spiffs, 0x300000, 0xc0000),
PT_ENTRY("rf_cal", SubType::Data::rfCal, 0x3fb000, 0x1000),
PT_ENTRY("phy_init", SubType::Data::phy, 0x3fc000, 0x1000),
PT_ENTRY("sys_param", SubType::Data::sysParam, 0x3fd000, 0x3000),
};
uint8_t buffer[sizeof(partitionTableData)];
memcpy(buffer, partitionTableData, sizeof(partitionTableData));
flash.erase_range(PARTITION_TABLE_OFFSET, flash.getBlockSize());
flash.write(PARTITION_TABLE_OFFSET, buffer, sizeof(buffer));
flash.loadPartitions(PARTITION_TABLE_OFFSET);
}
extern void __real_user_pre_init(void);
__real_user_pre_init();
}
#endif // ARCH_ESP8266
This example is based on a typical Sming 4.0 4MByte flash layout as for the Basic_rBoot
sample application.
The above examples are provided as templates and should be modified as required and tested thoroughly!