OpenMV AE3

OpenMV AE3 este construit în jurul Alif Ensemble E3 — un SoC dual ARM Cortex‑M55 (nucleu HP de 400 MHz + nucleu HE de 160 MHz) cu două NPU‑uri integrate (NPU HP de 400 MHz / 204 GOPS + NPU HE de 160 MHz / 46 GOPS). Placa asociază NPU‑urile cu senzorul global‑shutter PAG7936 de 1 MP, USB‑C high‑speed, Wi‑Fi, Bluetooth 5.1, un IMU LSM6DSM, un microfon și un telemetru time‑of‑flight VL53L8CX de 8×8, toate pe o placă de 30 × 30 mm.

OpenMV AE3

Pentru fișa tehnică completă, fotografii și dimensiuni, consultați pagina de produs OpenMV AE3.

Caracteristici principale

  • Alif Ensemble E3 — dual ARM Cortex‑M55 cu Helium SIMD pe 128 de biți, nucleu HP de 400 MHz + nucleu HE de 160 MHz (~640 / ~256 DMIPS, CoreMark 1748 / 752).

  • NPU‑uri duble: NPU HP de 400 MHz / 204 GOPS + NPU HE de 160 MHz / 46 GOPS pentru AI/ML — rulează detecția de obiecte YOLO în paralel cu alte sarcini.

  • GPU 2D hardware pentru scalare.

  • 13.5 MB SRAM intern plus 5.5 MB MRAM integrat și 32 MB memorie flash octală externă (100 MHz 8‑biți DDR, citire de 200 MB/s).

  • 4 KB RAM de rezervă cu RTC‑ul integrat.

  • Senzor global‑shutter color PAG7936 de 1 MP.

  • IMU integrat (accelerometru + giroscop LSM6DSM), microfon și senzor VL53L8CX time‑of‑flight 8×8 (până la 4 m).

  • USB‑C high‑speed (480 Mb/s) cu filtrare EMI și protecție TVS, Wi‑Fi a/b/g/n + Bluetooth 5.1 (antenă pe cip sau opțiune U.FL).

  • 10 pini I/O de utilizator — P0–P3 pe headerele laterale, P4–P5 pe conectorul Qwiic și P6–P9 pe headerul B2B de pe spate. La headerul B2B sunt rutate și linii suplimentare de depanare și recuperare.

  • Toți pinii ieșire 3.3 V / tolerant 3.3 V, 25 mA per pin, capabili de întreruperi. Intrările ADC sunt referențiate la 1.8 V.

  • LED RGB de utilizator, buton de utilizator, comutator de recuperare, conector Qwiic.

  • 80 µA în deep sleep la 3.3 V (24 mA în repaus, 50–60 mA activ).

Atenționare

Pinii I/O ai AE3 nu sunt toleranți la 5 V. Nu conectați dispozitivul direct la un MCU de 5 V precum Arduino Mega — folosiți un convertor de nivel pentru orice semnal de 5 V.

Pinout

Pinout OpenMV AE3 PAG7936

Referință pini

AE3 expune 10 pini de utilizator pe headerele laterale (P0–P9). Semnale suplimentare — inclusiv JTAG și linia de recuperare — sunt rutate către un header B2B (board‑to‑board) de pe spatele plăcii, pentru shield‑uri și plăci purtătoare.

Nume pin

Referință

Funcție

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

P7

1.8 V

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

P8

1.8 V

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

P9

1.8 V

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

P10

1.8 V

GPIO / JTAG TCK (doar B2B)

P11

1.8 V

GPIO / JTAG TDO (doar B2B)

P13

1.8 V

GPIO / JTAG TMS (doar B2B)

P14

1.8 V

GPIO / JTAG TDI (doar B2B)

RESET

3.3 V

conectați la GND pentru a reseta placa

SW

3.3 V

buton de utilizator (activ pe nivel jos)

LED_RED

3.3 V

canalul roșu al LED‑ului RGB (activ pe nivel jos)

LED_GREEN

3.3 V

canalul verde al LED‑ului RGB (activ pe nivel jos)

LED_BLUE

3.3 V

canalul albastru al LED‑ului RGB (activ pe nivel jos)

Notă

P0–P5 se află pe headerele laterale (referențiați la 3.3 V); P6–P9 sunt expuși doar pe headerul B2B de pe spatele plăcii și sunt referențiați la 1.8 V. Aplicarea a 3.3 V pe un pin referențiat la 1.8 V va deteriora SoC‑ul — asigurați‑vă că orice semnal conectat la headerul B2B este la 1.8 V.

