OpenMV AE3

L’OpenMV AE3 est construit autour de l’Alif Ensemble E3 — un SoC double ARM Cortex‑M55 (cœur HP à 400 MHz + cœur HE à 160 MHz) avec deux NPU intégrés (NPU HP à 400 MHz / 204 GOPS + NPU HE à 160 MHz / 46 GOPS). La carte associe les NPU au capteur global‑shutter PAG7936 de 1 MP, à l’USB‑C haute vitesse, au Wi‑Fi, au Bluetooth 5.1, à une IMU LSM6DSM, à un microphone et à un télémètre time‑of‑flight VL53L8CX 8×8, le tout sur une carte de 30 × 30 mm.

OpenMV AE3

Pour la fiche technique complète, les photos et les dimensions, consultez la page produit de l’OpenMV AE3.

Points forts

  • Alif Ensemble E3 — double ARM Cortex‑M55 avec SIMD Helium 128 bits, cœur HP à 400 MHz + cœur HE à 160 MHz (~640 / ~256 DMIPS, CoreMark 1748 / 752).

  • Double NPU : NPU HP à 400 MHz / 204 GOPS + NPU HE à 160 MHz / 46 GOPS pour l’IA/ML — exécute la détection d’objets YOLO en parallèle d’autres charges de travail.

  • GPU 2D matériel pour la mise à l’échelle.

  • 13,5 Mo de SRAM interne plus 5,5 Mo de MRAM intégrée et 32 Mo de mémoire flash octale externe (DDR 8 bits à 100 MHz, lecture à 200 Mo/s).

  • 4 Ko de RAM de sauvegarde avec le RTC intégré.

  • Capteur PAG7936 couleur global‑shutter de 1 MP.

  • IMU embarquée (accéléromètre + gyroscope LSM6DSM), microphone et capteur time‑of‑flight VL53L8CX 8×8 (jusqu’à 4 m).

  • USB‑C haute vitesse (480 Mb/s) avec filtrage EMI et protection TVS, Wi‑Fi a/b/g/n + Bluetooth 5.1 (antenne sur puce ou option U.FL).

  • 10 broches d’E/S utilisateur — P0–P3 sur les connecteurs latéraux, P4–P5 sur le connecteur Qwiic, et P6–P9 sur le connecteur B2B à l’arrière. Des lignes de débogage et de récupération supplémentaires sont également routées vers le connecteur B2B.

  • Toutes les broches sont en sortie 3,3 V / tolérantes 3,3 V, 25 mA par broche, capables de générer des interruptions. Les entrées ADC sont référencées à 1,8 V.

  • LED RGB utilisateur, bouton utilisateur, interrupteur de récupération, connecteur Qwiic.

  • 80 µA en sommeil profond à 3,3 V (24 mA au repos, 50–60 mA en activité).

Avertissement

Les broches d’E/S de l’AE3 ne sont pas tolérantes au 5 V. Ne connectez pas l’appareil directement à un microcontrôleur 5 V comme l’Arduino Mega — utilisez un convertisseur de niveau pour tout signal 5 V.

Brochage

Brochage du PAG7936 de l'OpenMV AE3

Référence des broches

L’AE3 expose 10 broches utilisateur sur les connecteurs latéraux (P0–P9). Des signaux supplémentaires — y compris le JTAG et la ligne de récupération — sont routés vers un connecteur B2B (board‑to‑board) à l’arrière de la carte, destiné aux shields et cartes porteuses.

Nom de la broche

Référence

Fonction

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

P7

1,8 V

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

P8

1,8 V

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

P9

1,8 V

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

P10

1,8 V

GPIO / JTAG TCK (B2B uniquement)

P11

1,8 V

GPIO / JTAG TDO (B2B uniquement)

P13

1,8 V

GPIO / JTAG TMS (B2B uniquement)

P14

1,8 V

GPIO / JTAG TDI (B2B uniquement)

RESET

3,3 V

tirez vers GND pour réinitialiser la carte

SW

3,3 V

bouton utilisateur (actif à l’état bas)

LED_RED

3,3 V

canal rouge de la LED RGB (actif à l’état bas)

LED_GREEN

3,3 V

canal vert de la LED RGB (actif à l’état bas)

LED_BLUE

3,3 V

canal bleu de la LED RGB (actif à l’état bas)

Note

P0–P5 sont sur les connecteurs latéraux (référencées à 3,3 V) ; P6–P9 ne sont exposées que sur le connecteur B2B à l’arrière de la carte et sont référencées à 1,8 V. Appliquer 3,3 V sur une broche référencée à 1,8 V endommagera le SoC — assurez-vous que tout signal connecté au connecteur B2B est à 1,8 V.

