OpenMV AE3

OpenMV AE3 は Alif Ensemble E3(デュアル ARM Cortex‑M55 SoC、400 MHz HP コア + 160 MHz HE コア)を中心に構成されており、2 基のオンチップ NPU(400 MHz / 204 GOPS の HP NPU + 160 MHz / 46 GOPS の HE NPU)を搭載しています。本ボードは NPU に加えて PAG7936 1 MP グローバルシャッターセンサー、USB‑C ハイスピード、Wi‑Fi、Bluetooth 5.1、LSM6DSM IMU、マイク、8×8 の VL53L8CX Time‑of‑Flight 測距センサーを、わずか 30 × 30 mm のボードに収めています。

OpenMV AE3

完全なデータシート、写真、寸法については OpenMV AE3 製品ページ を参照してください。

主な特長

  • Alif Ensemble E3 — Helium 128 ビット SIMD を備えたデュアル ARM Cortex‑M55、400 MHz HP コア + 160 MHz HE コア(約 640 / 約 256 DMIPS、CoreMark 1748 / 752)。

  • デュアル NPU: AI/ML 向けの 400 MHz / 204 GOPS HP NPU + 160 MHz / 46 GOPS HE NPU — 他のワークロードと並行して YOLO 物体検出を実行できます。

  • スケーリング用のハードウェア 2D GPU

  • 13.5 MB 内蔵 SRAM に加え、5.5 MB オンチップ MRAM32 MB 外部オクタルフラッシュ(100 MHz 8 ビット DDR、200 MB/s リード)。

  • オンチップ RTC を備えた 4 KB バックアップ RAM

  • PAG7936 1 MP カラーグローバルシャッターセンサー。

  • オンボード IMU(LSM6DSM 加速度計 + ジャイロスコープ)、マイクVL53L8CX 8×8 Time‑of‑Flight センサー(最大 4 m)。

  • EMI フィルタリングと TVS 保護を備えた ハイスピード USB‑C(480 Mb/s)、Wi‑Fi a/b/g/n + Bluetooth 5.1(チップアンテナまたは U.FL オプション)。

  • 10 本のユーザー I/O ピン — サイドヘッダー上の P0–P3、Qwiic コネクタ上の P4–P5、背面の B2B ヘッダー 上の P6–P9。デバッグおよびリカバリ用のラインも B2B ヘッダーに引き出されています。

  • 全ピンは 3.3 V 出力 / 3.3 V トレラント、1 ピンあたり 25 mA、割り込み対応。ADC 入力は 1.8 V 基準です。

  • ユーザー RGB LED、ユーザーボタン、リカバリスイッチ、Qwiic コネクタ。

  • 3.3 V で 80 µA のディープスリープ(アイドル時 24 mA、アクティブ時 50–60 mA)。

警告

AE3 の I/O ピンは 5 V トレラントではありません。Arduino Mega のような 5 V MCU にデバイスを直接接続しないでください — 5 V 信号にはレベルシフタを使用してください。

ピン配置

OpenMV AE3 PAG7936 ピン配置

ピンリファレンス

AE3 はサイドヘッダーに 10 本のユーザーピン(P0–P9)を備えています。JTAG やリカバリラインを含む追加の信号は、シールドやキャリアボード用にボード 背面の B2B(board‑to‑board)ヘッダー に引き出されています。

ピン名

基準

機能

P0

3.3 V

SPI0 MOSI / I2C2 SCL / UART4 TX / TIM0 T1 / PDM D3

P1

3.3 V

SPI0 MISO / I2C2 SDA / UART4 RX / TIM0 T0

P2

3.3 V

SPI0 SCLK / LPI2C SDA / UART5 TX / TIM1 T1

P3

3.3 V

SPI0 SS / LPI2C SCL / UART5 RX / TIM1 T0 / PDM C3

P4

3.3 V

I2C1 SCL / UART1 TX / TIM2 T1 / PDM C0 / CAN TX

P5

3.3 V

I2C1 SDA / UART1 RX / TIM2 T0 / PDM D0 / CAN RX

P6

1.8 V

I2C1 SDA / UART3 CTS / TIM9 T0 (B2B only)