Pini de alimentare

  • 3.3V — magistrala principală de alimentare a AE3. Aceeași magistrală de 3.3 V este expusă pe padurile de lipit ale headerului GPIO, pe conectorul Qwiic și pe headerul B2B de pe spatele plăcii.

  • 1.8V — expus pe headerul B2B doar ca ieșire. Folosiți‑l pentru a alimenta periferice cu logică de 1.8 V pe o placă purtătoare B2B; nu îl alimentați din exteriorul plăcii.

  • GND — masă comună.

AE3 nu are pin VIN și nici încărcător LiPo. Poate fi alimentat pe oricare dintre cele trei căi:

  • USB‑C — regulatorul de pe placă coboară cei 5 V de la USB la 3.3 V și îi injectează pe magistrala de 3.3 V.

  • Conectorul Qwiic — aplicați o sursă reglată de 3.3 V pe headerul Qwiic pentru a alimenta placa de la un modul Qwiic.

  • Padurile de 3.3 V de pe headerul GPIO / B2B — aplicați o sursă reglată de 3.3 V pe oricare dintre padurile de 3.3 V de pe headerul I/O sau pe conectorul B2B.

Regulatorul USB alimentează magistrala printr‑o diodă ideală, astfel încât sursele externe de 3.3 V de pe partea Qwiic / GPIO / B2B pot alimenta placa chiar și atunci când USB este încă conectat, fără a alimenta înapoi regulatorul USB.

Sfat

Folosiți estimatorul duratei de viață a bateriei pentru a modela cât timp va funcționa AE3 pe baterie pentru un anumit ciclu de funcționare activ / deep-sleep.

Pini de recuperare și depanare

  • RESET — conectați la GND pentru a reseta placa. Eliberarea lui permite SoC‑ului să pornească normal.

Există un comutator de recuperare pe fața frontală (dinspre cameră) a plăcii, în colțul din stânga jos. Când este activat, forțează ieșirea UART‑ului SE al AE3 prin USB, astfel încât OpenMV IDE să poată reprograma bootloader‑ul de pe placă. Același mod de recuperare poate fi declanșat de la distanță prin coborârea pinului RECOVERY de pe conectorul B2B.

AE3 acceptă depanarea atât prin SWD, cât și prin JTAG complet:

  • Headerul SWD de 1.8 V de pe lateralul plăcii este pentru un cablu Tag-Connect ECV3-06-CTX și scoate la iveală cele patru semnale SWD (TCK / TMS / TDO / RSTN) plus GND.

  • Headerul B2B de pe spatele plăcii expune aceiași pini de depanare (P10 = TCK, P11 = TDO, P13 = TMS, P14 = TDI) plus RSTN-ul de sistem și un JTAG RSTN separat. Acești pini pot fi folosiți fie pentru SWD (TCK + TMS), fie pentru JTAG complet; linia JTAG RSTN este necesară doar în modul JTAG complet.

Toate semnalele de depanare sunt referențiate la 1.8 V — asigurați‑vă că adaptorul de depanare este configurat pentru logică de 1.8 V înainte de conectare.

Periferice de pe placă

LED‑uri

AE3 are un singur LED RGB de utilizator, controlabil din software prin machine.LED

from machine import LED

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

Buton de utilizator

AE3 are un singur buton de utilizator (SW):

from machine import Pin

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

Pentru a pune placa în deep sleep și a o trezi cu SW, apelați pur și simplu machine.deepsleep() — nu este necesară nicio configurare a trezirii, butonul este conectat direct la o intrare de trezire:

import machine

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

Puteți de asemenea conecta SW ca un comutator de pornire software. Declanșați pe frontul crescător — linia se stabilizează la nivel înalt după ce utilizatorul eliberează butonul, astfel încât următoarea apăsare este, fără ambiguitate, un eveniment de trezire:

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.

Senzorul camerei

PAG7936 este comandat prin modulul csi — senzori de cameră

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 acceptă modul declanșat (triggered) — integrarea pixelilor se aliniază exact cu fiecare apel csi.CSI.snapshot, în loc de ceasul de cadre liber, util pentru sincronizarea capturii cu un eveniment extern sau cu un alt senzor. Activați‑l prin csi.CSI.ioctl cu csi.IOCTL_SET_TRIGGERED_MODE. Rata de cadre scade la aproximativ jumătate față de modul liber, deoarece citirea nu se mai suprapune cu integrarea cadrului următor:

