ESP32: таблицы разделов |
![]() |
Добавил(а) microsin |
Одна flash-микросхема памяти ESP32 может содержать как несколько приложений, так и несколько разновидностей данных (данные калибровки, файловые системы, хранилище параметров и т. д.). По этому таблица разделов прошивается во flash по адресу 0x8000 (смещение по умолчанию). Длина таблицы разделов составляет 0xC00 байт (что дает максимальное колиество записей 95). Контрольная сумма MD5, которая используется для проверки целостности таблицы разделов, прикрепляется в конце данных таблицы. Каждая запись в таблице разделов имеет имя (метку, label), тип (app, data, или что-нибудь еще), подтип (subtype) и смещение во flash-памяти, куда загружен раздел. Самый простой способ использовать таблицу разделов - открыть меню конфигурации проекта (idf.py menuconfig) и опцией CONFIG_PARTITION_TABLE_TYPE выбрать одну из предварительно определенных таблиц разделов: • Single factory app, no OTA (одно заводское приложение, без OTA) Заводское приложение прошивается со смещением 0x10000. Если выполнить команду idf.py partition-table, то она напечатает общую информацию таблицы разделов (перед выполнением этой команды надо сделать текущей директорию проекта). [Встроенные таблицы разделов] Пример вывода общей информации для конфигурации "Single factory app, no OTA": # ESP-IDF Partition Table # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, • Со смещением 0x10000 (64 KB) во flash записано приложение помеченное как "factory". Загрузчик (bootloader) будет по умолчанию запускать это приложение. Пример вывода общей информации для конфигурации "Factory app, two OTA definitions": # ESP-IDF Partition Table # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x4000, otadata, data, ota, 0xd000, 0x2000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 1M, ota_0, app, ota_0, 0x110000, 1M, ota_1, app, ota_1, 0x210000, 1M, • Здесь присутствует определение трех разделов приложений (тип app): приложение factory по адресу 0x10000 и следующие два OTA-приложения. Обратите внимание, что подтипы приложений отличаются. [Создание пользовательских таблиц] Если в menuconfig выбрано "Custom partition table CSV", то можно также ввести имя CSV-файла (находящегося в директории проекта), чтобы использовать его для пользовательской таблицы разделов. CSV-файл может описывать любое количество определений для той таблицы, которая Вам нужна. Формат CSV-файла такой же, как показанный в примерах выше вывод информации по команде idf.py partition-table. Однако в CSV требуются не все поля. Например, может быть следующий входной CSV-файл для таблицы разделов OTA: # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x4000 otadata, data, ota, 0xd000, 0x2000 phy_init, data, phy, 0xf000, 0x1000 factory, app, factory, 0x10000, 1M ota_0, app, ota_0, , 1M ota_1, app, ota_1, , 1M nvs_key, data, nvs_keys, , 0x1000 • Пробелы между полями игнорируются, как и любая строка, начинающаяся на символ # (комментарий). Поле Name. Это поле имени, в нем может быть любое осмысленное значение. Для ESP32 содержимое поля имени не имеет значения. Имена длиннее 16 символов обрезаются. Поле Type. Это поле типа, в котором может быть app (0x00) или data (0x01). Или же здесь может быть число в диапазоне 0-254 (hex 0x00-0xFE). Типы 0x00-0x3F зарезервированы для функций ядра ESP-IDF. Если Вашему приложению нужно сохранить данные в формате, который не поддерживается ESP-IDF, то добавляйте раздел с типом в диапазоне 0x40-0xFE. См. перечисление esp_partition_type_t для определения разделов app и data. Если приложение пишется на C++, то указание типа раздела, определяемого для приложения, требует приведения типа от целого значения в значение esp_partition_type_t, чтобы тип можно было использовать в API разделов. Например: static const esp_partition_type_t APP_PARTITION_TYPE_A = (esp_partition_type_t)0x40; Загрузчик (bootloader) ESP-IDF игнорирует любые типы разделов, которые отличаются от app (0x00) и data (0x01). Поле SubType. 8-битное поле подтипа специфическое для каждого типа раздела. ESP-IDF в настоящее время указывает осмысленные значения поля subtype только для типов разделов app и data. Перечисление esp_partition_subtype_t, где приведен полный список подтипов, определенных средой разработки ESP-IDF, включает следующее: • Когда тип app, поле subtype может быть указано как factory (0x00), ota_0 (0x10) … ota_15 (0x1F), или test (0x20). - factory (0x00) это раздел приложения по умолчанию. Загрузчик выполнит приложение factory за исключением случаев, когда он увидит раздел типа data/ota. Для этого раздела загрузчик прочитает его, чтобы определить, какой образ OTA загружать. OTA никогда не обновляет раздел factory. Если необходимо экономить использование flash-памяти в проекте OTA, то можно удалить раздел factory, и использовать вместо него ota_0. • Когда у раздела тип data, поле subtype может быть указано как ota (0x00), phy (0x01), nvs (0x02), nvs_keys (0x04), либо оно может быть подтипом, специфичным для компонента (см. описание перечисления esp_partition_subtype_t для значений subtype [6]). - ota (0) это раздел данных OTA, где находится информация о том, какой в настоящий момент выбран слот приложения (OTA app slot). У этого раздела должен быть размер 0x2000 байт, подробнее см. раздел "OTA Data Partition" документации по OTA [3]. В конфигурации по умолчанию раздел phy не используется, и данные инициализации PHY компилируются в составе самого приложения. В этом случае раздел phy может быть удален из таблицы разделов, чтобы экономить место flash. Для загрузки данных PHY из этого раздела откройте меню конфигурации проекта (idf.py menuconfig), и разрешите опцию CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION. Также понадобится прошивка вашего устройства данными phy init, поскольку система разработки ESP-IDF не делает это автоматически. - nvs (2) это раздел энергонезависимого хранилища (Non-Volatile Storage, NVS), доступное через соответствующее API [4]. NVS используется для хранение данных калибровки PHY для каждого устройства (эти данные отличаются от данных инициализации). NVS используется для хранения данных WiFi, если используется функция инициализации esp_wifi_set_storage(WIFI_STORAGE_FLASH). NVS API может также использоваться для других данных приложения. Настоятельно рекомендуется включить в проект раздел NVS размером как минимум 0x3000 байт. Если для хранения большого количества данных используется NVS API, то размер по умолчанию 0x6000 байт (24K) может оказаться недостаточным, и его следует увеличить. - nvs_keys (4) это раздел для ключа, подробнее см [4]. В разделе nvs_keys хранятся ключи шифрования NVS, когда разрешена функция NVS Encryption. Размер этого раздела должен быть равен 4096 байт (минимальный размер раздела). Существуют и другие предопределенные подтипы данных для хранилища данных, поддерживаемые ESP-IDF. Эти типы включают файловую систему FAT (ESP_PARTITION_SUBTYPE_DATA_FAT), SPIFFS (ESP_PARTITION_SUBTYPE_DATA_SPIFFS), и т. д. Другие подтипы данных зарезервированы для будущего использования в ESP-IDF. Если у типа раздела задано значение, определяемое приложением (в диапазоне 0x40-0xFE), то поле subtype может быть любого значения, выбранного приложением (в диапазоне 0x00-0xFE). Обратите внимание, что когда приложение пишется на C++, определяемое приложением значение субтипа должно быть приведено к типу esp_partition_subtype_t, чтобы его можно было использовать в API-функциях разделов. Поля Offset и Size. Разделы, в описании CSV-файла которых поле смещения пустое, будет начинаться после предыдущего раздела, или после таблицы разделов в случае первого раздела. Разделы типа app должны быть размещены со смещением, выровненным на блок размером 0x10000 байт (64K). Если оставить поле offset пустым, то скрипт gen_esp32part.py автоматически выровняет смещение раздела. Если было указано не выровненное смещение для раздела app, то скрипт возвратит ошибку. Размеры (Size) и смещения могут задаваться десятичными числами, в hex-виде с префиксом 0x, или с помощью мультипликаторов единиц размера K или M (единицы 1024 или 1024*1024 байт соответственно). Если необходимо, чтобы разделы в таблице разделов работали относительно любого размещения (CONFIG_PARTITION_TABLE_OFFSET) самой таблицы, то оставьте поле смещения (в файле CSV) для всех разделов пустым. Аналогично, при изменении смещения таблицы разделов следует иметь в виду, что все пустые смещения разделов могут быть изменены, и любые фиксированные значения смещений могут столкнуться с таблицей разделов (что вызовет ошибку). Поле Flags. В настоящее время поддерживается только один флаг, encrypted. Если это поле установлено в encrypted, то этот раздел будет зашифрован, если разрешена функция Flash Encryption. Замечание: разделы типа app всегда будут незашифрованными, независимо от того, установлен ли этот флаг, или нет. [Генерация двоичной таблицы разделов] Таблица разделов, которая прошивается в ESP32, имеет двоичный формат, не CSV. Для преобразования CSV в двоичный формат используется утилита partition_table/gen_esp32part.py. Если Вы конфигурируете имя таблицы разделов CSV в конфигурации проекта (idf.py menuconfig), и затем выполняете сборку проекта или запускаете idf.py partition-table, то это преобразование осуществляется как часть процесса сборки. Для преобразования CSV в двоичный формат вручную, запустите следующую команду: python gen_esp32part.py input_partitions.csv binary_partitions.bin Для обратного преобразования двоичного формата в CSV вручную: python gen_esp32part.py binary_partitions.bin input_partitions.csv Для отображения содержимого двоичной таблицы разделов в stdout (таким образом генерируются суммарные отчеты, когда при запуске idf.py partition-table генерируется таблица разделов: python gen_esp32part.py binary_partitions.bin [Проверки размера разделов] Подсистема сборки ESP-IDF будет автоматически проверять, соответствуют ли сгенерированные двоичные файлы доступному пространству раздела, и произойдет ошибка, если двоичные данные для раздела слишком большие. В настоящее время эти проверки выполняются для следующих двоичных файлов: • Бинарный код загрузчика (bootloader) должен поместиться в пространство перед таблицей загрузчика (см. раздел "Bootloader Size" документации [5]). Важное замечание: хотя процесс сборки завершится неудачей, если проверка размера вернет ошибку, то двоичные файлы все равно будут сгенерированы и могут быть прошиты во flash-память (хотя они могут не работать, если слишком большие для доступного пространства). Контрольная сумма MD5. Двоичный формат таблицы разделов содержит контрольную сумму MD5, вычисленную по содержимому таблицы разделов. Эта контрольная сумма используется для проверки целостности таблицы разделов во время загрузки (boot). Генерация контрольной суммы MD5 может быть запрещена опцией --disable-md5sum скрипта gen_esp32part.py, или опцией конфигурацией CONFIG_PARTITION_TABLE_MD5. Это полезно, например, когда используется bootloader из ESP-IDF версии до v3.1, который не мог обрабатывать контрольные суммы MD5, и загрузка завершится неудачей с сообщением об ошибке invalid magic number 0xebeb. [Прошивка таблицы разделов] Таблицу разделов можно прошить в память flash следующими командами: idf.py partition-table-flash: эта команда прошьет таблицу раздела с помощью утилиты esptool.py. Результаты команды ручной прошивки также печатаются как часть вывода idf.py partition-table. Важное замечание: обратите внимание, что обновление таблицы разделов не стирает данные, которые были сохранены в старую таблицу разделов. Вы можете использовать команду idf.py erase-flash (или esptool.py erase_flash) для полной очистки содержимого памяти flash. [Partition Tool (parttool.py)] Компонент partition_table предоставляет скрипт parttool.py для операций, связанных с разделами на целевом устройстве. Эта утилита может выполнять следующее: • Чтение раздела и сохранение его содержимого в файл (read_partition). Утилита может быть импортирована и использоваться из другого скрипта Python, или может запускаться из командной строки (shell-скрипта) для пользователей, которые хотят программно выполнять операции с разделами. Этому способствует интерфейс Python API и интерфейс командной строки соответственно. Предварительно убедитесь, что импортирован модуль parttool. import sys import os # Получение значения переменной окружения IDF_PATH: idf_path = os.environ["IDF_PATH"] # parttool.py находится в каталоге $IDF_PATH/components/partition_table parttool_dir = os.path.join(idf_path, "components", "partition_table") sys.path.append(parttool_dir) # позволит Python найти модуль parttool from parttool import * # импорт всех имен внутри модуля parttool Отправной точкой для использования Python API утилиты является создание объекта ParttoolTarget: # Создание целевого устройства partool.py, подключенного
# к последовательному порту /dev/ttyUSB1: target = ParttoolTarget("/dev/ttyUSB1") Созданный объект теперь может использоваться для выполнения операций на целевом устройстве: # Стирание раздела с именем 'storage': target.erase_partition(PartitionName("storage")) # Чтение раздела типа 'data' и подтипа 'spiffs', и сохранение
# его в файл 'spiffs.bin': target.read_partition(PartitionType("data", "spiffs"), "spiffs.bin") # Запись в раздел 'factory' содержимого файла с именем 'factory.bin': target.write_partition(PartitionName("factory"), "factory.bin") # Печать размера раздела загрузки по умолчанию (default boot partition): storage = target.get_partition_info(PARTITION_BOOT_DEFAULT)print(storage.size) Раздел, на котором производится операция, указывается с помощью либо PartitionName, либо PartitionType, либо PARTITION_BOOT_DEFAULT. Как подразумевает имя, они позволяют ссылаться на раздел по определенному имени, комбинации type-subtype, или через указание default boot partition. Дополнительную информацию по Python API можно получить из строк документирования утилиты. parttool.py [command-args] [subcommand] [subcommand-args] - command-args - аргументы, которые нужны для выполнения основной команды (parttool.py). В основном они относятся к целевому устройству. # Стирание раздела с именем 'storage' parttool.py --port "/dev/ttyUSB1" erase_partition --partition-name=storage # Чтение раздела типа 'data' и подтипа 'spiffs', и сохранение в файл 'spiffs.bin' parttool.py --port "/dev/ttyUSB1" read_partition --partition-type=data --partition-subtype=spiffs --output "spiffs.bin" # Запись в раздел 'factory' содержимого файла 'factory.bin' parttool.py --port "/dev/ttyUSB1" write_partition --partition-name=factory --input "factory.bin" # Печать размера default boot partition parttool.py --port "/dev/ttyUSB1" get_partition_info --partition-boot-default --info size Дополнительную информацию можно получить, если в качестве аргумента указать –help: # Отображение субкоманд и описаний аргумента основной команды parttool.py --help # Показать описания аргументов определенной субкоманды parttool.py [subcommand] --help [Словарик] NVS Non-Volatile Storage, энергонезависимое хранилище данных. OTA Over-the-Air, обновление приложения по радио. PHY PHysical Layer, оборудование физического уровня реализации Ethernet, Wi-Fi или Bluetooth. [Ссылки] 1. ESP32 Partition Tables site:docs.espressif.com. |