使用 ROMFS¶
概觀¶
ROMFS(唯讀記憶體檔案系統,Read-Only Memory Filesystem)是專為 MicroPython 裝置設計的輕量級唯讀檔案系統。它針對微控制器與嵌入式系統進行最佳化,這類系統需要將程式碼與資料儲存於快閃記憶體中,並能在不複製到 RAM 的情況下有效率地存取。
ROMFS 的主要優點包括:
零複製匯入:儲存於 ROMFS 中的
.mpy位元組碼檔案可直接從快閃記憶體(記憶體對映)執行,而無需先複製到 RAM 中。這與 凍結模組 的運作方式類似,但不需要重新燒錄整個韌體。低 RAM 負擔:從 ROMFS 載入的
.mpy檔案中的常數物件(字串、位元組等)會直接從快閃記憶體參考,而不會在 RAM 中重複佔用。彈性部署:ROMFS 映像可在主機 PC 上建置,並透過 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 專屬的輔助工具,可檢視掛載於 /rom 的 ROMFS。
工作流程¶
使用 ROMFS 的典型工作流程如下:
在你的 PC 上建立一個目錄,放入你想部署的 Python 檔案(或
.mpy檔案)。使用
mpremote romfs deploy <directory>來建置 ROMFS 映像並部署到裝置。ROMFS 會在下次開機時掛載於
/rom(若重新啟動裝置,也可立即掛載)。接著裝置上的 Python 程式碼便可像從其他任何檔案系統一樣,從 ROMFS
import模組。
例如:
# On the host PC, with a directory "myapp/" containing app.py:
$ mpremote romfs deploy myapp/
經過軟重置後,裝置上即可匯入 /rom/app.py(若已安裝 mpy_cross,則為 /rom/app.mpy)。
如需 mpremote 子指令的完整細節,請參閱下方的 mpremote romfs 子指令 章節。
Python API¶
ROMFS 的 Python API 透過 vfs 模組提供。
- class vfs.VfsRom(buffer)
從 buffer 建立一個 ROMFS 檔案系統物件,該物件必須是支援緩衝區協定(buffer protocol)的物件(例如
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)
傳回 path 的類
os.stat10 元組。若該路徑不存在,則引發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)-- 以memoryview物件傳回索引為 id 的 ROM 分割區。該記憶體可讀取,但無法直接寫入。vfs.rom_ioctl(3, id, length)-- 準備一個 ROM 分割區供寫入。會抹除索引為 id 的分割區的前 length 個位元組。傳回最小寫入大小(位元組),即後續寫入所需的對齊值。vfs.rom_ioctl(4, id, offset, buf)-- 將 buf(類位元組物件)寫入索引為 id 的 ROM 分割區,位於位元組 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。
這表示在使用 mpremote 部署 ROMFS 映像之後,只需軟重置即可讓新模組可供匯入。
若在分割區中找不到有效的 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>
從主機 PC 上的目錄 source 建置 ROMFS 映像。映像會寫入 output(預設:<source>.romfs)。
選項:
-o <output>、--output <output>:指定輸出檔案路徑。-m、--mpy(預設):在將.py檔案加入映像之前,使用mpy_cross自動將其編譯為.mpy。需要mpy_crossPython 套件(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(預設):當 source 為目錄時,將.py編譯為.mpy。--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
從 Python 列出 ROMFS 內容¶
掛載後,便可像任何其他檔案系統一樣瀏覽 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",其中前兩個位元組的高位元已設定)開頭。映像的其餘部分由多個 記錄(records) 組成,每個記錄都包含一個類型標籤(varuint)、一個長度(varuint)以及一段酬載資料。
記錄類型包括:填補(padding)、原樣資料(verbatim data)、間接資料指標(indirect data pointer)、目錄(directory)、檔案(file)。
目錄與檔案名稱以長度前綴的位元組字串形式儲存。
檔案資料可原樣(內嵌)儲存,或透過指向映像中其他位置的間接指標儲存,後者可實現記憶體對映存取所需的對齊。
未知的記錄類型會被靜默略過,以提供向前相容性。
此格式定義於 MicroPython 原始碼的 extmod/vfs_rom.c 中。mpremote 用來建置映像的 Python 實作則位於 tools/mpremote/mpremote/romfs.py。
請參閱
使用檔案系統 -- MicroPython VFS 與可用檔案系統類型的概觀。
MicroPython manifest 檔案 -- 如何將 Python 模組凍結進韌體。
MicroPython .mpy 檔案 -- MicroPython .mpy 二進位檔案格式。
MicroPython 遠端控制:mpremote -- 完整的 mpremote 指令參考。
romfs -- 用於檢視掛載的 /rom 檔案系統的 OpenMV 輔助工具。