cam.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True)

NPU

Cele două NPU‑uri integrate ale AE3 (NPU HP de 400 MHz / 204 GOPS + NPU HE de 160 MHz / 46 GOPS) sunt expuse prin modulul ml — Învățare automată. Modelele stocate pe sistemul de fișiere /rom doar‑citire se încarcă direct din memoria flash fără a fi copiate în RAM, astfel încât chiar și detectoarele mari încap confortabil alături de buffer‑ul de cadre live. Rulați un detector YOLOv8 pe fiecare cadru și desenați predicțiile peste imaginea live:

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

Nucleul HE

AE3 împachetează două nuclee Cortex‑M55 într‑un singur MCU: nucleul de înaltă performanță (HP), care rulează instanța principală MicroPython, camera, NPU‑ul HP, USB‑ul și așa mai departe; și nucleul de înaltă eficiență (HE), care funcționează la un consum mult mai redus și pornește o instanță MicroPython mică proprie. Ambele nuclee partajează o magistrală de mesaje Open-AMP / RPMsg, astfel încât nucleul HP poate trimite funcții Python către nucleul HE, primi rezultatele înapoi și menține cele două jumătăți decuplate.

Cel mai simplu punct de intrare este decoratorul @openamp.async_remote. Acesta serializează o funcție Python, o trimite către nucleul HE, iar nucleul HE o rulează ca o sarcină asyncio. După înregistrarea sarcinilor, instanțiați openamp.RemoteProc cu adresa flash a firmware‑ului HE și apelați rproc.start() pentru a porni al doilea nucleu. Fără un callback, ieșirea print() a funcției decorate este redirecționată prin endpoint‑ul implicit către stdout‑ul nucleului HP — util pentru 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)

Pentru mesagerie bidirecțională, transmiteți un callback decoratorului. Callback‑ul rulează pe nucleul HP de fiecare dată când sarcina HE apelează 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)

Nucleul HE are propriul NPU HE (160 MHz, 46 GOPS), astfel încât poate rula un al doilea model ML în paralel cu orice rulează NPU‑ul HP al nucleului HP. O împărțire utilă este să plasați un model mic de declanșare / clasificare mereu activ pe partea HE și să lăsați nucleul HP să reacționeze doar atunci când este semnalat ceva interesant — detecția de cuvinte-cheie din microfonul de pe placă se potrivește bine, deoarece este continuă, cu lățime de bandă mică, iar nucleul HE rămâne la un consum mult mai redus decât HP. Asistentul înghețat ml.apps.MicroSpeech recunoaște „Yes” și „No” din start — rostiți cuvintele tare și clar în microfonul de pe placă pentru a declanșa detecția:

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)

Pentru o împărțire mai bogată, rulați BlazeFace pe NPU‑ul HP în timp ce nucleul HE se ocupă de detecția de cuvinte-cheie în fundal — bucla HP suprapune cel mai recent cuvânt‑cheie auzit peste cadrul camerei:

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

Nucleul HE este potrivit pentru sarcini mereu active sau cu rată redusă pe care nu doriți să concureze cu pipeline‑ul camerei/NPU de pe partea HP — inferență ML de mici dimensiuni, DSP ușor pe date de la microfon sau IMU și alte sarcini similare de fundal.

Câteva constrângeri de reținut:

  • Limitați‑vă la microfon și IMU atunci când comandați periferice de pe nucleul HE — acestea sunt cele pentru care a fost proiectată partea HE. Fiecare periferic poate fi deținut de un singur nucleu la un moment dat, așa că alegeți HP sau HE pentru el și păstrați alegerea pe toată durata scriptului.

  • Corpul fiecărei sarcini @openamp.async_remote trebuie să se serializeze în sub 500 de octeți de bytecode mpy — păstrați funcția mică și mutați logica mai grea în module de bibliotecă separate, care sunt înghețate în firmware.

  • Importurile din interiorul funcției trimise văd doar modulele care există pe sistemul de fișiere al nucleului HE. Nucleul HE are propriul ROMFS /rom — separat de /rom-ul nucleului HP — așa că modulele și modelele ML pe care doriți să le aveți disponibile pe HE trebuie incluse în imaginea ROMFS de pe partea HE, nu în cea HP.

Microfon

Microfonul de pe placă este capturat prin audio — Modulul Audio. Fiecare buffer sosește ca un bytearray PCM pe 16 biți cu semn, ceea ce face trivială alimentarea lui în ulab/numpy pentru DSP rapid. Un detector simplu de intensitate sonoră — afișează ori de câte ori volumul RMS depășește un prag:

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