Broches d’alimentation

  • 3.3V — le rail d’alimentation principal de l’AE3. Ce même rail 3,3 V est exposé sur les pastilles à souder du connecteur GPIO, sur le connecteur Qwiic et sur le connecteur B2B à l’arrière de la carte.

  • 1.8V — exposé sur le connecteur B2B en sortie uniquement. Utilisez-le pour alimenter des périphériques à logique 1,8 V sur une carte porteuse B2B ; ne l’alimentez pas depuis l’extérieur de la carte.

  • GND — masse commune.

L’AE3 ne possède ni broche VIN ni chargeur LiPo. Il peut être alimenté par l’une des trois voies suivantes :

  • USB‑C — le régulateur embarqué abaisse le 5 V de l’USB à 3,3 V et l’injecte sur le rail 3,3 V.

  • Connecteur Qwiic — appliquez une alimentation régulée de 3,3 V sur le connecteur Qwiic pour alimenter la carte depuis un module Qwiic.

  • Pastilles 3,3 V du connecteur GPIO / B2B — appliquez une alimentation régulée de 3,3 V sur l’une des pastilles 3,3 V du connecteur d’E/S ou du connecteur B2B.

Le régulateur USB alimente le rail via une diode idéale, de sorte que des alimentations externes de 3,3 V côté Qwiic / GPIO / B2B peuvent alimenter la carte même lorsque l’USB est toujours branché, sans refouler le régulateur USB.

Astuce

Utilisez l”estimateur d’autonomie de batterie pour estimer la durée de fonctionnement de l’AE3 sur batterie pour un cycle de service actif / sommeil profond donné.

Broches de récupération et de débogage

  • RESET — tirez vers GND pour réinitialiser la carte. Le relâchement permet au SoC de démarrer normalement.

Il y a un interrupteur de récupération sur la face avant (côté caméra) de la carte, dans le coin inférieur gauche. Lorsqu’il est activé, il force la sortie de l’UART SE de l’AE3 vers l’USB afin que l’OpenMV IDE puisse reprogrammer le programme d’amorçage embarqué. Le même mode de récupération peut être déclenché à distance en tirant la broche RECOVERY du connecteur B2B à l’état bas.

L’AE3 prend en charge le débogage SWD ainsi que le JTAG complet :

  • Le connecteur SWD 1,8 V sur le côté de la carte est destiné à un câble Tag-Connect ECV3-06-CTX et expose les quatre signaux SWD (TCK / TMS / TDO / RSTN) plus GND.

  • Le connecteur B2B à l’arrière de la carte expose les mêmes broches de débogage (P10 = TCK, P11 = TDO, P13 = TMS, P14 = TDI) plus le RSTN système et un JTAG RSTN distinct. Ces broches peuvent être utilisées soit pour le SWD (TCK + TMS), soit pour le JTAG complet ; la ligne JTAG RSTN n’est nécessaire qu’en mode JTAG complet.

Tous les signaux de débogage sont référencés à 1,8 V — assurez-vous que votre adaptateur de débogage est configuré pour une logique 1,8 V avant de le connecter.

Périphériques embarqués

LED

L’AE3 dispose d’une seule LED RGB utilisateur, contrôlable par logiciel via machine.LED

from machine import LED

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

Bouton utilisateur

L’AE3 dispose d’un seul bouton utilisateur (SW)

from machine import Pin

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

Pour mettre la carte en sommeil profond et la réveiller avec SW, appelez simplement machine.deepsleep() — aucune configuration de réveil n’est requise, le bouton est câblé directement sur une entrée de réveil

import machine

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

Vous pouvez aussi câbler SW comme interrupteur d’alimentation logiciel. Déclenchez sur le front montant — la ligne se stabilise à l’état haut une fois que l’utilisateur relâche le bouton, de sorte que la pression suivante constitue sans ambiguïté un événement de réveil

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.

Capteur de la caméra

Le PAG7936 est piloté via le module csi — capteurs de caméra

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

Le PAG7936 prend en charge le mode déclenché — l’intégration des pixels s’aligne exactement sur chaque appel csi.CSI.snapshot plutôt que sur l’horloge de trame en roue libre, ce qui est utile pour synchroniser la capture avec un événement externe ou un autre capteur. Activez-le via csi.CSI.ioctl avec csi.IOCTL_SET_TRIGGERED_MODE. La cadence d’images chute à environ la moitié de celle du mode en roue libre, car la lecture ne se chevauche plus avec l’intégration de la trame suivante

cam.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True)

