Utilisation de ROMFS

Vue d’ensemble

ROMFS (Read-Only Memory Filesystem) est un système de fichiers léger et en lecture seule conçu pour les appareils MicroPython. Il est optimisé pour les microcontrôleurs et les systèmes embarqués où le code et les données doivent être stockés en mémoire flash et accessibles efficacement sans être copiés en RAM.

Les principaux avantages de ROMFS sont les suivants :

  • Imports sans copie : les fichiers de bytecode .mpy stockés dans un ROMFS peuvent être exécutés directement depuis la mémoire flash (mappée en mémoire) plutôt que d’être d’abord copiés en RAM. Cela fonctionne de manière similaire aux modules figés, mais sans nécessiter de reflasher l’intégralité du micrologiciel.

  • Faible empreinte RAM : les objets constants (chaînes, octets, etc.) des fichiers .mpy chargés depuis ROMFS sont référencés directement depuis la mémoire flash, et non dupliqués en RAM.

  • Déploiement flexible : une image ROMFS peut être construite sur un PC hôte et déployée sur l’appareil à l’aide de mpremote, sans recompiler le micrologiciel.

  • Interface de système de fichiers standard : un ROMFS est monté dans le VFS et accessible via les opérations de fichiers Python habituelles (open, os.listdir, import, etc.).

ROMFS est complémentaire à la fois des systèmes de fichiers FAT/LittleFS en lecture-écriture (qui résident dans d’autres partitions flash) et des modules figés (qui sont compilés dans le micrologiciel lui-même).

Prise en charge par les cartes

ROMFS est activé dans le micrologiciel OpenMV sur chaque carte caméra disposant d’une partition ROMFS réservée dans son agencement flash. Sur ces cartes, la partition ROMFS est détectée automatiquement au démarrage et montée sur /rom ; /rom et /rom/lib sont tous deux ajoutés à sys.path afin que les modules qui y sont stockés puissent être importés directement.

Carte

Prise en charge de ROMFS

OpenMV Cam N6

Oui

OpenMV AE3

Oui

OpenMV Cam RT1062

Oui

OpenMV Cam Pure Thermal

Oui

OpenMV Cam M4 / M7 / H7 / H7 Plus

Oui

Arduino Giga

Oui

Arduino Portenta H7

Oui

Arduino Nicla Vision

Oui

Arduino Nano 33 BLE Sense

Non (pas de partition ROMFS)

Arduino Nano RP2040 Connect

Non (pas de partition ROMFS)

Consultez romfs pour un utilitaire spécifique à OpenMV qui inspecte le ROMFS monté sur /rom.

Flux de travail

Le flux de travail typique pour utiliser ROMFS est le suivant :

  1. Créez sur votre PC un répertoire contenant les fichiers Python (ou les fichiers .mpy) que vous souhaitez déployer.

  2. Utilisez mpremote romfs deploy <directory> pour construire et déployer l’image ROMFS sur l’appareil.

  3. Le ROMFS sera monté sur /rom au prochain démarrage (ou peut être monté immédiatement si l’appareil est redémarré).

  4. Le code Python sur l’appareil peut alors import des modules depuis le ROMFS exactement comme depuis n’importe quel autre système de fichiers.

Par exemple

# On the host PC, with a directory "myapp/" containing app.py:
$ mpremote romfs deploy myapp/

Après une réinitialisation logicielle, l’appareil disposera de /rom/app.py (ou /rom/app.mpy si mpy_cross est installé) prêt à être importé.

Consultez la section sous-commandes mpremote romfs ci-dessous pour tous les détails sur les sous-commandes mpremote.

API Python

L’API Python de ROMFS est fournie via le module vfs.

class vfs.VfsRom(buffer)

Crée un objet système de fichiers ROMFS à partir de buffer, qui doit être un objet prenant en charge le protocole de tampon (par exemple un objet bytes, bytearray ou memoryview) contenant une image ROMFS valide.

Le constructeur vérifie que buffer commence par les octets magiques de ROMFS (b"\xd2\xcd\x31"). Si le tampon est trop petit ou n’est pas un ROMFS valide, OSError(ENODEV) est levée.

Les objets créés par ce constructeur peuvent être montés à l’aide de vfs.mount().

Exemple

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')

Ou, pour monter une image ROMFS stockée dans un fichier

import vfs