P7

1.8 V

I2C1 SCL / UART3 RTS / TIM9 T1 (B2B only)

P8

1.8 V

I3C SDA / UART3 RX / TIM5 T0 / ADC ch S10 (B2B only)

P9

1.8 V

I3C SCL / UART3 TX / TIM5 T1 / ADC ch S11 (B2B only)

P10

1.8 V

GPIO / JTAG TCK (B2B only)

P11

1.8 V

GPIO / JTAG TDO (B2B only)

P13

1.8 V

GPIO / JTAG TMS (B2B only)

P14

1.8 V

GPIO / JTAG TDI (B2B only)

RESET

3.3 V

GND に引き下げるとボードがリセットされます

SW

3.3 V

ユーザーボタン(アクティブロー)

LED_RED

3.3 V

RGB LED の赤チャンネル(アクティブロー)

LED_GREEN

3.3 V

RGB LED の緑チャンネル(アクティブロー)

LED_BLUE

3.3 V

RGB LED の青チャンネル(アクティブロー)

注釈

P0–P5 はサイドヘッダー上にあり(3.3 V 基準)、P6–P9 はボード背面の B2B ヘッダーにのみ引き出されており 1.8 V 基準です。 1.8 V 基準のピンに 3.3 V を加えると SoC が破損します — B2B ヘッダーに接続する信号はすべて 1.8 V であることを確認してください。

電源ピン

  • 3.3V — AE3 のメイン電源レール。同じ 3.3 V レールは GPIO ヘッダーのはんだパッド、Qwiic コネクタ、ボード背面の B2B ヘッダー に引き出されています。

  • 1.8VB2B ヘッダー出力専用 として引き出されています。B2B キャリア上の 1.8 V ロジックのペリフェラルへの給電に使用してください。ボード外部からこのピンを駆動しないでください。

  • GND — 共通グランド。

AE3 には VIN ピンも LiPo チャージャーもありません。次の 3 つの経路のいずれかで給電できます:

  • USB‑C — オンボードのレギュレータが USB からの 5 V を 3.3 V に降圧し、それを 3.3 V レールに供給します。

  • Qwiic コネクタ — Qwiic ヘッダーに安定化された 3.3 V 電源を供給して、Qwiic モジュールからボードに給電します。

  • GPIO ヘッダー / B2B 3.3 V パッド — I/O ヘッダーまたは B2B コネクタ上の 3.3 V パッドのいずれかに安定化された 3.3 V 電源を供給します。

USB レギュレータは 理想ダイオード を通じてレールに給電するため、USB がまだ接続されている状態でも、Qwiic / GPIO / B2B 側の外部 3.3 V 電源で USB レギュレータに逆流することなくボードに給電できます。

Tip

バッテリー寿命推定ツール を使うと、指定したアクティブ / ディープスリープのデューティサイクルにおいて AE3 がバッテリーでどれだけ動作するかをモデル化できます。

リカバリおよびデバッグピン

  • RESET — GND に引き下げるとボードがリセットされます。解放すると SoC が通常どおり起動します。

ボードの 前面(カメラ側)の左下隅に リカバリスイッチ があります。有効にすると、AE3 の SE UART を USB 経由で強制的に出力し、OpenMV IDE がオンボードのブートローダーを再書き込みできるようにします。同じリカバリモードは、B2B コネクタ上の RECOVERY ピンを Low に引き下げることでリモートからトリガーすることもできます。

AE3 は SWD と完全な JTAG デバッグの両方をサポートします:

  • ボード側面の 1.8 V SWD ヘッダーTag-Connect ECV3-06-CTX ケーブル用で、4 本の SWD 信号(TCK / TMS / TDO / RSTN)と GND を引き出します。

  • ボード背面の B2B ヘッダー は同じデバッグピン(P10 = TCK、P11 = TDO、P13 = TMS、P14 = TDI)に加えて、システムの RSTN と独立した JTAG RSTN を引き出します。これらのピンは SWD(TCK + TMS)または完全な JTAG のいずれにも使用できます。JTAG RSTN ラインは完全 JTAG モードでのみ必要です。

