Praca z ROMFS¶
Przegląd¶
ROMFS (Read-Only Memory Filesystem) to lekki system plików tylko do odczytu, zaprojektowany dla urządzeń MicroPython. Jest zoptymalizowany pod kątem mikrokontrolerów i systemów wbudowanych, w których kod i dane muszą być przechowywane w pamięci flash i wydajnie dostępne bez konieczności kopiowania do pamięci RAM.
Najważniejsze zalety ROMFS to:
Importy bez kopiowania (zero-copy): pliki bajtkodu
.mpyprzechowywane w ROMFS mogą być wykonywane bezpośrednio z pamięci flash (mapowanej do pamięci) zamiast być najpierw kopiowane do pamięci RAM. Działa to podobnie do modułów zamrożonych, ale nie wymaga ponownego programowania całego oprogramowania układowego.Niewielkie zużycie pamięci RAM: stałe obiekty (łańcuchy znaków, bajty itp.) w plikach
.mpywczytywanych z ROMFS są odwoływane bezpośrednio z pamięci flash, a nie powielane w pamięci RAM.Elastyczne wdrażanie: obraz ROMFS można zbudować na komputerze hosta i wdrożyć na urządzeniu za pomocą mpremote, bez ponownego budowania oprogramowania układowego.
Standardowy interfejs systemu plików: ROMFS jest montowany w VFS i dostępny poprzez zwykłe operacje na plikach w Pythonie (
open,os.listdir,importitp.).
ROMFS uzupełnia zarówno systemy plików FAT/LittleFS z możliwością odczytu i zapisu (które znajdują się w innych partycjach pamięci flash), jak i moduły zamrożone (które są kompilowane bezpośrednio do oprogramowania układowego).
Wsparcie dla płytek¶
ROMFS jest włączony w oprogramowaniu układowym OpenMV na każdej płytce kamery, która ma zarezerwowaną partycję ROMFS w swoim układzie pamięci flash. Na tych płytkach partycja ROMFS jest automatycznie wykrywana przy uruchomieniu i montowana w /rom; zarówno /rom, jak i /rom/lib są dodawane do sys.path, dzięki czemu przechowywane tam moduły można importować bezpośrednio.
Płytka |
Wsparcie dla ROMFS |
|---|---|
OpenMV Cam N6 |
Tak |
OpenMV AE3 |
Tak |
OpenMV Cam RT1062 |
Tak |
OpenMV Cam Pure Thermal |
Tak |
OpenMV Cam M4 / M7 / H7 / H7 Plus |
Tak |
Arduino Giga |
Tak |
Arduino Portenta H7 |
Tak |
Arduino Nicla Vision |
Tak |
Arduino Nano 33 BLE Sense |
Nie (brak partycji ROMFS) |
Arduino Nano RP2040 Connect |
Nie (brak partycji ROMFS) |
Zobacz romfs, aby poznać narzędzie pomocnicze specyficzne dla OpenMV, które analizuje zamontowany ROMFS w /rom.
Przepływ pracy¶
Typowy przepływ pracy podczas korzystania z ROMFS jest następujący:
Utwórz na swoim komputerze katalog zawierający pliki Pythona (lub pliki
.mpy), które chcesz wdrożyć.Użyj
mpremote romfs deploy <directory>, aby zbudować i wdrożyć obraz ROMFS na urządzeniu.ROMFS zostanie zamontowany w
/romprzy następnym uruchomieniu (lub może zostać zamontowany natychmiast po ponownym uruchomieniu urządzenia).Kod Pythona na urządzeniu może następnie importować (
import) moduły z ROMFS tak samo jak z dowolnego innego systemu plików.
Na przykład:
# On the host PC, with a directory "myapp/" containing app.py:
$ mpremote romfs deploy myapp/
Po miękkim resecie urządzenie będzie miało dostępny do importu plik /rom/app.py (lub /rom/app.mpy, jeśli zainstalowano mpy_cross).
Pełne szczegóły dotyczące podpoleceń mpremote znajdują się w sekcji podpolecenia mpremote romfs poniżej.
API Pythona¶
API ROMFS dla Pythona jest udostępniane poprzez moduł vfs.
- class vfs.VfsRom(buffer)
Tworzy obiekt systemu plików ROMFS z buffer, który musi być obiektem obsługującym protokół buforów (np. obiektem
bytes,bytearraylubmemoryview) zawierającym prawidłowy obraz ROMFS.Konstruktor sprawdza, czy buffer zaczyna się od magicznych bajtów ROMFS (
b"\xd2\xcd\x31"). Jeśli bufor jest zbyt mały lub nie jest prawidłowym ROMFS, zgłaszany jestOSError(ENODEV).Obiekty utworzone przez ten konstruktor można zamontować za pomocą
vfs.mount().Przykład:
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')
Lub, aby zamontować obraz ROMFS przechowywany w pliku:
import vfs with open('/flash/app.romfs', 'rb') as f: romfs_data = f.read() fs = vfs.VfsRom(romfs_data) vfs.mount(fs, '/rom2')
Na obiekcie
VfsRomdostępne są następujące metody:- VfsRom.open(path, mode)
Otwiera plik z ROMFS. Obsługiwane są tylko tryby odczytu (
'','r','rt','rb'). Próba otwarcia pliku do zapisu spowoduje zgłoszenieOSError(EROFS).Zwracany obiekt pliku obsługuje
read(),seek(),tell()orazclose(). W przypadku plików binarnych otwartych w trybie odczytu zwracany obiekt obsługuje również protokół buforów, dzięki czemu można uzyskaćmemoryviewdanych pliku, który odwołuje się bezpośrednio do pamięci ROMFS (bez kopiowania).
- VfsRom.ilistdir(path)
Zwraca iterator po wpisach w katalogu path. Każdy wpis jest krotką
(name, type, inode, size), gdzie type wynosi0x8000dla pliku lub0x4000dla katalogu.
- VfsRom.stat(path)
Zwraca 10-elementową krotkę w stylu
os.statdla path. ZgłaszaOSError(ENOENT), jeśli ścieżka nie istnieje.
- VfsRom.statvfs(path)
Zwraca statystyki systemu plików. Rozmiar bloku jest raportowany jako 1, a liczba bloków reprezentuje całkowity rozmiar obrazu ROMFS w bajtach. Liczba wolnych bloków i wolnych plików zawsze wynosi 0 (system plików tylko do odczytu).
- VfsRom.chdir(path)
Zmienia katalog w obrębie ROMFS. Obsługiwany jest tylko katalog główny (
'/'); zmiana na dowolny podkatalog zgłaszaOSError(EOPNOTSUPP).
- VfsRom.getcwd()
Zwraca bieżący katalog roboczy w obrębie ROMFS. Zawsze zwraca
'/'.
- vfs.rom_ioctl(op, ...)
Niskopoziomowy interfejs dostępu do partycji pamięci tylko do odczytu (ROM) urządzenia.
Obsługiwane operacje to:
vfs.rom_ioctl(1)– Zwraca liczbę dostępnych partycji ROM.vfs.rom_ioctl(2, id)– Zwraca partycję ROM o indeksie id jako obiektmemoryview. Pamięć można odczytywać, ale nie można jej bezpośrednio zapisywać.vfs.rom_ioctl(3, id, length)– Przygotowuje partycję ROM do zapisu. Kasuje pierwsze length bajtów partycji o indeksie id. Zwraca minimalny rozmiar zapisu w bajtach (wyrównanie wymagane dla kolejnych zapisów).vfs.rom_ioctl(4, id, offset, buf)– Zapisuje buf (obiekt typu bytes) do partycji ROM o indeksie id pod bajtem offset.vfs.rom_ioctl(5, id)– Kończy sekwencję zapisu do partycji id (wykonuje wszelkie operacje finalizujące potrzebne po zapisie, takie jak opróżnienie pamięci podręcznej).
Operacje te są używane wewnętrznie przez
mpremotedo wdrażania obrazów ROMFS. Większość użytkowników nie musi bezpośrednio wywoływaćvfs.rom_ioctl().Przykład (odpytywanie dostępnych partycji):
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")
Automatyczne montowanie przy uruchomieniu¶
Gdy wsparcie dla ROMFS jest włączone w oprogramowaniu układowym, MicroPython podczas inicjalizacji automatycznie spróbuje zamontować pierwszą partycję ROM w /rom. Jeśli partycja zawiera prawidłowy obraz ROMFS, jest on montowany, a zarówno /rom, jak i /rom/lib są automatycznie dodawane do sys.path.
Oznacza to, że po wdrożeniu obrazu ROMFS za pomocą mpremote wystarczy miękki reset, aby nowe moduły stały się dostępne do importu.
Jeśli w partycji nie zostanie znaleziony prawidłowy obraz ROMFS (np. na świeżo zaprogramowanej płytce), montowanie jest po cichu pomijane.
Zarządzanie ROMFS za pomocą mpremote¶
Narzędzie mpremote udostępnia trzy podpolecenia do zarządzania obrazami ROMFS na podłączonym urządzeniu.
romfs query¶
$ mpremote romfs query
Wyświetla wszystkie dostępne partycje ROMFS na urządzeniu wraz z ich rozmiarami. Pokazuje również pierwsze 12 bajtów każdej partycji w postaci szesnastkowej i informuje, czy obecny jest prawidłowy obraz ROMFS.
Przykładowe wyjście:
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>
Buduje obraz ROMFS z katalogu source na komputerze hosta. Obraz jest zapisywany do output (domyślnie: <source>.romfs).
Opcje:
-o <output>,--output <output>: Określa ścieżkę pliku wyjściowego.-m,--mpy(domyślnie): Automatycznie kompiluje pliki.pydo.mpyza pomocąmpy_crossprzed dodaniem ich do obrazu. Wymaga pakietu Pythonmpy_cross(pip install mpy_cross).--no-mpy: Wyłącza automatyczną kompilację plików.py.
Przykład:
$ 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>
Wdraża obraz ROMFS na urządzeniu. source może być jednym z:
Katalog na hoście: obraz ROMFS jest budowany w pamięci i wdrażany bezpośrednio.
Plik
.romfslub.img: obraz jest odczytywany z dysku i wdrażany.
Opcje:
-p <partition>,--partition <partition>: Określa indeks partycji docelowej (domyślnie:0).-m,--mpy(domyślnie): Kompiluje.pydo.mpy, gdy source jest katalogiem.--no-mpy: Wyłącza automatyczną kompilację plików.py.
Po wdrożeniu urządzenie musi zostać poddane miękkiemu resetowi, aby nowy ROMFS został zamontowany w /rom.
Przykład:
$ 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
Przykłady¶
Wdrażanie prostej aplikacji¶
Załóżmy, że masz katalog projektu myapp/ o następującej strukturze:
myapp/
main.py
utils.py
lib/
helper.py
Aby wdrożyć go do ROMFS urządzenia:
$ mpremote romfs deploy myapp/
Po miękkim resecie moduły można importować z ROMFS:
import main
import utils
from lib import helper
Wyświetlanie zawartości ROMFS z poziomu Pythona¶
Po zamontowaniu zawartość ROMFS można przeglądać tak jak każdy inny system plików:
import os
for entry in os.ilistdir('/rom'):
print(entry)
# Or simply:
print(os.listdir('/rom'))
OpenMV dostarcza również niewielkie narzędzie pomocnicze romfs, które wyświetla sformatowaną listę zawierającą adres mapowany do pamięci oraz wyrównanie każdego pliku:
from omv import romfs
romfs.ls_romfs()
Zagnieżdżanie ROMFS w ROMFS¶
Obraz ROMFS przechowywany jako plik wewnątrz zewnętrznego ROMFS można zamontować jako zagnieżdżony system plików. Na przykład, jeśli istnieje /rom/inner.romfs. Ponieważ /rom jest systemem ROMFS, obiekty plików otwierane z niego obsługują protokół buforów, dzięki czemu można uzyskać bezpośrednio memoryview bez kopiowania:
import vfs
with open('/rom/inner.romfs', 'rb') as f:
inner = vfs.VfsRom(memoryview(f))
vfs.mount(inner, '/inner')
print(os.listdir('/inner'))
Format obrazu ROMFS¶
Format obrazu ROMFS to zwarty format binarny zaprojektowany do dostępu mapowanego do pamięci na mikrokontrolerach. Krótki przegląd:
Obraz zaczyna się od magicznych bajtów
0xd2 0xcd 0x31(zakodowanych jako"RM1"z ustawionymi najstarszymi bitami dwóch pierwszych bajtów).Pozostała część obrazu składa się z rekordów, z których każdy zawiera znacznik typu (varuint), długość (varuint) oraz ładunek.
Typy rekordów obejmują: wypełnienie, dane dosłowne, wskaźnik pośredni do danych, katalog, plik.
Nazwy katalogów i plików są przechowywane jako łańcuchy bajtów z prefiksem długości.
Dane pliku mogą być przechowywane dosłownie (w treści) lub poprzez wskaźnik pośredni do innego miejsca w obrazie, co umożliwia wyrównanie na potrzeby dostępu mapowanego do pamięci.
Nieznane typy rekordów są po cichu pomijane, co zapewnia zgodność w przód.
Format ten jest zdefiniowany w extmod/vfs_rom.c w źródłach MicroPython. Implementacja w Pythonie używana przez mpremote do budowania obrazów znajduje się w tools/mpremote/mpremote/romfs.py.
Zobacz także
Praca z systemami plików – Przegląd VFS w MicroPython oraz dostępnych typów systemów plików.
Pliki manifestu MicroPython – Jak zamrażać moduły Pythona w oprogramowaniu układowym.
Pliki .mpy w MicroPython – Format pliku binarnego .mpy w MicroPython.
Zdalne sterowanie MicroPython: mpremote – Pełny opis poleceń mpremote.
romfs – Narzędzie pomocnicze OpenMV do inspekcji zamontowanego systemu plików /rom.