with open('/flash/app.romfs', 'rb') as f:
    romfs_data = f.read()
fs = vfs.VfsRom(romfs_data)
vfs.mount(fs, '/rom2')

Les méthodes suivantes sont disponibles sur un objet VfsRom :

VfsRom.open(path, mode)

Ouvre un fichier depuis le ROMFS. Seuls les modes de lecture ('', 'r', 'rt', 'rb') sont pris en charge. Tenter d’ouvrir un fichier en écriture lèvera OSError(EROFS).

L’objet fichier renvoyé prend en charge read(), seek(), tell() et close(). Pour les fichiers binaires ouverts en mode lecture, l’objet renvoyé prend également en charge le protocole de tampon, de sorte qu’une memoryview des données du fichier peut être obtenue, qui référence directement la mémoire du ROMFS (sans copie).

VfsRom.ilistdir(path)

Renvoie un itérateur sur les entrées du répertoire path. Chaque entrée est un tuple (name, type, inode, size)type vaut 0x8000 pour un fichier ou 0x4000 pour un répertoire.

VfsRom.stat(path)

Renvoie un 10-tuple de type os.stat pour path. Lève OSError(ENOENT) si le chemin n’existe pas.

VfsRom.statvfs(path)

Renvoie les statistiques du système de fichiers. La taille de bloc est rapportée comme étant 1 et le nombre de blocs représente la taille totale de l’image ROMFS en octets. Les blocs libres et les fichiers libres valent toujours 0 (système de fichiers en lecture seule).

VfsRom.chdir(path)

Change de répertoire au sein du ROMFS. Seule la racine ('/') est prise en charge ; changer vers un sous-répertoire quelconque lève OSError(EOPNOTSUPP).

VfsRom.getcwd()

Renvoie le répertoire de travail courant au sein du ROMFS. Renvoie toujours '/'.

vfs.rom_ioctl(op, ...)

Interface bas niveau pour accéder à la ou aux partitions de mémoire morte (ROM) en lecture seule de l’appareil.

Les opérations prises en charge sont les suivantes :

  • vfs.rom_ioctl(1) – Renvoie le nombre de partitions ROM disponibles.

  • vfs.rom_ioctl(2, id) – Renvoie la partition ROM d’indice id sous forme d’objet memoryview. La mémoire peut être lue mais pas écrite directement.

  • vfs.rom_ioctl(3, id, length) – Prépare une partition ROM pour l’écriture. Efface les length premiers octets de la partition d’indice id. Renvoie la taille d’écriture minimale en octets (l’alignement requis pour les écritures ultérieures).

  • vfs.rom_ioctl(4, id, offset, buf) – Écrit buf (un objet de type bytes) dans la partition ROM d’indice id à l’octet offset.

  • vfs.rom_ioctl(5, id) – Termine une séquence d’écriture sur la partition id (effectue toute finalisation nécessaire après l’écriture, comme le vidage du cache).

Ces opérations sont utilisées en interne par mpremote pour déployer des images ROMFS. La plupart des utilisateurs n’ont pas besoin d’appeler vfs.rom_ioctl() directement.

Exemple (interrogation des partitions disponibles)

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")

Montage automatique au démarrage

Lorsque la prise en charge de ROMFS est activée dans le micrologiciel, MicroPython tentera automatiquement de monter la première partition ROM sur /rom lors de l’initialisation. Si la partition contient une image ROMFS valide, elle est montée et /rom ainsi que /rom/lib sont ajoutés automatiquement à sys.path.

Cela signifie qu’après le déploiement d’une image ROMFS avec mpremote, une réinitialisation logicielle suffit pour rendre les nouveaux modules importables.

Si aucune image ROMFS valide n’est trouvée dans la partition (par exemple sur une carte fraîchement programmée), le montage est silencieusement ignoré.

Utilisation de mpremote pour gérer ROMFS

L’outil mpremote fournit trois sous-commandes pour gérer les images ROMFS sur un appareil connecté.

romfs query

$ mpremote romfs query

Liste toutes les partitions ROMFS disponibles sur l’appareil ainsi que leurs tailles. Affiche également les 12 premiers octets de chaque partition en hexadécimal et indique si une image ROMFS valide est présente.

Exemple de sortie

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>

Construit une image ROMFS à partir du répertoire source sur le PC hôte. L’image est écrite dans output (par défaut : <source>.romfs).