すべてのデバッグ信号は 1.8 V 基準 です — 接続する前にデバッグアダプタが 1.8 V ロジック向けに設定されていることを確認してください。

オンボードペリフェラル

LED

AE3 には machine.LED を通じてソフトウェアで制御できるユーザー RGB LED が 1 つあります:

from machine import LED

LED("LED_RED").on()
LED("LED_GREEN").on()
LED("LED_BLUE").on()

ユーザーボタン

AE3 には 1 つのユーザーボタン(SW)があります:

from machine import Pin

sw = Pin("SW", Pin.IN)
print(sw.value())

ボードをディープスリープに入れて SW で復帰させるには、単に machine.deepsleep() を呼び出すだけです — ウェイクアップの設定は不要で、ボタンはウェイク入力に直接配線されています:

import machine

machine.deepsleep()   # press SW to wake the board

SW をソフト電源スイッチとして配線することもできます。立ち上がり エッジでトリガーしてください — ユーザーがボタンを離すとラインは High に落ち着くため、次の押下は明確にウェイクイベントとなります:

import machine
from machine import Pin

def power_off(_):
    machine.deepsleep()

Pin("SW", Pin.IN).irq(power_off, Pin.IRQ_RISING)

# ...rest of the application runs here. Press SW once to sleep,
# press it again to wake.

カメラセンサー

PAG7936 は csi --- カメラセンサー モジュールを通じて駆動されます:

import csi

cam = csi.CSI()
cam.reset()
cam.pixformat(csi.RGB565)
cam.framesize(csi.HD)         # 1280×800
cam.snapshot(time=2000)       # let auto‑exposure settle

while True:
    img = cam.snapshot()

PAG7936 はトリガーモードをサポートしています — フリーランのフレームクロックではなく、ピクセルの積分が各 csi.CSI.snapshot 呼び出しに正確に合わせられるため、外部イベントや別のセンサーへの取り込み同期に役立ちます。csi.CSI.ioctlcsi.IOCTL_SET_TRIGGERED_MODE を使って有効にします。読み出しが次のフレームの積分とパイプライン処理されなくなるため、フレームレートはフリーランモードのおよそ半分に低下します:

cam.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True)

NPU

AE3 の 2 基のオンチップ NPU(400 MHz / 204 GOPS HP NPU + 160 MHz / 46 GOPS HE NPU)は ml --- 機械学習 モジュールを通じて公開されています。読み取り専用の /rom ファイルシステムに保存されたモデルは、RAM へコピーすることなくフラッシュから直接ロードされるため、大きな検出器でもライブのフレームバッファと並んで余裕を持って収まります。すべてのフレームで YOLOv8 検出器を実行し、ライブ画像の上に予測結果を描画します:

import csi
import time
import ml
from ml.postprocessing.ultralytics import YoloV8

# Initialize the sensor.
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)

# Load YOLO V8 model from ROM FS.
model = ml.Model("/rom/yolov8n_192.tflite", postprocess=YoloV8(threshold=0.4))
print(model)

