Работа с ROMFS¶
Обзор¶
ROMFS (Read-Only Memory Filesystem) – это лёгкая файловая система только для чтения, разработанная для устройств MicroPython. Она оптимизирована для микроконтроллеров и встраиваемых систем, где код и данные нужно хранить во флеш-памяти и эффективно обращаться к ним без копирования в RAM.
Основные преимущества ROMFS:
Импорт без копирования: файлы байт-кода
.mpy, хранящиеся в ROMFS, могут выполняться непосредственно из флеш-памяти (через отображение в память), а не копироваться сначала в RAM. Это похоже на работу замороженных модулей, но не требует повторной перепрошивки всей прошивки.Низкие накладные расходы RAM: константные объекты (строки, байты и т. д.) в файлах
.mpy, загруженных из ROMFS, ссылаются напрямую на флеш-память и не дублируются в RAM.Гибкое развёртывание: образ ROMFS можно собрать на хост-ПК и развернуть на устройстве с помощью mpremote, не пересобирая прошивку.
Стандартный интерфейс файловой системы: ROMFS монтируется в VFS и доступен через обычные файловые операции Python (
open,os.listdir,importи т. д.).
ROMFS дополняет как файловые системы FAT/LittleFS с доступом для чтения и записи (которые располагаются в других разделах флеш-памяти), так и замороженные модули (которые компилируются в саму прошивку).
Поддержка плат¶
ROMFS включён в прошивку OpenMV на каждой плате камеры, в схеме флеш-памяти которой зарезервирован раздел ROMFS. На этих платах раздел ROMFS автоматически обнаруживается при загрузке и монтируется в /rom; оба пути /rom и /rom/lib добавляются в sys.path, чтобы хранящиеся там модули можно было импортировать напрямую.
Плата |
Поддержка ROMFS |
|---|---|
OpenMV Cam N6 |
Да |
OpenMV AE3 |
Да |
OpenMV Cam RT1062 |
Да |
OpenMV Cam Pure Thermal |
Да |
OpenMV Cam M4 / M7 / H7 / H7 Plus |
Да |
Arduino Giga |
Да |
Arduino Portenta H7 |
Да |
Arduino Nicla Vision |
Да |
Arduino Nano 33 BLE Sense |
Нет (нет раздела ROMFS) |
Arduino Nano RP2040 Connect |
Нет (нет раздела ROMFS) |
См. romfs для специфичного для OpenMV помощника, который исследует смонтированный ROMFS в /rom.
Рабочий процесс¶
Типичный рабочий процесс использования ROMFS таков:
Создайте на своём ПК каталог с файлами Python (или файлами
.mpy), которые вы хотите развернуть.Используйте
mpremote romfs deploy <directory>, чтобы собрать и развернуть образ ROMFS на устройстве.ROMFS будет смонтирован в
/romпри следующей загрузке (или может быть смонтирован сразу, если устройство перезагрузить).Затем код Python на устройстве может выполнять
importмодулей из ROMFS точно так же, как из любой другой файловой системы.
Например:
# On the host PC, with a directory "myapp/" containing app.py:
$ mpremote romfs deploy myapp/
После программного сброса на устройстве будет доступен для импорта файл /rom/app.py (или /rom/app.mpy, если установлен mpy_cross).
Полное описание подкоманд mpremote см. в разделе подкоманды mpremote romfs ниже.
Python API¶
Python API для ROMFS предоставляется через модуль vfs.
- class vfs.VfsRom(buffer)
Создаёт объект файловой системы ROMFS из buffer, который должен быть объектом, поддерживающим протокол буфера (например, объектом
bytes,bytearrayилиmemoryview) и содержащим корректный образ ROMFS.Конструктор проверяет, что buffer начинается с магических байтов ROMFS (
b"\xd2\xcd\x31"). Если буфер слишком мал или не является корректным ROMFS, возбуждаетсяOSError(ENODEV).Объекты, созданные этим конструктором, могут быть смонтированы с помощью
vfs.mount().Пример:
import vfs # Load a ROMFS image from flash into a memoryview. dev = vfs.rom_ioctl(2, 0) # get partition 0 as a memoryview fs = vfs.VfsRom(dev) vfs.mount(fs, '/rom')
Или, чтобы смонтировать образ ROMFS, хранящийся в файле:
import vfs with open('/flash/app.romfs', 'rb') as f: romfs_data = f.read() fs = vfs.VfsRom(romfs_data) vfs.mount(fs, '/rom2')
На объекте
VfsRomдоступны следующие методы:- VfsRom.open(path, mode)
Открывает файл из ROMFS. Поддерживаются только режимы чтения (
'','r','rt','rb'). Попытка открыть файл для записи возбудитOSError(EROFS).Возвращаемый объект файла поддерживает
read(),seek(),tell()иclose(). Для двоичных файлов, открытых в режиме чтения, возвращаемый объект также поддерживает протокол буфера, так что можно получитьmemoryviewданных файла, который ссылается напрямую на память ROMFS (без копирования).
- VfsRom.ilistdir(path)
Возвращает итератор по записям в каталоге path. Каждая запись – это кортеж
(name, type, inode, size), где type равен0x8000для файла или0x4000для каталога.
- VfsRom.stat(path)
Возвращает 10-элементный кортеж в стиле
os.statдля path. ВозбуждаетOSError(ENOENT), если путь не существует.
- VfsRom.statvfs(path)
Возвращает статистику файловой системы. Размер блока сообщается как 1, а количество блоков представляет общий размер образа ROMFS в байтах. Количество свободных блоков и свободных файлов всегда равно 0 (файловая система только для чтения).
- VfsRom.chdir(path)
Изменяет каталог внутри ROMFS. Поддерживается только корень (
'/'); переход в любой подкаталог возбуждаетOSError(EOPNOTSUPP).
- VfsRom.getcwd()
Возвращает текущий рабочий каталог внутри ROMFS. Всегда возвращает
'/'.
- vfs.rom_ioctl(op, ...)
Низкоуровневый интерфейс для доступа к раздел(ам) памяти только для чтения (ROM) устройства.
Поддерживаются следующие операции:
vfs.rom_ioctl(1)– возвращает количество доступных разделов ROM.vfs.rom_ioctl(2, id)– возвращает раздел ROM с индексом id в виде объектаmemoryview. Эту память можно читать, но нельзя записывать напрямую.vfs.rom_ioctl(3, id, length)– подготавливает раздел ROM к записи. Стирает первые length байт раздела с индексом id. Возвращает минимальный размер записи в байтах (выравнивание, требуемое для последующих записей).vfs.rom_ioctl(4, id, offset, buf)– записывает buf (объект, подобный bytes) в раздел ROM с индексом id по байтовому смещению offset.vfs.rom_ioctl(5, id)– завершает последовательность записи в раздел id (выполняет любую необходимую финализацию после записи, например сброс кэша).
Эти операции используются внутренне инструментом
mpremoteдля развёртывания образов ROMFS. Большинству пользователей не нужно вызыватьvfs.rom_ioctl()напрямую.Пример (запрос доступных разделов):
import vfs n = vfs.rom_ioctl(1) print("Number of ROM partitions:", n) for i in range(n): dev = vfs.rom_ioctl(2, i) print(f" Partition {i}: {len(dev)} bytes")
Автоматическое монтирование при загрузке¶
Когда поддержка ROMFS включена в прошивке, MicroPython автоматически попытается смонтировать первый раздел ROM в /rom во время инициализации. Если раздел содержит корректный образ ROMFS, он монтируется, и оба пути /rom и /rom/lib автоматически добавляются в sys.path.
Это означает, что после развёртывания образа ROMFS с помощью mpremote достаточно программного сброса, чтобы новые модули стали доступны для импорта.
Если в разделе не найден корректный образ ROMFS (например, на только что запрограммированной плате), монтирование молча пропускается.
Использование mpremote для управления ROMFS¶
Инструмент mpremote предоставляет три подкоманды для управления образами ROMFS на подключённом устройстве.
romfs query¶
$ mpremote romfs query
Выводит список всех доступных разделов ROMFS на устройстве и их размеры. Также показывает первые 12 байт каждого раздела в шестнадцатеричном виде и сообщает, присутствует ли корректный образ ROMFS.
Пример вывода:
ROMFS0 partition has size 131072 bytes (32 blocks of 4096 bytes each)
Raw contents: d2:cd:31:XX:XX:XX:XX:XX:XX:XX:XX:XX ...
ROMFS image size: 1234
romfs build¶
$ mpremote romfs [-o <output>] build <source>
Собирает образ ROMFS из каталога source на хост-ПК. Образ записывается в output (по умолчанию: <source>.romfs).
Параметры:
-o <output>,--output <output>: задаёт путь к выходному файлу.-m,--mpy(по умолчанию): автоматически компилирует файлы.pyв.mpyс помощьюmpy_crossперед добавлением их в образ. Требует пакет Pythonmpy_cross(pip install mpy_cross).--no-mpy: отключает автоматическую компиляцию файлов.py.
Пример:
$ mpremote romfs build myapp/
Building romfs filesystem, source directory: myapp/
/
|-- main.py -> .mpy
\-- lib/
\-- helper.py -> .mpy
Writing 2048 bytes to output file myapp.romfs
romfs deploy¶
$ mpremote romfs [-p <partition>] deploy <source>
Развёртывает образ ROMFS на устройстве. source может быть одним из следующего:
Каталог на хосте: образ ROMFS собирается в памяти и развёртывается напрямую.
Файл
.romfsили.img: образ читается с диска и развёртывается.
Параметры:
-p <partition>,--partition <partition>: задаёт индекс целевого раздела (по умолчанию:0).-m,--mpy(по умолчанию): компилирует.pyв.mpy, когда source – это каталог.--no-mpy: отключает автоматическую компиляцию файлов.py.
После развёртывания устройство необходимо программно сбросить, чтобы новый ROMFS был смонтирован в /rom.
Пример:
$ mpremote romfs deploy myapp/
Building romfs filesystem, source directory: myapp/
/
|-- main.py -> .mpy
\-- lib/
\-- helper.py -> .mpy
Image size is 2048 bytes
ROMFS0 partition has size 131072 bytes (32 blocks of 4096 bytes each)
Preparing ROMFS0 partition for writing
Deploying ROMFS to ROMFS0 partition
ROMFS image deployed
$ mpremote soft-reset
Примеры¶
Развёртывание простого приложения¶
Предположим, у вас есть каталог проекта myapp/ со следующей структурой:
myapp/
main.py
utils.py
lib/
helper.py
Чтобы развернуть его в ROMFS устройства:
$ mpremote romfs deploy myapp/
После программного сброса модули можно импортировать из ROMFS:
import main
import utils
from lib import helper
Просмотр содержимого ROMFS из Python¶
После монтирования содержимое ROMFS можно просматривать как у любой другой файловой системы:
import os
for entry in os.ilistdir('/rom'):
print(entry)
# Or simply:
print(os.listdir('/rom'))
OpenMV также поставляет небольшой помощник romfs, который выводит отформатированный список, включая отображённый в память адрес и выравнивание каждого файла:
from omv import romfs
romfs.ls_romfs()
Вложение ROMFS внутрь ROMFS¶
Образ ROMFS, хранящийся как файл внутри внешнего ROMFS, может быть смонтирован как вложенная файловая система. Например, если существует /rom/inner.romfs. Поскольку /rom – это ROMFS, объекты файлов, открытые из него, поддерживают протокол буфера, так что можно получить напрямую memoryview без копирования:
import vfs
with open('/rom/inner.romfs', 'rb') as f:
inner = vfs.VfsRom(memoryview(f))
vfs.mount(inner, '/inner')
print(os.listdir('/inner'))
Формат образа ROMFS¶
Формат образа ROMFS – это компактный двоичный формат, разработанный для отображённого в память доступа на микроконтроллерах. Краткий обзор:
Образ начинается с магических байтов
0xd2 0xcd 0x31(закодированных как"RM1"с установленными старшими битами первых двух байт).Остальная часть образа состоит из записей, каждая из которых имеет тег типа (varuint), длину (varuint) и полезную нагрузку.
Типы записей включают: заполнение, дословные данные, косвенный указатель данных, каталог, файл.
Имена каталогов и файлов хранятся как байтовые строки с префиксом длины.
Данные файла могут храниться дословно (встроенно) или через косвенный указатель на другое место в образе, что обеспечивает выравнивание для отображённого в память доступа.
Неизвестные типы записей молча пропускаются, обеспечивая совместимость с будущими версиями.
Этот формат определён в файле extmod/vfs_rom.c в исходном коде MicroPython. Реализация на Python, используемая mpremote для сборки образов, находится в tools/mpremote/mpremote/romfs.py.
См. также
Работа с файловыми системами – обзор VFS MicroPython и доступных типов файловых систем.
Файлы манифеста MicroPython – как замораживать модули Python в прошивку.
Файлы .mpy в MicroPython – двоичный формат файлов .mpy MicroPython.
Удалённое управление MicroPython: mpremote – полный справочник команд mpremote.
romfs – помощник OpenMV для исследования смонтированной файловой системы /rom.