OpenMV AE3¶
ה‑OpenMV AE3 בנוי סביב ה‑Alif Ensemble E3 — SoC כפול ARM Cortex‑M55 (ליבת HP בתדר 400 MHz + ליבת HE בתדר 160 MHz) עם שני NPU על השבב (HP NPU בתדר 400 MHz / 204 GOPS + HE NPU בתדר 160 MHz / 46 GOPS). הלוח משלב את ה‑NPU עם החיישן PAG7936 בגודל 1 MP עם global‑shutter, USB‑C במהירות גבוהה, Wi‑Fi, Bluetooth 5.1, IMU מסוג LSM6DSM, מיקרופון ומד טווח time‑of‑flight מסוג VL53L8CX בגודל 8×8, הכול על לוח בגודל 30 × 30 מ“מ.
לדף נתונים מלא, תמונות וממדים ראו את דף המוצר של OpenMV AE3.
עיקרי הדברים¶
Alif Ensemble E3 — כפול ARM Cortex‑M55 עם Helium SIMD ברוחב 128 ביט, ליבת HP בתדר 400 MHz + ליבת HE בתדר 160 MHz (כ‑640 / כ‑256 DMIPS, CoreMark 1748 / 752).
שני NPU: HP NPU בתדר 400 MHz / 204 GOPS + HE NPU בתדר 160 MHz / 46 GOPS עבור AI/ML — מריץ זיהוי עצמים מסוג YOLO לצד עומסי עבודה נוספים.
GPU דו‑ממדי חומרתי לשינוי קנה מידה.
13.5 MB של SRAM פנימי בתוספת 5.5 MB של MRAM על השבב ו‑32 MB של flash אוקטלי חיצוני (DDR 8‑ביט בתדר 100 MHz, קריאה ב‑200 MB/s).
4 KB של backup RAM עם ה‑RTC שעל השבב.
חיישן PAG7936 צבעוני בגודל 1 MP עם global‑shutter.
IMU מובנה (מד תאוצה + ג’ירוסקופ LSM6DSM), מיקרופון וחיישן VL53L8CX 8×8 time‑of‑flight (עד 4 מ«).
USB‑C במהירות גבוהה (480 Mb/s) עם סינון EMI והגנת TVS, Wi‑Fi a/b/g/n + Bluetooth 5.1 (אנטנת שבב או אפשרות U.FL).
10 פיני I/O למשתמש — P0–P3 על מחברי הצד, P4–P5 על מחבר ה‑Qwiic, ו‑P6–P9 על מחבר ה‑B2B שבגב. קווי ניפוי שגיאות ושחזור נוספים מנותבים גם הם אל מחבר ה‑B2B.
כל הפינים הם פלט 3.3 V / סובלני ל‑3.3 V, 25 mA לכל פין, בעלי יכולת פסיקה. כניסות ה‑ADC מתייחסות אל 1.8 V.
LED RGB למשתמש, כפתור משתמש, מתג שחזור, מחבר Qwiic.
שינה עמוקה ב‑80 µA בתדר 3.3 V (24 mA במצב סרק, 50–60 mA במצב פעיל).
אזהרה
פיני ה‑I/O של ה‑AE3 אינם סובלניים ל‑5 V. אל תחברו את ההתקן ישירות ל‑MCU של 5 V כמו ה‑Arduino Mega — השתמשו בממיר מתח (level shifter) לכל אות של 5 V.
מפת פינים¶
מדריך פינים¶
ה‑AE3 חושף 10 פיני משתמש על מחברי הצד (P0–P9). אותות נוספים — כולל JTAG וקו השחזור — מנותבים אל מחבר B2B (board‑to‑board) שבגב הלוח עבור shields ולוחות נושאים.
שם פין |
התייחסות |
פונקציה |
|---|---|---|
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 בלבד) |
P7 |
1.8 V |
I2C1 SCL / UART3 RTS / TIM9 T1 (B2B בלבד) |
P8 |
1.8 V |
I3C SDA / UART3 RX / TIM5 T0 / ADC ch S10 (B2B בלבד) |
P9 |
1.8 V |
I3C SCL / UART3 TX / TIM5 T1 / ADC ch S11 (B2B בלבד) |
P10 |
1.8 V |
GPIO / JTAG TCK (B2B בלבד) |
P11 |
1.8 V |
GPIO / JTAG TDO (B2B בלבד) |
P13 |
1.8 V |
GPIO / JTAG TMS (B2B בלבד) |
P14 |
1.8 V |
GPIO / JTAG TDI (B2B בלבד) |
RESET |
3.3 V |
משכו ל‑GND כדי לאפס את הלוח |
SW |
3.3 V |
כפתור משתמש (active low) |
LED_RED |
3.3 V |
ערוץ אדום של LED RGB (active low) |
LED_GREEN |
3.3 V |
ערוץ ירוק של LED RGB (active low) |
LED_BLUE |
3.3 V |
ערוץ כחול של LED RGB (active low) |
הערה
P0–P5 נמצאים על מחברי הצד (מתייחסים ל‑3.3 V); P6–P9 חשופים רק על מחבר ה‑B2B שבגב הלוח ומתייחסים ל‑1.8 V. הזרמת 3.3 V לתוך פין שמתייחס ל‑1.8 V תפגע ב‑SoC — ודאו שכל אות המחובר אל מחבר ה‑B2B נמצא ב‑1.8 V.
פיני מתח¶
3.3V — פס המתח הראשי של ה‑AE3. אותו פס 3.3 V חשוף על משטחי ההלחמה של מחבר ה‑GPIO, על מחבר ה‑Qwiic, ועל מחבר ה‑B2B שבגב הלוח.
1.8V — חשוף על מחבר ה‑B2B כ‑פלט בלבד. השתמשו בו כדי להזין התקנים היקפיים בלוגיקת 1.8 V על לוח נושא B2B; אל תזינו אותו מחוץ ללוח.
GND — הארקה משותפת.
ל‑AE3 אין פין VIN ואין מטען LiPo. ניתן להזין אותו דרך כל אחד משלושה נתיבים:
USB‑C — הרגולטור שעל הלוח מוריד את ה‑5 V מה‑USB ל‑3.3 V ומזריק אותם לפס ה‑3.3 V.
מחבר Qwiic — הזרימו אספקת 3.3 V מיוצבת לתוך מחבר ה‑Qwiic כדי להזין את הלוח ממודול Qwiic.
מחבר GPIO / משטחי 3.3 V של B2B — הזרימו אספקת 3.3 V מיוצבת לתוך כל אחד ממשטחי ה‑3.3 V שעל מחבר ה‑I/O או מחבר ה‑B2B.
רגולטור ה‑USB מזין את הפס דרך דיודה אידיאלית, כך שמקורות 3.3 V חיצוניים בצד ה‑Qwiic / GPIO / B2B יכולים להזין את הלוח גם כאשר ה‑USB עדיין מחובר, מבלי להזין לאחור את רגולטור ה‑USB.
טיפ
השתמשו במעריך אורך חיי הסוללה כדי לדמות כמה זמן ה‑AE3 יפעל על סוללה עבור מחזור עבודה נתון של פעילות / שינה עמוקה.
פיני שחזור וניפוי שגיאות¶
RESET — משכו ל‑GND כדי לאפס את הלוח. שחרורו מאפשר ל‑SoC להתחיל בפעולה רגילה.
ישנו מתג שחזור בפאה הקדמית (בצד המצלמה) של הלוח, בפינה השמאלית התחתונה. כשהוא מופעל, הוא מאלץ את ה‑SE UART של ה‑AE3 לצאת דרך ה‑USB כך ש‑OpenMV IDE יכול לבצע reflash ל‑bootloader שעל הלוח. ניתן להפעיל את אותו מצב שחזור מרחוק על ידי משיכת פין ה‑RECOVERY שעל מחבר ה‑B2B למצב נמוך.
ה‑AE3 תומך גם בניפוי שגיאות SWD וגם ב‑JTAG מלא:
מחבר ה‑SWD של 1.8 V שבצד הלוח מיועד לכבל Tag-Connect ECV3-06-CTX ומפצל את ארבעת אותות ה‑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 יש LED RGB יחיד למשתמש, הניתן לשליטה בתוכנה דרך machine.LED
from machine import LED
LED("LED_RED").on()
LED("LED_GREEN").on()
LED("LED_BLUE").on()
חיישן המצלמה¶
ה‑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 תומך במצב מופעל (triggered) — אינטגרציית הפיקסלים מסתנכרנת בדיוק עם כל קריאת csi.CSI.snapshot במקום עם שעון הפריימים הרץ באופן חופשי, דבר שימושי לסנכרון לכידה אל אירוע חיצוני או חיישן אחר. הפעילו אותו דרך csi.CSI.ioctl עם csi.IOCTL_SET_TRIGGERED_MODE. קצב הפריימים יורד לכמחצית ממצב הריצה החופשית מאחר שהקריאה כבר אינה מתבצעת בצנרת עם האינטגרציה של הפריים הבא:
cam.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True)
NPU¶
שני ה‑NPU שעל השבב של ה‑AE3 (HP NPU בתדר 400 MHz / 204 GOPS + HE NPU בתדר 160 MHz / 46 GOPS) חשופים דרך המודול ml — למידת מכונה. מודלים המאוחסנים במערכת הקבצים /rom לקריאה בלבד נטענים ישירות מה‑flash מבלי להעתיק ל‑RAM, כך שאפילו מזהים גדולים נכנסים בנוחות לצד ה‑framebuffer החי. הריצו מזהה 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 אורז שתי ליבות Cortex‑M55 ב‑MCU אחד: ליבת הביצועים הגבוהים (HP) שמריצה את מופע ה‑MicroPython הראשי, את המצלמה, את ה‑HP NPU, את ה‑USB וכן הלאה; וליבת היעילות הגבוהה (HE) היושבת בצריכת מתח נמוכה בהרבה ומאתחלת למופע MicroPython קטן משלה. שתי הליבות חולקות אפיק הודעות Open-AMP / RPMsg, כך שליבת ה‑HP יכולה לשגר פונקציות Python לליבת ה‑HE, לקבל תוצאות בחזרה ולשמור על שני החצאים מנותקים.
נקודת הכניסה הפשוטה ביותר היא הדקורטור @openamp.async_remote. הוא ממסר פונקציית Python, שולח אותה לליבת ה‑HE, וליבת ה‑HE מריצה אותה כמשימת asyncio. לאחר רישום המשימות, יצרו מופע של openamp.RemoteProc עם כתובת ה‑flash של קושחת ה‑HE וקראו ל‑rproc.start() כדי לאתחל את הליבה השנייה. ללא callback, פלט ה‑print() של הפונקציה המעוטרת מועבר דרך נקודת הקצה ברירת המחדל אל ה‑stdout של ליבת ה‑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)
להעברת הודעות דו‑כיוונית, העבירו callback לדקורטור. ה‑callback רץ על ליבת ה‑HP בכל פעם שמשימת ה‑HE קוראת ל‑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)
לליבת ה‑HE יש HE NPU משלה (160 MHz, 46 GOPS), כך שהיא יכולה להריץ מודל ML שני במקביל לכל מה שה‑HP NPU של ליבת ה‑HP עסוק בו. חלוקה שימושית היא להעמיד מודל טריגר / מסווג קטן וקבוע (always-on) בצד ה‑HE ולתת לליבת ה‑HP להגיב רק כשמשהו מעניין מסומן — זיהוי מילות מפתח מהמיקרופון המובנה מתאים היטב מכיוון שהוא רציף, בעל רוחב פס נמוך, וליבת ה‑HE נשארת בצריכת מתח נמוכה בהרבה מ‑HP. העזר הקפוא 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)
לחלוקה עשירה יותר, הריצו BlazeFace על ה‑HP NPU בעוד ליבת ה‑HE מטפלת בזיהוי מילות מפתח ברקע — לולאת ה‑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 מתאימה היטב לעומסי עבודה קבועים (always-on) או בקצב נמוך שאינכם רוצים שיתחרו בצנרת המצלמה/NPU בצד ה‑HP — הסקת ML קטנה, DSP קל על נתוני מיקרופון או IMU, ועבודות רקע דומות.
כמה מגבלות שכדאי לזכור:
היצמדו למיקרופון ול‑IMU בעת הפעלת התקנים היקפיים מליבת ה‑HE — אלה הם הדברים שצד ה‑HE תוכנן עבורם. כל התקן היקפי יכול להיות בבעלות ליבה אחת בלבד בכל רגע נתון, אז בחרו HP או HE עבורו והיצמדו לכך למשך כל חיי הסקריפט.
גוף כל משימת
@openamp.async_remoteחייב להיות ניתן למסירה (marshal) בפחות מ‑500 בייט של bytecode מסוג mpy — שמרו על הפונקציה קטנה ופרקו לוגיקה כבדה יותר למודולי ספרייה נפרדים המוקפאים לתוך הקושחה.ייבואים בתוך הפונקציה המשוגרת רואים רק מודולים הקיימים במערכת הקבצים של ליבת ה‑HE. לליבת ה‑HE יש
/romROMFS משלה — נפרד מה‑/romשל ליבת ה‑HP — כך שמודולים ומודלי ML שברצונכם שיהיו זמינים ב‑HE צריכים להיאפות לתוך תמונת ה‑ROMFS שבצד ה‑HE, ולא זו של ה‑HP.
מיקרופון¶
המיקרופון המובנה נלכד דרך audio — מודול אודיו. כל חוצץ (buffer) מגיע כ‑PCM מסוג signed‑16‑bit בתבנית bytearray, מה שמקל מאוד להזין אותו ל‑ulab/numpy לצורך DSP מהיר. גלאי עוצמת קול פשוט — מדפיס בכל פעם שעוצמת ה‑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 רב‑אזורי המחזיר עד 64 קריאות מרחק לכל פריים, עם טווח מרבי של כ‑4 מ«. הוא חשוף דרך המודול tof — מנהל התקן חיישן time-of-flight — קראו ל‑tof.init() כדי להפעיל את החיישן ול‑tof.read_depth() כדי לתפוס פריים עומק כרשימה שטוחה של קריאות במילימטרים (אחת לכל אזור):
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. השתמשו ב‑aioble — BLE אסינכרוני עבור BLE ידידותי ל‑asyncio — לדוגמה, פרסמו כהתקן היקפי והמתינו שהתקן מרכזי יתחבר:
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 ויכולים לשקוע/לספק עד 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 פועל רק דרך ממיר מתח (level shifter) או לוח נושא 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 המובנה מפצל את I2C2 ב‑3.3 V.
ניתן להשתמש ב‑I2C1 וב‑I2C2 גם במצב יעד (slave) דרך machine.I2CTarget כדי לחשוף אזור זיכרון לבקר I²C אחר:
from machine import I2CTarget
buf = bytearray(32)
target = I2CTarget(1, addr=0x42, mem=buf)
הערה
ההתקן ההיקפי LPI2C אינו חשוף בקושחה. אילו היה חשוף, הוא היה תומך רק ב‑מצב יעד (slave), ו‑I2C1 ו‑I2C2 כבר מכסים גם פעולת בקר וגם פעולת יעד.
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 חושף שני ערוצי ADC של 12 ביט על P8 ו‑P9 (מחבר B2B בלבד). שתי הכניסות מתייחסות ל‑1.8 V — read_u16 מחזיר 0–65535 לאורך 0–1.8 V בפין:
from machine import ADC
import time
adc = ADC("P8")
while True:
voltage = adc.read_u16() * 1.8 / 65535
print(voltage)
time.sleep_ms(100)
אזהרה
כניסות ה‑ADC של ה‑AE3 מתייחסות ל‑1.8 V, לא ל‑3.3 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 בלבד) |
P7 |
TIM9 T1 (B2B בלבד) |
P8 |
TIM5 T0 (B2B בלבד) |
P9 |
TIM5 T1 (B2B בלבד) |
הניעו כל אחד מהם דרך machine.PWM
from machine import Pin, PWM
pwm = PWM(Pin("P0"), freq=1_000, duty_u16=32768)
אפיקים בתוכנה (bit‑banged)¶
machine.SoftI2C ו‑machine.SoftSPI פועלים על כל GPIO אם אתם זקוקים לאפיק נוסף.
חיישן תרמי (חיצוני ללוח)¶
הקושחה כוללת את הדרייבר fir — מנהל התקן לחיישן תרמי (fir == far infrared) עבור מצלם תרמי AMG8833 8 × 8 המחווט חיצונית. חברו את המודול לאפיק ה‑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 מתזמן פונקציות callback מחזוריות או חד‑פעמיות מבלי לצרוך משבצת טיימר חומרתית. העבירו -1 כ‑id כדי להשתמש בטיימר וירטואלי (תוכנה):
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 של backup 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().
מידע על אתחול וזמן ריצה¶
חלון bootloader של USB¶
בכל הפעלה המצלמה מריצה bootloader קצר (כמה שניות) המאפשר ל‑OpenMV IDE לעדכן את הקושחה מבלי שהמשתמש יצטרך להיכנס למצב DFU. לאחר שהחלון פג, ה‑bootloader מעביר את השליטה ל‑boot.py ואז ל‑main.py.
סקריפט פעיל יכול להיכנס מחדש ל‑bootloader לפי דרישה על ידי קריאה ל‑machine.bootloader()
import machine
machine.bootloader()
מערכת קבצים וסדר אתחול¶
קושחת ה‑AE3 מעלה עד שתי מערכות קבצים באתחול:
flash פנימי — תמיד מעלה ב‑
/flash. מחזיק אתmain.pyואתREADME.txtכברירת מחדל; נוצר באתחול הראשון ממש.ROMFS — מערכת קבצים לקריאה בלבד, ממופת זיכרון, ב‑
/romהמשמשת למשלוח נכסי נתונים גדולים (למשל מודלי AI) הנהנים מגישה ללא העתקה (zero‑copy). מועלית אוטומטית על ידי MicroPython באתחול, לפני שכל קוד Python של משתמש רץ.
לאחר ההעלאה, ספריית העבודה מוגדרת ל‑/flash. המפרש אז מריץ סקריפטים מאותה ספרייה:
boot.pyמורץ בכל איפוס רך (אתחול קר,Ctrl‑Dמה‑REPL, או בכל פעם שהסקריפט הרץ חוזר).main.pyמורץ רק באתחול קר, מיד לאחרboot.py. איפוסים רכים עוקבים מריצים מחדש אתboot.pyאך עוברים ישירות ל‑REPL — כדי להריץ מחדש אתmain.pyעליכם לאפס את הלוח לחלוטין.
ה‑main.py ברירת המחדל המשולח בלוח שזה עתה עבר flash פשוט מהבהב בערוץ הכחול של ה‑LED RGB של המשתמש כפעימת לב (שני פולסים קצרים, מרווח קצר), כך שתוכלו לדעת שהקושחה אותחלה כראוי ללא כל מארח מחובר.
sys.path מורחב לכלול את שתי מערכות הקבצים ואת תת‑הספריות lib/ שלהן, כך שמודולים הניתנים לייבוא יכולים לשכון ב‑/flash/lib או ב‑/rom/lib.
כאשר מחובר דרך USB, /flash גם נרשם ככונן אחסון המוני (mass‑storage) USB במארח, ומאפשר לכם לערוך את boot.py, את main.py וכל קובץ אחר ישירות. הוציאו את הכונן לפני איפוס המצלמה כך שהמארח ישטוף את הכתיבות השמורות במטמון שלו.
הערה
מכיוון שמערכת ההפעלה מתייחסת לכונן כהתקן בלוקים פסיבי, קבצים שנוצרו או שונו על ידי קוד הרץ על ה‑OpenMV Cam לא יופיעו עד שהמארח יעלה מחדש את הכונן. אם גם מערכת ההפעלה וגם ה‑OpenMV Cam כותבים לאותה מערכת קבצים בו‑זמנית, מערכת ההפעלה תנצח ותדרוס שינויים שביצעה המצלמה.
הערה
ערוץ האדום של ה‑LED RGB של המשתמש עשוי להידלק לרגע בעוד המארח קורא מכונן האחסון ההמוני USB או כותב אליו — זהו מחוון פעילות מונע‑קושחה, לא תקלה.
גדלי אחסון¶
ה‑AE3 משולח עם:
/flash— מערכת קבצים FAT בגודל 8 MB, קריאה/כתיבה./romבליבת ה‑HP — ROMFS לקריאה בלבד וממופת זיכרון בגודל 24 MB עבור סקריפטים ונתונים שליבת ה‑HP טוענת באתחול./romבליבת ה‑HE — ROMFS לקריאה בלבד בגודל 1 MB שבבעלות ליבת ה‑HE. מודולים ומודלי ML שברצונכם שיהיו זמינים למשימות@openamp.async_remoteחייבים להיאפות לתוך תמונה זו, ולא זו של ה‑HP.
מחוון תקלה חמורה (hard‑fault)¶
אם ה‑LED RGB של המשתמש עובר במהירות בין כל הצבעים — מהר מספיק כך שהוא נוטה להיראות כ‑LED לבן מנצנץ ולא כגוונים נפרדים — הקושחה נתקלה בתקלה חמורה בלתי ניתנת לשחזור. בצעו reflash לקושחה כדי להתאושש; אם ה‑reflash אינו עוזר, ייתכן שהלוח ניזוק פיזית.
ספריות תוכנה¶
ראו את אינדקס הספרייה לרשימה המלאה של המודולים — כולל אילו מהם ייחודיים לבנייה של ה‑AE3.