OpenMV AE3¶
بُنيت OpenMV AE3 حول Alif Ensemble E3 — وهو نظام على شريحة (SoC) ثنائي النواة من نوع ARM Cortex‑M55 (نواة عالية الأداء بتردد 400 MHz + نواة عالية الكفاءة بتردد 160 MHz) مع وحدتي معالجة عصبية (NPU) على الشريحة (وحدة NPU عالية الأداء بتردد 400 MHz / 204 GOPS + وحدة NPU عالية الكفاءة بتردد 160 MHz / 46 GOPS). تجمع اللوحة بين وحدات NPU والمستشعر PAG7936 ذي الـ 1 ميجابكسل والغالق الشامل، ومنفذ USB‑C عالي السرعة، وWi‑Fi، وBluetooth 5.1، ووحدة قياس بالقصور الذاتي LSM6DSM، وميكروفون، ومقياس مدى بزمن الطيران VL53L8CX بدقة 8×8، وكل ذلك على لوحة قياسها 30 × 30 مم.
للاطلاع على ورقة البيانات الكاملة والصور والأبعاد، راجع صفحة منتج OpenMV AE3.
أبرز الميزات¶
Alif Ensemble E3 — معالج ثنائي ARM Cortex‑M55 مع تقنية Helium وحدة SIMD بعرض 128 بت، نواة عالية الأداء بتردد 400 MHz + نواة عالية الكفاءة بتردد 160 MHz (نحو 640 / 256 DMIPS، وCoreMark 1748 / 752).
وحدتا NPU: وحدة NPU عالية الأداء بتردد 400 MHz / 204 GOPS + وحدة NPU عالية الكفاءة بتردد 160 MHz / 46 GOPS للذكاء الاصطناعي / تعلم الآلة — تشغّل كشف الأجسام YOLO جنبًا إلى جنب مع أعباء عمل أخرى.
وحدة معالجة رسومات (GPU) ثنائية الأبعاد عتادية لتغيير الحجم.
ذاكرة SRAM داخلية بسعة 13.5 ميجابايت بالإضافة إلى ذاكرة MRAM على الشريحة بسعة 5.5 ميجابايت وذاكرة فلاش ثُمانية خارجية بسعة 32 ميجابايت (تردد 100 MHz بعرض 8 بت من نوع DDR، قراءة بسرعة 200 ميجابايت/ث).
ذاكرة احتياطية RAM بسعة 4 كيلوبايت مع ساعة الوقت الحقيقي (RTC) على الشريحة.
مستشعر ملوّن بغالق شامل بدقة 1 ميجابكسل من نوع PAG7936.
وحدة قياس بالقصور الذاتي مدمجة (مقياس تسارع + جيروسكوب من نوع LSM6DSM)، وميكروفون، ومستشعر زمن الطيران VL53L8CX بدقة 8×8 (حتى 4 أمتار).
منفذ USB‑C عالي السرعة (480 ميجابت/ث) مع ترشيح للتداخل الكهرومغناطيسي وحماية TVS، وWi‑Fi من نوع a/b/g/n + Bluetooth 5.1 (هوائي على الشريحة أو خيار U.FL).
10 دبابيس إدخال/إخراج للمستخدم — P0–P3 على الموصلات الجانبية، وP4–P5 على موصل Qwiic، وP6–P9 على موصل B2B في الخلف. كما توجّه خطوط إضافية للتنقيح والاسترداد إلى موصل B2B.
جميع الدبابيس إخراج 3.3 فولت / متحملة 3.3 فولت، 25 ملّي أمبير لكل دبوس، وقادرة على المقاطعة. مدخلات ADC مرجعها 1.8 فولت.
LED من نوع RGB للمستخدم، وزر للمستخدم، ومفتاح استرداد، وموصل Qwiic.
سُبات عميق بسحب 80 ميكرو أمبير عند 3.3 فولت (24 ملّي أمبير في الخمول، 50–60 ملّي أمبير عند النشاط).
تحذير
دبابيس الإدخال/الإخراج في AE3 غير متحملة لجهد 5 فولت. لا توصّل الجهاز مباشرة بوحدة تحكم دقيقة تعمل بجهد 5 فولت مثل Arduino Mega — استخدم محوّل مستوى لأي إشارة بجهد 5 فولت.
مخطط الدبابيس¶
مرجع الدبابيس¶
تكشف AE3 عن 10 دبابيس للمستخدم على الموصلات الجانبية (P0–P9). تُوجَّه إشارات إضافية — بما في ذلك JTAG وخط الاسترداد — إلى موصل B2B (لوحة إلى لوحة) في الخلف من اللوحة من أجل الدروع واللوحات الحاملة.
اسم الدبوس |
المرجع |
الوظيفة |
|---|---|---|
P0 |
3.3 فولت |
SPI0 MOSI / I2C2 SCL / UART4 TX / TIM0 T1 / PDM D3 |
P1 |
3.3 فولت |
SPI0 MISO / I2C2 SDA / UART4 RX / TIM0 T0 |
P2 |
3.3 فولت |
SPI0 SCLK / LPI2C SDA / UART5 TX / TIM1 T1 |
P3 |
3.3 فولت |
SPI0 SS / LPI2C SCL / UART5 RX / TIM1 T0 / PDM C3 |
P4 |
3.3 فولت |
I2C1 SCL / UART1 TX / TIM2 T1 / PDM C0 / CAN TX |
P5 |
3.3 فولت |
I2C1 SDA / UART1 RX / TIM2 T0 / PDM D0 / CAN RX |
P6 |
1.8 فولت |
I2C1 SDA / UART3 CTS / TIM9 T0 (B2B فقط) |
P7 |
1.8 فولت |
I2C1 SCL / UART3 RTS / TIM9 T1 (B2B فقط) |
P8 |
1.8 فولت |
I3C SDA / UART3 RX / TIM5 T0 / ADC ch S10 (B2B فقط) |
P9 |
1.8 فولت |
I3C SCL / UART3 TX / TIM5 T1 / ADC ch S11 (B2B فقط) |
P10 |
1.8 فولت |
GPIO / JTAG TCK (B2B فقط) |
P11 |
1.8 فولت |
GPIO / JTAG TDO (B2B فقط) |
P13 |
1.8 فولت |
GPIO / JTAG TMS (B2B فقط) |
P14 |
1.8 فولت |
GPIO / JTAG TDI (B2B فقط) |
RESET |
3.3 فولت |
اسحبه إلى GND لإعادة ضبط اللوحة |
SW |
3.3 فولت |
زر المستخدم (نشط عند المستوى المنخفض) |
LED_RED |
3.3 فولت |
قناة الأحمر في LED من نوع RGB (نشطة عند المستوى المنخفض) |
LED_GREEN |
3.3 فولت |
قناة الأخضر في LED من نوع RGB (نشطة عند المستوى المنخفض) |
LED_BLUE |
3.3 فولت |
قناة الأزرق في LED من نوع RGB (نشطة عند المستوى المنخفض) |
ملاحظة
الدبابيس P0–P5 موجودة على الموصلات الجانبية (مرجعها 3.3 فولت)؛ أما P6–P9 فتُكشف فقط على موصل B2B في خلف اللوحة ومرجعها 1.8 فولت. سيؤدي دفع 3.3 فولت إلى دبوس مرجعه 1.8 فولت إلى تلف نظام SoC — تأكد من أن أي إشارة متصلة بموصل B2B تكون عند 1.8 فولت.
دبابيس الطاقة¶
3.3V — مسار الطاقة الرئيسي في AE3. يُكشف مسار 3.3 فولت نفسه على وسادات لحام موصل GPIO، وموصل Qwiic، وموصل B2B في خلف اللوحة.
1.8V — يُكشف على موصل B2B بوصفه إخراجًا فقط. استخدمه لتزويد الطرفيات ذات منطق 1.8 فولت بالطاقة على لوحة حاملة B2B؛ لا تدفعه من خارج اللوحة.
GND — الأرضي المشترك.
لا تملك AE3 دبوس VIN ولا شاحن LiPo. ويمكن تزويدها بالطاقة عبر أي من ثلاثة مسارات:
USB‑C — يخفض المنظّم الموجود على اللوحة الجهد من 5 فولت في USB إلى 3.3 فولت ويحقنه في مسار 3.3 فولت.
موصل Qwiic — ادفع مصدر تغذية منظّمًا بجهد 3.3 فولت إلى موصل Qwiic لتزويد اللوحة بالطاقة من وحدة Qwiic.
موصل GPIO / وسادات 3.3 فولت في B2B — ادفع مصدر تغذية منظّمًا بجهد 3.3 فولت إلى أي من وسادات 3.3 فولت على موصل الإدخال/الإخراج أو موصل B2B.
يغذّي منظّم USB المسار عبر صمام ثنائي مثالي، لذا تستطيع مصادر التغذية الخارجية بجهد 3.3 فولت على جانب Qwiic / GPIO / B2B تزويد اللوحة بالطاقة حتى وإن كان USB ما يزال موصولًا، دون دفع عكسي لمنظّم USB.
نصيحة
استخدم أداة تقدير عمر البطارية لنمذجة المدة التي ستعمل خلالها AE3 على بطارية وفق دورة عمل معطاة بين النشاط والسُبات العميق.
دبابيس الاسترداد والتنقيح¶
RESET — اسحبه إلى GND لإعادة ضبط اللوحة. وعند تحريره يبدأ نظام SoC في التشغيل بشكل طبيعي.
يوجد مفتاح استرداد على الوجه الأمامي (جانب الكاميرا) من اللوحة، في الزاوية السفلية اليسرى. وعند تمكينه يُجبر منفذ SE UART في AE3 على الخروج عبر USB كي يتمكن OpenMV IDE من إعادة وميض محمّل الإقلاع الموجود على اللوحة. ويمكن تشغيل وضع الاسترداد نفسه عن بُعد عبر سحب دبوس RECOVERY على موصل B2B إلى المستوى المنخفض.
تدعم AE3 كلا نوعي التنقيح SWD وJTAG الكامل:
موصل SWD بجهد 1.8 فولت على جانب اللوحة مخصص لكابل 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 فولت — تأكد من ضبط محوّل التنقيح لديك على منطق 1.8 فولت قبل التوصيل.
الطرفيات الموجودة على اللوحة¶
مصابيح 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 الوضع المُحفَّز — حيث تتزامن خطوط تكامل البكسلات بدقة مع كل استدعاء لـ csi.CSI.snapshot بدلًا من ساعة الإطارات ذاتية التشغيل، وهو مفيد لمزامنة الالتقاط مع حدث خارجي أو مع مستشعر آخر. مكّنه عبر csi.CSI.ioctl مع csi.IOCTL_SET_TRIGGERED_MODE. وينخفض معدل الإطارات إلى نحو نصف معدل الوضع ذاتي التشغيل لأن القراءة لم تعد تتداخل مع تكامل الإطار التالي:
cam.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True)
NPU¶
تُكشف وحدتا NPU على الشريحة في AE3 (وحدة NPU عالية الأداء بتردد 400 MHz / 204 GOPS + وحدة NPU عالية الكفاءة بتردد 160 MHz / 46 GOPS) عبر وحدة 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 نواتي Cortex‑M55 في وحدة تحكم دقيقة واحدة: النواة عالية الأداء (HP) التي تشغّل نسخة MicroPython الرئيسية والكاميرا ووحدة NPU عالية الأداء وUSB وما إلى ذلك؛ والنواة عالية الكفاءة (HE) التي تعمل بطاقة أقل بكثير وتُقلع إلى نسخة MicroPython صغيرة خاصة بها. وتتشارك النواتان ناقل رسائل Open-AMP / RPMsg، فيمكن للنواة HP إرسال دوال Python إلى النواة HE واستلام النتائج وإبقاء النصفين منفصلين.
أبسط نقطة دخول هي المُزخرِف @openamp.async_remote. فهو يُسلسِل دالة Python ويرسلها إلى النواة HE، التي تشغّلها بوصفها مهمة asyncio. وبعد تسجيل المهام، أنشئ نسخة من openamp.RemoteProc بعنوان فلاش البرنامج الثابت للنواة HE واستدعِ rproc.start() لإقلاع النواة الثانية. وفي حال عدم وجود دالة رد نداء، يُمرَّر خرج 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)
للمراسلة ثنائية الاتجاه، مرّر دالة رد نداء إلى المُزخرِف. وتُنفَّذ دالة رد النداء على النواة 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 وحدة NPU عالية الكفاءة خاصة بها (160 MHz، 46 GOPS)، فتستطيع تشغيل نموذج تعلم آلة ثانٍ بالتوازي مع ما تنشغل به وحدة NPU عالية الأداء في النواة HP. ومن التقسيمات المفيدة وضع نموذج محفّز / مُصنِّف صغير دائم العمل على جانب 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 على وحدة 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 أعباء العمل الدائمة العمل أو منخفضة المعدل التي لا تريد لها أن تنافس مسار الكاميرا / NPU على جانب HP — كالاستدلال بنماذج تعلم آلة صغيرة، ومعالجة الإشارات الرقمية الخفيفة على بيانات الميكروفون أو وحدة القصور الذاتي، وأعمال الخلفية المماثلة.
بعض القيود التي ينبغي وضعها في الحسبان:
اقتصر على الميكروفون ووحدة القصور الذاتي عند تشغيل الطرفيات من النواة HE — فهي ما صُمم جانب HE من أجله. ولا يمكن أن تملك كل طرفية إلا نواة واحدة في وقت معين، لذا اختر لها HP أو HE والتزم بذلك طوال عمر البرنامج النصي.
يجب أن يُسلسَل متن كل مهمة
@openamp.async_remoteإلى أقل من 500 بايت من بايتكود mpy — أبقِ الدالة صغيرة وفكّك المنطق الأثقل إلى وحدات مكتبية منفصلة تُجمَّد في البرنامج الثابت.لا ترى عمليات الاستيراد داخل الدالة المُرسَلة إلا الوحدات الموجودة على نظام ملفات النواة HE. وتملك النواة HE نظام ROMFS
/romخاصًا بها — منفصلًا عن/romالخاص بالنواة HP — لذا يجب خبز الوحدات ونماذج تعلم الآلة التي تريد إتاحتها على HE داخل صورة ROMFS الخاصة بجانب HE، لا تلك الخاصة بـ HP.
الميكروفون¶
يُلتقط الميكروفون الموجود على اللوحة عبر audio --- وحدة الصوت. ويصل كل مخزن مؤقت على هيئة bytearray بصيغة PCM ذي 16 بت بإشارة، مما يجعل من البسيط تمريره إلى 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)
مستشعر زمن الطيران¶
تحمل AE3 مستشعر زمن الطيران متعدد المناطق VL53L8CX بدقة 8×8 الذي يعيد حتى 64 قراءة مسافة لكل إطار، بمدى أقصى نحو 4 أمتار. ويُكشف عبر وحدة tof --- مشغل مستشعر زمن الرحلة — استدعِ 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 فولت CMOS ويمكنها سحب/إمداد حتى 25 ملّي أمبير لكل دبوس.
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 فولت، فإن UART3 لا يعمل إلا عبر محوّل مستوى أو لوحة حاملة B2B — لا توصّل منطق 3.3 فولت به مباشرة.
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 فولت.
يمكن أيضًا استخدام I2C1 وI2C2 في وضع الهدف (التابع) عبر machine.I2CTarget لكشف منطقة ذاكرة لوحدة تحكم I²C أخرى:
from machine import I2CTarget
buf = bytearray(32)
target = I2CTarget(1, addr=0x42, mem=buf)
ملاحظة
الطرفية LPI2C غير مكشوفة في البرنامج الثابت. وهي لن تدعم سوى وضع الهدف (التابع) إن كُشفت، كما أن 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 فولت — يعيد read_u16 القيمة 0–65535 عبر المدى 0–1.8 فولت عند الدبوس:
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 فولت، لا 3.3 فولت. وسيؤدي دفع إشارة خام بجهد 3.3 فولت إلى إشباع المحوّل وقد يتلف الدبوس — قسّم الجهود الأعلى خارجيًا.
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‑banging¶
تعمل 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 دوال رد نداء دورية أو لمرة واحدة دون استهلاك فتحة مؤقت عتادي. مرّر -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 كيلوبايت من ذاكرة 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¶
عند كل تشغيل تعمل الكاميرا على محمّل إقلاع قصير (بضع ثوانٍ) يتيح لـ OpenMV IDE تحديث البرنامج الثابت دون اضطرار المستخدم إلى الدخول في وضع DFU. وبعد انتهاء النافذة يسلّم محمّل الإقلاع المهمة إلى boot.py ثم main.py.
يمكن لبرنامج نصي قيد التشغيل إعادة الدخول إلى محمّل الإقلاع عند الطلب باستدعاء machine.bootloader()
import machine
machine.bootloader()
نظام الملفات وترتيب الإقلاع¶
يركّب البرنامج الثابت في AE3 ما يصل إلى نظامي ملفات عند الإقلاع:
الفلاش الداخلي — مركّب دائمًا عند
/flash. ويحتوي علىmain.pyوREADME.txtافتراضيًا؛ ويُنشأ عند أول إقلاع على الإطلاق.ROMFS — نظام ملفات للقراءة فقط ومُسقَط في الذاكرة عند
/romيُستخدم لشحن أصول بيانات كبيرة (مثل نماذج الذكاء الاصطناعي) تستفيد من الوصول بلا نسخ. يركّبه MicroPython تلقائيًا عند بدء التشغيل، قبل تشغيل أي شيفرة Python للمستخدم.
بعد التركيب، يُضبط دليل العمل على /flash. ثم يشغّل المفسّر البرامج النصية من ذلك الدليل:
يُنفَّذ
boot.pyعند كل إعادة ضبط ناعمة (إقلاع بارد، أوCtrl‑Dمن REPL، أو كلما عاد البرنامج النصي قيد التشغيل).يُنفَّذ
main.pyعند الإقلاع البارد فقط، فورboot.pyمباشرة. وتعيد عمليات إعادة الضبط الناعمة اللاحقة تشغيلboot.pyلكنها تنتقل مباشرة إلى REPL — ولإعادة تشغيلmain.pyعليك إعادة ضبط اللوحة بالكامل.
يكتفي main.py الافتراضي المشحون على لوحة طازجة الوميض بإيماض قناة الأزرق في LED من نوع RGB للمستخدم بوصفها نبض حياة (نبضتان قصيرتان، بفاصل قصير)، فيمكنك معرفة أن البرنامج الثابت أقلع بنجاح دون أي مضيف موصول.
يُوسَّع sys.path ليشمل نظامي الملفات كليهما وأدلتهما الفرعية lib/، فيمكن للوحدات القابلة للاستيراد أن تقيم في /flash/lib أو /rom/lib.
عند التوصيل عبر USB، يُعدَّد /flash أيضًا بوصفه قرص تخزين USB كبير السعة على المضيف، مما يتيح لك تحرير boot.py وmain.py وأي ملفات أخرى مباشرة. أخرج القرص قبل إعادة ضبط الكاميرا كي يُفرغ المضيف كتاباته المخزنة مؤقتًا.
ملاحظة
لأن نظام التشغيل يعامل القرص بوصفه جهاز كتل سلبيًا، فإن الملفات التي تنشئها أو تعدّلها شيفرة تعمل على OpenMV Cam لن تظهر حتى يعيد المضيف تركيب القرص. وإذا كتب كل من نظام التشغيل وOpenMV Cam على نظام الملفات نفسه في الوقت نفسه، فسيفوز نظام التشغيل ويكتب فوق التغييرات التي أجرتها الكاميرا.
ملاحظة
قد تضيء قناة الأحمر في LED من نوع RGB للمستخدم لفترة وجيزة أثناء قراءة المضيف من قرص تخزين USB كبير السعة أو الكتابة إليه — وهذا مؤشر نشاط يقوده البرنامج الثابت، وليس عطلًا.
أحجام التخزين¶
تأتي AE3 مع:
/flash— نظام ملفات FAT بسعة 8 ميجابايت، للقراءة/الكتابة./romعلى النواة HP — نظام ROMFS للقراءة فقط ومُسقَط في الذاكرة بسعة 24 ميجابايت للبرامج النصية والبيانات التي تحمّلها النواة HP عند بدء التشغيل./romعلى النواة HE — نظام ROMFS للقراءة فقط بسعة 1 ميجابايت تملكه النواة HE. ويجب خبز الوحدات ونماذج تعلم الآلة التي تريد إتاحتها لمهام@openamp.async_remoteداخل هذه الصورة، لا تلك الخاصة بـ HP.
مؤشر العطل الفادح¶
إذا كان LED من نوع RGB للمستخدم يدور بسرعة عبر جميع الألوان — بسرعة كافية تجعله يبدو غالبًا كـ LED أبيض متلألئ بدلًا من ألوان متمايزة — فهذا يعني أن البرنامج الثابت واجه عطلًا فادحًا غير قابل للاسترداد. أعد وميض البرنامج الثابت للاسترداد؛ وإذا لم تساعد إعادة الوميض، فقد تكون اللوحة تالفة ماديًا.
المكتبات البرمجية¶
راجع فهرس المكتبات للحصول على القائمة الكاملة للوحدات — بما في ذلك تلك الفريدة لبناء AE3.