Options :

  • -o <output>, --output <output> : spécifie le chemin du fichier de sortie.

  • -m, --mpy (par défaut) : compile automatiquement les fichiers .py en .mpy à l’aide de mpy_cross avant de les ajouter à l’image. Nécessite le paquet Python mpy_cross (pip install mpy_cross).

  • --no-mpy : désactive la compilation automatique des fichiers .py.

Exemple

$ 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>

Déploie une image ROMFS sur l’appareil. source peut être soit :

  • Un répertoire sur l’hôte : l’image ROMFS est construite en mémoire et déployée directement.

  • Un fichier .romfs ou .img : l’image est lue depuis le disque et déployée.

Options :

  • -p <partition>, --partition <partition> : spécifie l’indice de la partition cible (par défaut : 0).

  • -m, --mpy (par défaut) : compile les fichiers .py en .mpy lorsque source est un répertoire.

  • --no-mpy : désactive la compilation automatique des fichiers .py.

Après le déploiement, l’appareil doit être réinitialisé en mode logiciel pour que le nouveau ROMFS soit monté sur /rom.

Exemple

$ 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

Exemples

Déploiement d’une application simple

Supposons que vous disposiez d’un répertoire de projet myapp/ ayant la structure suivante

myapp/
    main.py
    utils.py
    lib/
        helper.py

Pour le déployer sur le ROMFS de l’appareil

$ mpremote romfs deploy myapp/

Après une réinitialisation logicielle, les modules sont importables depuis le ROMFS

import main
import utils
from lib import helper

Lister le contenu d’un ROMFS depuis Python

Après le montage, le contenu du ROMFS peut être exploré comme n’importe quel autre système de fichiers

import os

for entry in os.ilistdir('/rom'):
    print(entry)

# Or simply:
print(os.listdir('/rom'))

OpenMV fournit également un petit utilitaire romfs qui affiche une liste formatée incluant l’adresse mappée en mémoire et l’alignement de chaque fichier

from omv import romfs
romfs.ls_romfs()

Imbrication d’un ROMFS dans un ROMFS

Une image ROMFS stockée sous forme de fichier dans un ROMFS externe peut être montée comme un système de fichiers imbriqué. Par exemple, si /rom/inner.romfs existe. Comme /rom est un ROMFS, les objets fichiers ouverts depuis celui-ci prennent en charge le protocole de tampon, de sorte qu’une memoryview sans copie peut être obtenue directement

import vfs

with open('/rom/inner.romfs', 'rb') as f:
    inner = vfs.VfsRom(memoryview(f))
vfs.mount(inner, '/inner')

print(os.listdir('/inner'))

Format d’image ROMFS

Le format d’image ROMFS est un format binaire compact conçu pour l’accès mappé en mémoire sur les microcontrôleurs. Aperçu rapide :

  • L’image commence par les octets magiques 0xd2 0xcd 0x31 (encodés sous la forme "RM1" avec les bits de poids fort des deux premiers octets positionnés).

  • Le reste de l’image est composé d”enregistrements, chacun comportant une étiquette de type (varuint), une longueur (varuint) et une charge utile.

  • Les types d’enregistrements comprennent : remplissage, données littérales, pointeur de données indirect, répertoire, fichier.

  • Les noms de répertoires et de fichiers sont stockés sous forme de chaînes d’octets préfixées par leur longueur.

  • Les données de fichier peuvent être stockées littéralement (en ligne) ou via un pointeur indirect vers un autre emplacement de l’image, ce qui permet l’alignement nécessaire à l’accès mappé en mémoire.

  • Les types d’enregistrements inconnus sont silencieusement ignorés, ce qui assure une compatibilité ascendante.

Ce format est défini dans extmod/vfs_rom.c dans les sources de MicroPython. L’implémentation Python utilisée par mpremote pour construire les images se trouve dans tools/mpremote/mpremote/romfs.py.

Voir aussi

Utilisation des systèmes de fichiers – Vue d’ensemble du VFS de MicroPython et des types de systèmes de fichiers disponibles.

Fichiers manifest de MicroPython – Comment figer des modules Python dans le micrologiciel.

Fichiers .mpy de MicroPython – Format de fichier binaire .mpy de MicroPython.

Contrôle à distance de MicroPython : mpremote – Référence complète des commandes mpremote.

romfs – Utilitaire OpenMV pour inspecter le système de fichiers /rom monté.