Accelerometrul + giroscopul LSM6DSM de pe placă este expus prin imu — senzor 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)

Senzor time‑of‑flight

AE3 include un senzor time‑of‑flight multi‑zonă VL53L8CX 8×8 care returnează până la 64 de citiri de distanță per cadru, cu o rază maximă de ~4 m. Este expus prin modulul tof — driver pentru senzor time-of-flight — apelați tof.init() pentru a porni senzorul și tof.read_depth() pentru a obține un cadru de adâncime sub forma unei liste plate de citiri în milimetri (una per zonă):

import tof

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

Tabloul de adâncime poate fi de asemenea desenat peste un cadru color de la senzorul principal — tof.draw_depth() îl aplică peste o image.Image existentă, în timp ce tof.snapshot() returnează o imagine de adâncime randată proaspăt:

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

Cipul CYW43439 de pe placă este expus prin network — configurarea rețelei ca interfață de tip stație. După conectare, ipconfig("addr4") returnează perechea (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

Același CYW43439 expune și Bluetooth 5.1. Folosiți aioble — BLE asincron pentru BLE prietenos cu asyncio — de exemplu, faceți reclamă (advertise) ca periferic și așteptați conectarea unui dispozitiv central:

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

Referință magistrale

GPIO

Folosiți machine.Pin pentru a citi sau comanda oricare dintre pinii inscripționați pe placă. Ieșirile sunt 3.3 V CMOS și pot absorbi/furniza până la 25 mA per pin.

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

Orice pin de intrare poate de asemenea declanșa o întrerupere la tranzițiile de front:

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

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

UART

Magistrală

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 este singura magistrală cu control hardware al fluxului. Deoarece P6–P9 se află pe headerul B2B și sunt referențiați la 1.8 V, UART3 funcționează doar printr‑un convertor de nivel sau o placă purtătoare B2B — nu conectați logică de 3.3 V direct la el.

I²C

Magistrală

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

Conectorul Qwiic de pe placă scoate la iveală I2C2 la 3.3 V.

I2C1 și I2C2 pot fi folosite și în mod target (slave) prin machine.I2CTarget pentru a expune o regiune de memorie unui alt controler I²C:

from machine import I2CTarget

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

Notă

Perifericul LPI2C nu este expus în firmware. Dacă ar fi expus, ar accepta doar modul target (slave), iar I2C1 și I2C2 acoperă deja atât funcționarea ca controler, cât și ca target.

SPI

Magistrală

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 expune două canale ADC pe 12 biți pe P8 și P9 (doar headerul B2B). Ambele intrări sunt referențiate la 1.8 Vread_u16 returnează 0–65535 pe intervalul 0–1.8 V la pin:

from machine import ADC
import time

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

Atenționare

Intrările ADC ale AE3 sunt referențiate la 1.8 V, nu la 3.3 V. Aplicarea unui semnal brut de 3.3 V va satura convertorul și poate deteriora pinul — divizați extern tensiunile mai mari.

PWM

Pin

Temporizator / canal

P0

TIM0 T1

P1

TIM0 T0

P2

TIM1 T1

P3

TIM1 T0

P4

TIM2 T1

P5

TIM2 T0

P6

TIM9 T0 (doar B2B)

P7

TIM9 T1 (doar B2B)

P8

TIM5 T0 (doar B2B)

P9

TIM5 T1 (doar B2B)

Comandați‑le pe oricare dintre ele prin machine.PWM

from machine import Pin, PWM

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

Magistrale software bit‑banged

machine.SoftI2C și machine.SoftSPI funcționează pe orice GPIO dacă aveți nevoie de o magistrală suplimentară.

Senzor termic (extern)

Firmware‑ul include driverul fir — driver pentru senzori termici (fir == far infrared) pentru un imager termic AMG8833 8 × 8 cablat extern. Conectați modulul la magistrala I²C listată mai jos, apoi citiți cadre cu 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())

Driverul fir comunică cu senzorul doar prin I²C 1 — cablați modulul la P4 (SCL) și P5 (SDA).

Sincronizare

time

Modulul time acoperă întârzieri blocante, ticuri monotone și măsurarea timpului scurs:

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)

Temporizatoare virtuale

machine.Timer programează callback‑uri periodice sau unice fără a consuma un slot de temporizator hardware. Transmiteți -1 ca id pentru a folosi un temporizator virtual (software):

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