NPU

Les deux NPU intégrés de l’AE3 (NPU HP à 400 MHz / 204 GOPS + NPU HE à 160 MHz / 46 GOPS) sont exposés via le module ml — Apprentissage automatique. Les modèles stockés sur le système de fichiers en lecture seule /rom se chargent directement depuis la mémoire flash sans copie en RAM, de sorte que même de gros détecteurs tiennent confortablement à côté du tampon d’image en direct. Exécutez un détecteur YOLOv8 sur chaque trame et dessinez les prédictions par-dessus l’image en direct

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

Cœur HE

L’AE3 regroupe deux cœurs Cortex‑M55 dans un seul MCU : le cœur haute performance (HP) qui exécute l’instance MicroPython principale, la caméra, le NPU HP, l’USB, etc. ; et le cœur haute efficacité (HE) qui fonctionne à une consommation bien moindre et démarre sa propre petite instance MicroPython. Les deux cœurs partagent un bus de messages Open-AMP / RPMsg, de sorte que le cœur HP peut envoyer des fonctions Python au cœur HE, récupérer les résultats et garder les deux moitiés découplées.

Le point d’entrée le plus simple est le décorateur @openamp.async_remote. Il sérialise une fonction Python, l’envoie au cœur HE, et le cœur HE l’exécute comme une tâche asyncio. Après avoir enregistré les tâches, instanciez openamp.RemoteProc avec l’adresse flash du micrologiciel HE et appelez rproc.start() pour démarrer le second cœur. Sans fonction de rappel, la sortie print() de la fonction décorée est transmise via le point de terminaison par défaut vers la stdout du cœur HP — pratique pour un « 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)

Pour une messagerie bidirectionnelle, passez une fonction de rappel au décorateur. La fonction de rappel s’exécute sur le cœur HP chaque fois que la tâche HE appelle ept.send()

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)

Le cœur HE possède son propre NPU HE (160 MHz, 46 GOPS), de sorte qu’il peut exécuter un second modèle ML en parallèle de ce dont le NPU HP du cœur HP est occupé. Une répartition utile consiste à placer un petit modèle de déclenchement / classification toujours actif côté HE et à ne laisser le cœur HP réagir que lorsque quelque chose d’intéressant est signalé — la détection de mots-clés depuis le microphone embarqué convient bien, car elle est continue, à faible bande passante, et le cœur HE reste à une consommation bien plus faible que le HP. L’assistant figé ml.apps.MicroSpeech reconnaît « Yes » et « No » d’emblée — prononcez les mots fort et clairement dans le micro embarqué pour déclencher la détection

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)

Pour une répartition plus riche, exécutez BlazeFace sur le NPU HP pendant que le cœur HE gère la détection de mots-clés en arrière-plan — la boucle HP superpose le dernier mot-clé entendu sur la trame de la caméra

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

Le cœur HE est bien adapté aux charges de travail toujours actives ou à faible cadence que vous ne voulez pas voir entrer en concurrence avec le pipeline caméra/NPU côté HP — petites inférences ML, traitement DSP léger sur les données du microphone ou de l’IMU, et autres tâches d’arrière-plan similaires.

Quelques contraintes à garder à l’esprit :

  • Tenez-vous-en au microphone et à l’IMU lorsque vous pilotez des périphériques depuis le cœur HE — ce sont ceux pour lesquels le côté HE est conçu. Chaque périphérique ne peut être détenu que par un seul cœur à la fois, alors choisissez HP ou HE pour celui-ci et conservez ce choix pendant toute la durée de vie du script.

  • Le corps de chaque tâche @openamp.async_remote doit se sérialiser en moins de 500 octets de bytecode mpy — gardez la fonction petite et déportez la logique plus lourde dans des modules de bibliothèque séparés, figés dans le micrologiciel.

  • Les imports à l’intérieur de la fonction envoyée ne voient que les modules présents sur le système de fichiers du cœur HE. Le cœur HE possède son propre ROMFS /rom — distinct du /rom du cœur HP — de sorte que les modules et les modèles ML que vous voulez rendre disponibles côté HE doivent être intégrés dans l’image ROMFS du côté HE, et non celle du HP.

Microphone

Le micro embarqué est capturé via audio — Module Audio. Chaque tampon arrive sous forme de bytearray PCM signé 16 bits, ce qui le rend trivial à alimenter dans ulab/numpy pour un traitement DSP rapide. Un simple détecteur de volume sonore — affiche un message chaque fois que le volume RMS dépasse un seuil

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

L’accéléromètre + gyroscope LSM6DSM embarqué est exposé via imu — capteur 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)