# Visualization parameters.
n = len(model.labels)
model_class_colors = [
    (int(255 * i // n), int(255 * (n - i - 1) // n), 255)
    for i in range(n)
]

clock = time.clock()
while True:
    clock.tick()
    img = csi0.snapshot()

    # boxes is a list of list per class of ((x, y, w, h), score) tuples
    boxes = model.predict([img])

    # Draw bounding boxes around the detected objects
    for i, class_detections in enumerate(boxes):
        rects = [r for r, score in class_detections]
        labels = [model.labels[i] for j in range(len(rects))]
        colors = [model_class_colors[i] for j in range(len(rects))]
        ml.utils.draw_predictions(img, rects, labels, colors, format=None)

    print(clock.fps(), "fps")

HE コア

AE3 は 2 つの Cortex‑M55 コアを 1 つの MCU にパッケージしています: メインの MicroPython インスタンス、カメラ、HP NPU、USB などを実行する 高性能(HP)コア と、はるかに低い電力で動作し、独自の小さな MicroPython インスタンスを起動する 高効率(HE)コア です。両コアは Open-AMP / RPMsg メッセージバスを共有しているため、HP コアは Python 関数を HE コアにディスパッチして結果を受け取り、両者を疎結合に保つことができます。

最もシンプルな入口は @openamp.async_remote デコレータです。これは Python 関数をマーシャリングして HE コアに送り、HE コアがそれを asyncio タスクとして実行します。タスクを登録したら、HE ファームウェアのフラッシュアドレスを指定して openamp.RemoteProc をインスタンス化し、rproc.start() を呼び出して 2 つ目のコアを起動します。コールバックを指定しない場合、デコレートされた関数の print() 出力はデフォルトのエンドポイント経由で HP コアの標準出力に転送されます — 「hello world」に便利です:

import time
import openamp

@openamp.async_remote
async def task1(ept):
    import asyncio
    while True:
        print("Hello from the HE core!")
        await asyncio.sleep(1)

# Boot the HE core. This runs the registered tasks.
rproc = openamp.RemoteProc(0x80320000)
rproc.start()

while True:
    print("Hello from the HP core!")
    time.sleep(1)

双方向のメッセージングには、デコレータにコールバックを渡します。コールバックは、HE タスクが ept.send() を呼び出すたびに HP コア上で実行されます:

import time
import openamp

def task_callback(src_addr, data):
    print("HP received:", data.decode())

@openamp.async_remote(task_callback)
async def task1(ept):
    import asyncio
    count = 0
    while True:
        ept.send(f"count = {count}")
        count += 1
        await asyncio.sleep(1)

rproc = openamp.RemoteProc(0x80320000)
rproc.start()

while True:
    time.sleep(1)

HE コアには独自の HE NPU(160 MHz、46 GOPS)があるため、HP コアの HP NPU が処理しているものと並行して 2 つ目の ML モデルを実行できます。有用な分割方法は、小さな常時オンのトリガー / 分類モデルを HE 側に置き、何か興味深いものがフラグされたときだけ HP コアが反応するようにすることです — オンボードマイクからのキーワードスポッティングは、連続的で低帯域幅であり、HE コアが HP よりはるかに低電力に保たれるため、適しています。frozen の ml.apps.MicroSpeech ヘルパーは標準で「Yes」と「No」を認識します — オンボードマイクに向かって大きくはっきりと単語を発声すると検出がトリガーされます:

import time
import openamp

def task_callback(src_addr, data):
    print("Heard:", data.decode())

@openamp.async_remote(task_callback)
async def task1(ept):
    from ml.apps import MicroSpeech
    speech = MicroSpeech(gain_db=24)
    while True:
        label, scores = speech.listen(timeout=0, threshold=0.70)
        if label:
            ept.send(label)

rproc = openamp.RemoteProc(0x80320000)
rproc.start()

while True:
    time.sleep(1)

さらに高度な分割では、HE コアがバックグラウンドでキーワードスポッティングを処理する一方で、HP NPU 上で BlazeFace を実行します — HP ループは最後に聞き取ったキーワードをカメラフレームにオーバーレイします:

import csi
import time
import openamp
import ml
from ml.postprocessing.mediapipe import BlazeFace

label = None
label_ticks = 0
LABEL_HOLD_MS = 2000

def task_callback(src_addr, data):
    global label, label_ticks
    label = data.decode()
    label_ticks = time.ticks_ms()

@openamp.async_remote(task_callback)
async def task1(ept):
    from ml.apps import MicroSpeech
    speech = MicroSpeech(gain_db=24)
    while True:
        l, scores = speech.listen(timeout=0, threshold=0.70)
        if l:
            ept.send(l)

# Start the HE core before initializing the camera on the HP core.
rproc = openamp.RemoteProc(0x80320000)
rproc.start()

csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)
csi0.window((400, 400))

model = ml.Model("/rom/blazeface_front_128.tflite",
                 postprocess=BlazeFace(threshold=0.4))

clock = time.clock()
while True:
    clock.tick()
    img = csi0.snapshot()
    for r, score, keypoints in model.predict([img]):
        ml.utils.draw_predictions(img, [r], ("face",),
                                  ((0, 0, 255),), format=None)
        ml.utils.draw_keypoints(img, keypoints, color=(255, 0, 0))
    if label is not None:
        if time.ticks_diff(time.ticks_ms(), label_ticks) < LABEL_HOLD_MS:
            img.draw_string((4, 4), f"Heard: {label}",
                            color=(255, 0, 0), scale=2)
        else:
            label = None
    print(clock.fps(), "fps")

HE コアは、HP 側でカメラ/NPU パイプラインと競合させたくない常時オンまたは低レートのワークロード — 小規模な ML 推論、マイクや IMU データの軽量な DSP、そして同様のバックグラウンドジョブ — に適しています。

留意すべきいくつかの制約:

  • HE コアからペリフェラルを駆動する場合は、マイクと IMU に限定してください — これらが HE 側で想定されているものです。各ペリフェラルは一度に 1 つのコアのみが所有できるため、HP か HE のどちらかを選び、スクリプトの実行期間中はそれを維持してください。

  • @openamp.async_remote タスクの本体は、500 バイト未満の mpy バイトコードにマーシャリングされる必要があります — 関数を小さく保ち、重いロジックはファームウェアに frozen される別のライブラリモジュールに分けてください。

  • ディスパッチされた関数内の import は、HE コアのファイルシステム上に存在するモジュールのみを参照します。HE コアは HP コアの /rom とは別個の独自の /rom ROMFS を持っているため、HE で利用したいモジュールや ML モデルは、HP 側ではなく HE 側の ROMFS イメージに焼き込む必要があります。

マイク

オンボードマイクは audio --- オーディオモジュール を通じて取り込まれます。各バッファは符号付き 16 ビット PCM の bytearray として到着するため、簡単な DSP のために ulab/numpy へ供給するのが容易です。RMS ボリュームがしきい値を超えるたびに表示する、シンプルな音量検出器です:

import audio
from ulab import numpy as np

def loudness(pcmbuf):
    samples = np.array(np.frombuffer(pcmbuf, dtype=np.int16), dtype=np.float)
    rms = np.sqrt(np.mean(samples ** 2))
    if rms > 10000:
        print("Loud!", int(rms))

audio.init(channels=1, frequency=16000, gain_db=24)
audio.start_streaming(loudness)

while True:
    pass

IMU

オンボードの LSM6DSM 加速度計 + ジャイロスコープは imu --- imu センサー を通じて公開されています:

import imu
import time

while True:
    print(imu.acceleration_mg())   # (x, y, z) in milli‑g
    print(imu.angular_rate_mdps()) # (x, y, z) in milli‑deg/s
    time.sleep_ms(100)

Time‑of‑Flight センサー

AE3 は VL53L8CX 8×8 マルチゾーン Time‑of‑Flight センサー を搭載しており、1 フレームあたり最大 64 個の距離測定値を返し、最大測距範囲は約 4 m です。これは tof --- 飛行時間(ToF)センサードライバ モジュールを通じて公開されています — tof.init() を呼び出してセンサーを起動し、tof.read_depth() を呼び出して深度フレームをミリメートル単位の測定値(ゾーンごとに 1 つ)のフラットなリストとして取得します:

import tof

tof.init()
while True:
    depth, depth_min, depth_max = tof.read_depth()
    print("min:", depth_min, "mm  max:", depth_max, "mm")

深度配列はメインセンサーからのカラーフレームの上に描画することもできます — tof.draw_depth() は既存の image.Image の上にそれを描画し、tof.snapshot() は新しくレンダリングされた深度画像を返します:

import image
import tof
import csi

# Bring up the VL53L8CX time-of-flight sensor.
tof.init()

# Configure the main camera at VGA RGB565.
cam = csi.CSI()
cam.reset()
cam.pixformat(csi.RGB565)
cam.framesize(csi.VGA)

# Off-screen framebuffer used to compose the camera frame and the
# up-scaled depth heat-map side by side before pushing the result
# back to the live preview.
b = image.Image(640, 480, image.RGB565)

while True:
    # Grab a colour frame from the main camera.
    img = cam.snapshot()

    try:
        # Capture TOF data [depth map, min distance, max distance].
        # vflip / hmirror align the ToF orientation with the camera.
        depth, dmin, dmax = tof.read_depth(vflip=True, hmirror=True)

        # Zones with no return read back as 0.0 — clamp them to the
        # frame's max distance so the colour palette doesn't show
        # them as "closest".
        for i in range(0, len(depth)):
            if depth[i] == 0.0:
                depth[i] = dmax

    except RuntimeError:
        # The sensor occasionally faults on a frame; reset and skip.
        tof.reset()
        continue

    # Draw the camera frame into the left half of the framebuffer,
    # scaled to 60% so it leaves room for the depth heat-map on
    # the right.
    b.draw_image(img, x=0, y=64+8, x_scale=0.6, hint=image.BILINEAR)

    # Up-sample the 8x8 depth array 30x with bicubic smoothing and
    # blend it into the right half using the depth palette.
    # scale=(0, 400) maps 0-400 mm to the full palette range.
    tof.draw_depth(b, depth, x=320+64+16, y=64+8, alpha=255,
                   hint=image.BICUBIC, x_scale=30, y_scale=30,
                   scale=(0, 400), color_palette=image.PALETTE_DEPTH)

    # Copy the composed framebuffer back into the live preview so
    # OpenMV IDE shows both panels.
    img.set(b)

Wi‑Fi

オンボードの CYW43439 は network --- ネットワーク構成 を通じてステーションインターフェースとして公開されています。接続後、ipconfig("addr4")(ip, netmask) のペアを返します:

import network, time

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("ssid", "password")
while not wlan.isconnected():
    time.sleep(1)
print("Wi‑Fi IP:", wlan.ipconfig("addr4")[0])

Bluetooth

同じ CYW43439 は Bluetooth 5.1 も公開します。asyncio 対応の BLE には aioble --- 非同期 BLE を使用します — 例えば、ペリフェラルとしてアドバタイズし、セントラルの接続を待ちます:

import asyncio
import aioble

async def run():
    while True:
        conn = await aioble.advertise(250_000, name="OpenMV-AE3")
        print("Connected:", conn.device)
        await conn.disconnected()

asyncio.run(run())

バスリファレンス

GPIO

machine.Pin を使用して、シルク印刷されたピンのいずれかを読み取りまたは駆動します。出力は 3.3 V CMOS で、1 ピンあたり最大 25 mA をシンク/ソースできます。

from machine import Pin

out = Pin("P0", Pin.OUT)
out.on()
out.off()
out.value(1)

inp = Pin("P1", Pin.IN, Pin.PULL_UP)
print(inp.value())

任意の入力ピンは、エッジ遷移で割り込みを発生させることもできます:

def handler(pin):
    print("triggered:", pin)

Pin("P1", Pin.IN, Pin.PULL_UP).irq(
    handler, Pin.IRQ_FALLING | Pin.IRQ_RISING,
)

UART

バス

TX

RX

RTS

CTS

UART1

P4

P5

UART3

P9

P8

P7

P6

UART4

P0

P1

UART5

P2

P3

from machine import UART

uart = UART(1, baudrate=115200)
uart.write("hello")
uart.read(5)

UART3 はハードウェアフロー制御を備えた唯一のバスです。P6–P9 は B2B ヘッダー上にあり 1.8 V 基準であるため、UART3 はレベルシフタまたは B2B キャリアを介してのみ動作します — 3.3 V ロジックを直接接続しないでください。

I²C

バス

SCL

SDA

I2C1

P4

P5

I2C2

P0

P1

LPI2C

P3

P2

from machine import I2C

i2c = I2C(1, freq=400_000)
i2c.scan()
i2c.writeto(0x76, b"hi")

オンボードの Qwiic コネクタは I2C23.3 V で引き出します。

I2C1I2C2 は、machine.I2CTarget を通じてターゲット(スレーブ)モードで使用し、メモリ領域を別の I²C コントローラに公開することもできます:

from machine import I2CTarget

buf = bytearray(32)
target = I2CTarget(1, addr=0x42, mem=buf)

注釈

LPI2C ペリフェラルはファームウェアでは公開されていません。公開されたとしても ターゲット(スレーブ)モード のみをサポートし、I2C1I2C2 がすでにコントローラとターゲットの両方の動作をカバーしています。

SPI

バス

MOSI

MISO

SCK

CS

SPI0

P0

P1

P2

P3

from machine import SPI
from machine import Pin

spi = SPI(0, baudrate=10_000_000)
cs = Pin("P3", Pin.OUT, value=1)   # CS is not driven by the SPI peripheral

cs.value(0)
spi.write(b"hello")
cs.value(1)

ADC

Alif Ensemble E3 は P8P9(B2B ヘッダーのみ)に 2 つの 12 ビット ADC チャンネルを公開しています。どちらの入力も 1.8 V 基準です — read_u16 はピンの 0–1.8 V にわたって 0–65535 を返します:

from machine import ADC
import time

adc = ADC("P8")
while True:
    voltage = adc.read_u16() * 1.8 / 65535
    print(voltage)
    time.sleep_ms(100)

警告

AE3 の ADC 入力は 3.3 V ではなく 1.8 V 基準 です。生の 3.3 V 信号をそのまま入力するとコンバータが飽和し、ピンを破損する可能性があります — より高い電圧は外部で分圧してください。

PWM

ピン

タイマー / チャンネル

P0

TIM0 T1

P1

TIM0 T0

P2

TIM1 T1

P3

TIM1 T0

P4

TIM2 T1

P5

TIM2 T0

P6

TIM9 T0 (B2B only)

P7

TIM9 T1 (B2B only)

P8

TIM5 T0 (B2B only)

P9

TIM5 T1 (B2B only)

いずれも machine.PWM を通じて駆動します:

from machine import Pin, PWM

pwm = PWM(Pin("P0"), freq=1_000, duty_u16=32768)

ソフトウェアによるビットバンギングバス

追加のバスが必要な場合、machine.SoftI2Cmachine.SoftSPI は任意の GPIO で動作します。

サーマルセンサー(オフボード)

ファームウェアには、外部配線された AMG8833 8 × 8 サーマルイメージャー用の fir --- 熱センサードライバー(fir == 遠赤外線) ドライバが含まれています。下記の I²C バスにモジュールを接続し、fir.init() + fir.snapshot() でフレームを読み取ります:

import time
import image
import fir

fir.init()                          # auto‑detects the sensor
clock = time.clock()

while True:
    clock.tick()
    try:
        img = fir.snapshot(x_scale=5, y_scale=5,
                           color_palette=image.PALETTE_IRONBOW,
                           hint=image.BICUBIC,
                           copy_to_fb=True)
    except OSError:
        continue
    print(clock.fps())

fir ドライバは I²C 1 経由でのみセンサーと通信します — モジュールを P4(SCL)と P5(SDA)に配線してください。

タイミング

time

time モジュールは、ブロッキング遅延、モノトニックティック、経過時間の測定をカバーします:

import time

time.sleep(1)              # seconds
time.sleep_ms(500)
time.sleep_us(10)

start = time.ticks_ms()
# ...do work...
elapsed = time.ticks_diff(time.ticks_ms(), start)

仮想タイマー

machine.Timer は、ハードウェアタイマースロットを消費せずに周期的またはワンショットのコールバックをスケジュールします。仮想(ソフトウェア)タイマーを使用するには、id として -1 を渡します:

from machine import Timer

one_shot = Timer(-1)
one_shot.init(period=5_000, mode=Timer.ONE_SHOT,
              callback=lambda t: print("once"))

periodic = Timer(-1)
periodic.init(period=2_000, mode=Timer.PERIODIC,
              callback=lambda t: print("tick"))

周期の値はミリ秒単位です。deinit() を呼び出して停止し、スロットを解放します。

リアルタイムクロック

machine.RTC は、ディープスリープを生き延びる 4 KB のオンチップバックアップ RAM に支えられ、リセットをまたいで実時間を保持します:

from machine import RTC

rtc = RTC()
rtc.datetime((2026, 4, 30, 4, 12, 0, 0, 0))   # Y, M, D, weekday, h, m, s, subsec
print(rtc.datetime())

RTC はディープスリープ中も動作するため、machine.deepsleep() のウェイクアップソースとして使用できます。

起動とランタイム情報

USB ブートローダーウィンドウ

電源投入のたびに、カメラは短いブートローダー(数秒)を実行し、ユーザーが DFU モードに入らなくても OpenMV IDE がファームウェアを更新できるようにします。ウィンドウが終了すると、ブートローダーは boot.py に、続いて main.py に制御を引き渡します。

実行中のスクリプトは、machine.bootloader() を呼び出すことで、オンデマンドでブートローダーに再び入ることができます:

import machine

machine.bootloader()

ファイルシステムと起動順序

AE3 ファームウェアは起動時に最大 2 つのファイルシステムをマウントします:

  • 内蔵フラッシュ — 常に /flash にマウントされます。デフォルトで main.pyREADME.txt を保持し、ごく最初の起動時に作成されます。

  • ROMFS/rom にある読み取り専用のメモリマップドファイルシステムで、ゼロコピーアクセスの恩恵を受ける大きなデータアセット(AI モデルなど)を出荷するために使用されます。ユーザーの Python が実行される前に、起動時に MicroPython によって自動的にマウントされます。

マウント後、作業ディレクトリは /flash に設定されます。インタプリタはそのディレクトリからスクリプトを実行します:

  • boot.pyすべての ソフトリセット時(コールドブート、REPL からの Ctrl‑D、または実行中のスクリプトが戻ったとき)に実行されます。

  • main.pyコールドブート時のみboot.py の直後に実行されます。その後のソフトリセットでは boot.py は再実行されますが、そのまま REPL に落ちます — main.py を再実行するにはボードを完全にリセットする必要があります。

新しく書き込まれたボードに同梱されるデフォルトの main.py は、ハートビートとしてユーザー RGB LED の チャンネルを点滅させるだけです(2 回の短いパルス、短い間隔)。これにより、ホストを接続しなくてもファームウェアが正常に起動したことを確認できます。

sys.path は両方のファイルシステムとそれぞれの lib/ サブディレクトリを含むよう拡張されるため、インポート可能なモジュールは /flash/lib または /rom/lib に置けます。

USB 経由で接続すると、/flash はホスト上で USB マスストレージドライブとしても列挙され、boot.pymain.py、その他のファイルを直接編集できます。カメラをリセットする前にドライブを取り出して ホストがキャッシュした書き込みをフラッシュさせてください。

注釈

OS はドライブを受動的なブロックデバイスとして扱うため、OpenMV Cam 上で実行されているコードによって作成または変更されたファイルは、ホストがドライブを再マウントするまで表示されません。OS と OpenMV Cam が同時に同じファイルシステムに書き込むと、OS が優先され、カメラが行った変更は上書きされます。

注釈

ホストが USB マスストレージドライブから読み取りまたは書き込みを行っている間、ユーザー RGB LED の チャンネルが一時的に点灯することがあります — これはファームウェアによるアクティビティインジケータであり、障害ではありません。

ストレージサイズ

AE3 には以下が同梱されています:

  • /flash8 MB の FAT ファイルシステム、読み書き可能。

  • HP コア上の /rom — HP コアが起動時にロードするスクリプトやデータ用の 24 MB 読み取り専用メモリマップド ROMFS。

  • HE コア上の /rom — HE コアが所有する 1 MB の読み取り専用 ROMFS。@openamp.async_remote タスクで利用したいモジュールや ML モデルは、HP 側ではなくこのイメージに焼き込む必要があります。

ハードフォルトインジケータ

ユーザー RGB LED がすべての色を高速に切り替えている場合 — 個別の色合いというより きらめく白色 LED のように見えるほど速い場合 — ファームウェアは回復不能なハードフォルトに陥っています。回復するにはファームウェアを再書き込みしてください。再書き込みしても改善しない場合、ボードが物理的に損傷している可能性があります。

ソフトウェアライブラリ

モジュールの完全な一覧 — AE3 ビルド固有のものを含む — については ライブラリインデックス を参照してください。