Valorile perioadei sunt în milisecunde. Apelați deinit() pentru a opri și elibera slotul.

Ceas în timp real

machine.RTC păstrează ora calendaristică între resetări, susținut de 4 KB de RAM de rezervă integrat care supraviețuiește modului deep sleep:

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‑ul funcționează și pe durata modului deep sleep, așa că îl puteți folosi ca sursă de trezire pentru machine.deepsleep().

Informații despre boot și execuție

Fereastra bootloader‑ului USB

La fiecare pornire, camera rulează un bootloader scurt (câteva secunde) care permite OpenMV IDE să actualizeze firmware‑ul fără ca utilizatorul să fie nevoit să intre în modul DFU. După expirarea ferestrei, bootloader‑ul predă controlul către boot.py și apoi main.py.

Un script în execuție poate reintra în bootloader la cerere apelând machine.bootloader()

import machine

machine.bootloader()

Sistem de fișiere și ordinea de boot

Firmware‑ul AE3 montează până la două sisteme de fișiere la pornire:

  • Memorie flash internă — întotdeauna montată la /flash. Conține main.py și README.txt în mod implicit; creată la prima pornire.

  • ROMFS — sistem de fișiere doar‑citire, mapat în memorie la /rom, folosit pentru a livra resurse de date mari (de ex. modele AI) care beneficiază de acces fără copiere. Montat automat de MicroPython la pornire, înainte de rularea oricărui cod Python al utilizatorului.

După montare, directorul de lucru este setat la /flash. Interpretorul rulează apoi scripturile din acel director:

  • boot.py este executat la fiecare resetare software (pornire la rece, Ctrl‑D din REPL sau ori de câte ori scriptul în execuție se încheie).

  • main.py este executat doar la pornirea la rece, imediat după boot.py. Resetările software ulterioare rerulează boot.py, dar trec direct la REPL — pentru a rerula main.py trebuie să resetați complet placa.

main.py-ul implicit livrat pe o placă proaspăt programată doar clipește canalul albastru al LED‑ului RGB de utilizator ca puls de bază (două impulsuri scurte, pauză scurtă), astfel încât să puteți spune că firmware‑ul a pornit corect fără niciun host atașat.

sys.path este extins pentru a include ambele sisteme de fișiere și subdirectoarele lor lib/, astfel încât modulele importabile pot fi în /flash/lib sau /rom/lib.

Când este conectat prin USB, /flash se enumeră de asemenea ca unitate de stocare în masă USB pe host, permițându‑vă să editați direct boot.py, main.py și orice alte fișiere. Ejectați unitatea înainte de a reseta camera, pentru ca host‑ul să golească scrierile din cache.

Notă

Deoarece sistemul de operare tratează unitatea ca un dispozitiv bloc pasiv, fișierele create sau modificate de codul care rulează pe OpenMV Cam nu vor apărea până când host‑ul nu remontează unitatea. Dacă atât sistemul de operare, cât și OpenMV Cam scriu pe același sistem de fișiere în același timp, sistemul de operare va câștiga și va suprascrie modificările făcute de cameră.

Notă

Canalul roșu al LED‑ului RGB de utilizator se poate aprinde scurt în timp ce host‑ul citește de pe sau scrie pe unitatea de stocare în masă USB — acesta este un indicator de activitate generat de firmware, nu o defecțiune.

Dimensiuni de stocare

AE3 este livrat cu:

  • /flash — sistem de fișiere FAT de 8 MB, citire/scriere.

  • /rom pe nucleul HP — ROMFS doar‑citire mapat în memorie de 24 MB pentru scripturile și datele pe care nucleul HP le încarcă la pornire.

  • /rom pe nucleul HE — ROMFS doar‑citire de 1 MB deținut de nucleul HE. Modulele și modelele ML pe care doriți să le aveți disponibile pentru sarcinile @openamp.async_remote trebuie incluse în această imagine, nu în cea HP.

Indicator de hard‑fault

Dacă LED‑ul RGB de utilizator parcurge rapid toate culorile — suficient de rapid încât tinde să arate ca un LED alb licăritor mai degrabă decât nuanțe distincte — firmware‑ul a întâmpinat un hard fault nerecuperabil. Reprogramați firmware‑ul pentru a recupera; dacă reprogramarea nu ajută, placa poate fi deteriorată fizic.

Biblioteci software

Consultați indexul de biblioteci pentru lista completă de module — inclusiv care dintre ele sunt unice pentru build‑ul AE3.