Capteur time‑of‑flight

L’AE3 embarque un capteur time‑of‑flight multi‑zones VL53L8CX 8×8 qui renvoie jusqu’à 64 mesures de distance par trame, avec une portée maximale d’environ 4 m. Il est exposé via le module tof — pilote de capteur temps de vol — appelez tof.init() pour démarrer le capteur et tof.read_depth() pour récupérer une trame de profondeur sous forme de liste plate de mesures en millimètres (une par zone)

import tof

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

Le tableau de profondeur peut aussi être dessiné par-dessus une trame couleur du capteur principal — tof.draw_depth() le peint sur une image.Image existante, tandis que tof.snapshot() renvoie une image de profondeur fraîchement rendue

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

Le CYW43439 embarqué est exposé via network — configuration réseau comme interface station. Après connexion, ipconfig("addr4") renvoie le couple (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

Le même CYW43439 expose également le Bluetooth 5.1. Utilisez aioble — BLE asynchrone pour du BLE compatible asyncio — par exemple, annoncer comme périphérique et attendre qu’un central se connecte

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

Référence des bus

GPIO

Utilisez machine.Pin pour lire ou piloter n’importe laquelle des broches sérigraphiées. Les sorties sont en CMOS 3,3 V et peuvent absorber/fournir jusqu’à 25 mA par broche.

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

Toute broche d’entrée peut également déclencher une interruption sur les transitions de front

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

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

UART

Bus

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 est le seul bus doté d’un contrôle de flux matériel. Comme P6–P9 se trouvent sur le connecteur B2B et sont référencées à 1,8 V, UART3 ne fonctionne qu’à travers un convertisseur de niveau ou une carte porteuse B2B — n’y connectez pas directement de logique 3,3 V.

I²C

Bus

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

Le connecteur Qwiic embarqué expose I2C2 en 3,3 V.

I2C1 et I2C2 peuvent aussi être utilisés en mode cible (esclave) via machine.I2CTarget pour exposer une région mémoire à un autre contrôleur I²C

from machine import I2CTarget

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

Note

Le périphérique LPI2C n’est pas exposé dans le micrologiciel. S’il l’était, il ne prendrait en charge que le mode cible (esclave), et I2C1 et I2C2 couvrent déjà les opérations en contrôleur comme en cible.

SPI

Bus

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

L’Alif Ensemble E3 expose deux canaux ADC 12 bits sur P8 et P9 (connecteur B2B uniquement). Les deux entrées sont référencées à 1,8 Vread_u16 renvoie 0–65535 sur la plage 0–1,8 V à la broche

from machine import ADC
import time

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

Avertissement

Les entrées ADC de l’AE3 sont référencées à 1,8 V, pas à 3,3 V. Appliquer un signal brut de 3,3 V saturera le convertisseur et pourra endommager la broche — divisez les tensions plus élevées en externe.

PWM

Broche

Minuteur / canal

P0

TIM0 T1

P1

TIM0 T0

P2

TIM1 T1

P3

TIM1 T0

P4

TIM2 T1

P5

TIM2 T0

P6

TIM9 T0 (B2B uniquement)

P7

TIM9 T1 (B2B uniquement)

P8

TIM5 T0 (B2B uniquement)

P9

TIM5 T1 (B2B uniquement)

Pilotez n’importe lequel d’entre eux via machine.PWM

from machine import Pin, PWM

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

Bus émulés par logiciel (bit‑bang)

machine.SoftI2C et machine.SoftSPI fonctionnent sur n’importe quel GPIO si vous avez besoin d’un bus supplémentaire.

Capteur thermique (externe)

Le micrologiciel inclut le pilote fir — pilote de capteur thermique (fir == infrarouge lointain) pour un imageur thermique AMG8833 8 × 8 câblé en externe. Connectez le module au bus I²C indiqué ci-dessous, puis lisez les trames avec 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())

Le pilote fir ne communique avec le capteur que via l”I²C 1 — câblez le module sur P4 (SCL) et P5 (SDA).

Temporisation

time

Le module time couvre les délais bloquants, les tics monotones et la mesure du temps écoulé

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)

Minuteurs virtuels

machine.Timer planifie des fonctions de rappel périodiques ou à déclenchement unique sans consommer d’emplacement de minuteur matériel. Passez -1 comme id pour utiliser un minuteur virtuel (logiciel)

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

Les valeurs de période sont en millisecondes. Appelez deinit() pour arrêter et libérer l’emplacement.

Horloge temps réel

machine.RTC conserve l’heure murale entre les réinitialisations, grâce à 4 Ko de RAM de sauvegarde intégrée qui survit au sommeil profond

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

Le RTC continue également de fonctionner pendant le sommeil profond, vous pouvez donc l’utiliser comme source de réveil pour machine.deepsleep().

Informations sur le démarrage et l’exécution

Fenêtre du programme d’amorçage USB

À chaque mise sous tension, la caméra exécute un court programme d’amorçage (quelques secondes) qui permet à l’OpenMV IDE de mettre à jour le micrologiciel sans que l’utilisateur ait à entrer en mode DFU. Une fois la fenêtre expirée, le programme d’amorçage passe la main à boot.py puis à main.py.

Un script en cours d’exécution peut réentrer dans le programme d’amorçage à la demande en appelant machine.bootloader()

import machine

machine.bootloader()

Système de fichiers et ordre de démarrage

Le micrologiciel de l’AE3 monte jusqu’à deux systèmes de fichiers au démarrage :

  • Mémoire flash interne — toujours montée sur /flash. Contient main.py et README.txt par défaut ; créée au tout premier démarrage.

  • ROMFS — système de fichiers en lecture seule, mappé en mémoire, sur /rom, utilisé pour embarquer de grandes ressources de données (par exemple des modèles d’IA) qui bénéficient d’un accès sans copie. Monté automatiquement par MicroPython au démarrage, avant l’exécution de tout code Python utilisateur.

Après le montage, le répertoire de travail est positionné sur /flash. L’interpréteur exécute ensuite les scripts depuis ce répertoire :

  • boot.py est exécuté à chaque réinitialisation logicielle (démarrage à froid, Ctrl‑D depuis le REPL, ou chaque fois que le script en cours se termine).

  • main.py est exécuté uniquement au démarrage à froid, immédiatement après boot.py. Les réinitialisations logicielles suivantes ré-exécutent boot.py mais passent directement au REPL — pour ré-exécuter main.py, vous devez réinitialiser complètement la carte.

Le main.py par défaut livré sur une carte fraîchement programmée fait simplement clignoter le canal bleu de la LED RGB utilisateur comme indicateur de vie (deux impulsions courtes, courte pause), afin que vous puissiez constater que le micrologiciel a démarré correctement sans aucun hôte connecté.

sys.path est étendu pour inclure les deux systèmes de fichiers et leurs sous-répertoires lib/, de sorte que les modules importables peuvent résider dans /flash/lib ou /rom/lib.

Lorsqu’elle est connectée en USB, /flash s’énumère également comme un lecteur de stockage de masse USB sur l’hôte, ce qui vous permet d’éditer directement boot.py, main.py et tous les autres fichiers. Éjectez le lecteur avant de réinitialiser la caméra afin que l’hôte vide ses écritures en cache.

Note

Comme le système d’exploitation traite le lecteur comme un périphérique de bloc passif, les fichiers créés ou modifiés par du code s’exécutant sur l’OpenMV Cam n’apparaîtront pas tant que l’hôte n’aura pas remonté le lecteur. Si le système d’exploitation et l’OpenMV Cam écrivent sur le même système de fichiers en même temps, le système d’exploitation l’emportera et écrasera les modifications faites par la caméra.

Note

Le canal rouge de la LED RGB utilisateur peut s’allumer brièvement pendant que l’hôte lit ou écrit sur le lecteur de stockage de masse USB — c’est un indicateur d’activité piloté par le micrologiciel, et non une panne.

Tailles de stockage

L’AE3 est livré avec :

  • /flash — système de fichiers FAT de 8 Mo, en lecture/écriture.

  • /rom sur le cœur HP — ROMFS mappé en mémoire, en lecture seule, de 24 Mo, pour les scripts et les données que le cœur HP charge au démarrage.

  • /rom sur le cœur HE — ROMFS de 1 Mo en lecture seule détenu par le cœur HE. Les modules et les modèles ML que vous voulez rendre disponibles aux tâches @openamp.async_remote doivent être intégrés dans cette image, et non celle du HP.

Indicateur de défaillance matérielle (hard fault)

Si la LED RGB utilisateur défile rapidement à travers toutes les couleurs — suffisamment vite pour qu’elle ait tendance à ressembler à une LED blanche scintillante plutôt qu’à des teintes distinctes — c’est que le micrologiciel a rencontré une défaillance matérielle irrécupérable. Reprogrammez le micrologiciel pour récupérer ; si la reprogrammation n’aide pas, la carte est peut-être physiquement endommagée.

Bibliothèques logicielles

Consultez l”index de la bibliothèque pour la liste complète des modules — y compris ceux qui sont propres à la version AE3.