OpenMV Pure Thermal

إن OpenMV Pure Thermal هي لوحة تصوير حراري متكاملة النظام مبنية حول المعالج STMicroelectronics STM32H743 (Cortex‑M7 بتردد 480 MHz) مع 64 MB من ذاكرة SDRAM خارجية، و32 MB من ذاكرة فلاش QSPI، ومُرمِّز JPEG عتادي، وشاشة لمس سعوية IPS مقاس 4.3" بدقة 800×480، ومخرج HDMI، ومقبس حراري FLIR® Lepton®، وكاميرا ضوء مرئي OV5640 بدقة 5 ميجابكسل. كما تتضمن Wi‑Fi، ومقبس microSD، ومقياس مدى بالليزر، وجرس صفّارة، ومُضيء أبيض عالي الطاقة.

OpenMV Pure Thermal

للاطلاع على ورقة البيانات الكاملة والصور والأبعاد، راجع صفحة منتج OpenMV Pure Thermal.

أبرز المواصفات

  • STMicroelectronics STM32H743XI بنواة Cortex‑M7 بتردد 480 MHz.

  • مُرمِّز/فاك ترميز JPEG عتادي.

  • 64 MB من ذاكرة SDRAM خارجية (~400 MB/s) بالإضافة إلى 1 MB من ذاكرة SRAM داخلية.

  • 2 MB من ذاكرة فلاش داخلية + 32 MB من ذاكرة فلاش QSPI خارجية (قراءة ~50 MB/s).

  • مستشعر ضوء مرئي OV5640 بدقة 5 ميجابكسل بمصراع متدحرج.

  • مقبس FLIR® Lepton® — يقبل أي وحدة Lepton طراز 1/2/2.5/3/3.5، إشعاعية أو غير إشعاعية، مع قياس درجة الحرارة لكل بكسل بالدرجات المئوية.

  • شاشة لمس سعوية IPS مقاس 4.3" بدقة 800×480 (لون 24‑بت بتردد 60 Hz) مع دعم إيماءات يصل إلى 5 نقاط.

  • مخرج HDMI عبر مُسلسِل DVI من نوع TFP410 — حتى دقة 1280×720 بتردد 60 Hz.

  • Wi‑Fi عبر WINC1500؛ مع دعم MJPEG عبر RTSP جاهزاً للاستخدام.

  • USB‑C بسرعة كاملة (12 Mb/s، محدود التيار عند 900 mA) — يظهر للمضيف كـ VCP + جهاز تخزين USB، ويتولى الشحن أيضاً.

  • مقبس microSD — بطاقات SD حتى 2 GB، وSDHC حتى 32 GB، وSDXC حتى 2 TB.

  • مقياس مدى بالليزر VL53L1CX (حتى ~4 أمتار).

  • جرس صفّارة مع التحكم بالصوت/التردد برمجياً.

  • مُضيء LED أبيض عالي الطاقة بالإضافة إلى مؤشر LED RGB للمستخدم.

  • موصّل بطارية LiPo مع شحن عبر USB بتيار 500 mA.

  • 10 دبابيس إدخال/إخراج، تتحمل 5 فولت بمخرج 3.3 فولت، 25 mA لكل دبوس (120 mA إجمالاً)، قابلة للمقاطعة. لا يتحمل الدبوس P6 جهد 5 فولت عند استخدامه في وضع ADC أو DAC.

  • موصّل ARM SWD ذو 10 دبابيس لتصحيح الأخطاء عبر ST‑LINK / J‑Link.

  • موصّل Qwiic للطرفيات على ناقل I²C.

ملاحظة

تحتوي اللوحة على فتحة عند حافتها السفلية اليسرى لتركيب صامولة حامل ثلاثي القوائم بمقاس ¼"–20 اختيارية. وهي غير مركّبة من المصنع — قم بلحام واحدة في الفتحة إذا أردت تثبيت اللوحة على حامل كاميرا ثلاثي قياسي.

مخطط الدبابيس

OpenMV Pure Thermal pinout

مرجع الدبابيس

اسم الدبوس

الوظيفة

P0

UART1 RX / SPI2 MOSI

P1

UART1 TX / SPI2 MISO

P2

SPI2 SCK / FDCAN2 TX

P3

SPI2 NSS (CS) / FDCAN2 RX

P4

I2C2 SCL / UART3 TX / TIM2 CH3

P5

I2C2 SDA / UART3 RX / TIM2 CH4

P6

ADC / DAC / TIM2 CH1

P7

I2C4 SCL / TIM4 CH1

P8

I2C4 SDA / TIM4 CH2

P9

إدخال/إخراج رقمي

RESET

اوصله بـ GND لإعادة ضبط اللوحة

SYN

وسادة مزامنة الإطارات — غير موصولة

VIN

وسادة VIN للدرع — غير موصولة

BOOT0

اوصله بـ 3.3 فولت عند التشغيل لدخول وضع DFU / محمّل إقلاع ROM

BUZZER

جرس الصفّارة البيزو على اللوحة (مدفوع عبر TIM2/PWM)

LED_RED

القناة الحمراء لمؤشر LED RGB للحالة (فعّال عند المنخفض)

LED_GREEN

القناة الخضراء لمؤشر LED RGB للحالة (فعّال عند المنخفض)

LED_BLUE

القناة الزرقاء لمؤشر LED RGB للحالة (فعّال عند المنخفض)

LED_WHITE

مُضيء LED أبيض عالي الطاقة

ملاحظة

وسادتا SYN وVIN على الدرع/الترويسة ليس لهما أي اتصال كهربائي على Pure Thermal — فهما موجودتان لأغراض التوافق مع الترويسة فقط. شغّل اللوحة بدلاً من ذلك عبر USB‑C أو موصّل بطارية LiPo على اللوحة (راجع دبابيس الطاقة أدناه). لاحظ أيضاً أن وسادة VIN مطبوعة بالحرير VBAT على اللوحة (خطأ في الوسم) — الموضع هو دبوس VIN القياسي في ترويسة OpenMV وهو غير موصول في كلتا الحالتين.

دبابيس الطاقة

  • 3.3V — خط طاقة 3.3 فولت منظَّم. يتوفر حتى 250 mA للدروع.

  • GND — الأرضي المشترك.

تُغذَّى Pure Thermal بالطاقة عبر USB‑C أو موصّل بطارية LiPo على اللوحة. منفذ USB‑C محدود التيار عند 900 mA إجمالاً ويتولى أيضاً شحن LiPo بتيار 500 mA، لذا فإن توصيل بطارية إلى جانب USB مدعوم.

يبدّل زر الطاقة على اللوحة خطوط طاقة النظام بين التشغيل والإيقاف ويعمل سواء كانت اللوحة مُغذّاة من USB أو من LiPo. اضغط مع الاستمرار على الزر لبضع ثوانٍ لتغيير الحالة — يُتجاهل النقر السريع لمنع الإيقاف العرضي.

يتبع اختيار المصدر قاعدتين بسيطتين:

  • لا تُغذّي البطارية اللوحة إلا عندما يكون جهدها أعلى من 3 فولت. وأدنى من تلك العتبة تفصل دائرة PMIC على اللوحة البطارية لحمايتها من التفريغ المفرط.

  • عند وجود USB، فإن USB يُغذّي اللوحة وتُشحن أي بطارية LiPo موصولة في الخلفية.

كما يتميز موصّل LiPo بـ حماية من عكس الجهد، لذا فإن توصيل البطارية بشكل معكوس لن يضر باللوحة.

ملاحظة

كما توجّه اللوحة إشارتي جهد البطارية واستشعار تيار البطارية إلى قنوات ADC في المتحكم الدقيق، لكن لم يُضَف بعد دعم البرنامج الثابت لأي منهما.

دبابيس الاسترداد وتصحيح الأخطاء

  • RESET — اوصله بـ GND لإعادة ضبط اللوحة. تحتوي Pure Thermal أيضاً على زر RESET مخصص على اللوحة يقوم بالشيء نفسه.

  • BOOT0 — اوصله بـ 3.3 فولت أثناء تشغيل اللوحة لدخول محمّل إقلاع ROM في STM32 (وضع DFU). يستخدم OpenMV IDE هذا الوضع لإعادة تحميل محمّل الإقلاع على اللوحة. يوجد زر BOOT0 مخصص على اللوحة يقوم بالشيء نفسه — اضغط مع الاستمرار عليه أثناء توصيل الطاقة.

تعرض اللوحة ترويسة تصحيح أخطاء SWD (RST / SWCLK / SWDIO / SWO) بجوار ترويسة GPIO، متوافقة مع مهايئات ST‑LINK وSEGGER J‑Link. كما رُكّب موصّل منفصل ARM SWD ذو 10 دبابيس — يحمل إشارات SWD نفسها (دون JTAG كامل) لكن بالشكل القياسي ذي العشرة دبابيس بمقاس 0.05".

ملاحظة

دبوس تتبع SWO مشترك مع ساعة SPI الخاصة بـ FLIR® Lepton® على اللوحة. لا يمكن استخدام SWO في الوقت نفسه مع Lepton — اختر أحدهما.

رُكّب على اللوحة موصّل ثالث باسم PURE Modules Debug. وهو يُخرج حفنة من الإشارات الموجهة لتصحيح الأخطاء (SWCLK، وSWDIO، وRST، وSPI2_MISO، وSPI2_MOSI، وVBUS، و3.3 فولت، وGND، ودبوسي GPIO) لتوصيل وحدات مرافقة. ويُدفع دبوسا GPIO على هذا الموصّل عبر ناقل I²C مُحاكى ببرمجة البتات بدلاً من طرفية عتادية.

تشير موصّلات تصحيح الأخطاء الثلاثة جميعها (ترويسة SWD المضمّنة، وموصّل ARM SWD ذو 10 دبابيس، وموصّل PURE Modules Debug) إلى 3.3 فولت — تأكد من ضبط مهايئ تصحيح الأخطاء لديك على منطق 3.3 فولت قبل التوصيل.

الطرفيات المدمجة على اللوحة

مؤشرات LED

تحتوي Pure Thermal على ثلاثة مؤشرات LED على اللوحة:

  • مؤشر LED RGB للمستخدم — قابل للتحكم برمجياً، ومعروض كـ LED_RED وLED_GREEN وLED_BLUE

    from machine import LED
    
    LED("LED_RED").on()
    LED("LED_GREEN").on()
    LED("LED_BLUE").on()
    
  • المُضيء الأبيض — مدفوع عبر LED_WHITE. سُلِّك LED_WHITE ليكون فعّالاً عند المرتفع في العتاد بينما يعامل البرنامج الثابت كل مؤشر LED آخر على اللوحة على أنه فعّال عند المنخفض، لذا استخدم low() / high() بدلاً من on() / off() (التي ستعكس المنطق):

    from machine import LED
    
    light = LED("LED_WHITE")
    light.low()    # turn the white LED ON
    light.high()   # turn the white LED OFF
    
  • مؤشر LED للشحن — مدفوع مباشرة بعتاد إدارة الطاقة على اللوحة، دون أي تحكم برمجي. ويعمل سواء كانت خطوط طاقة النظام قيد التشغيل أو الإيقاف (أي مع زر الطاقة في أي من الوضعين).

    اللون

    المعنى

    أزرق

    قيد الشحن — راجع قائمة الأخطاء: قد لا ينطفئ عند اكتمال الشحن

    أخضر

    اكتمل الشحن — راجع قائمة الأخطاء: قد لا يُفعَّل بشكل موثوق

    أحمر

    بطارية منخفضة (≤ 3.2 فولت، فقط عند عدم الشحن الفعّال)

جرس الصفّارة

جرس الصفّارة البيزو على اللوحة مُسلَّك إلى قناة مؤقت — ادفعه باستخدام machine.PWM لإصدار نغمات مع التحكم برمجياً في التردد (طبقة الصوت) ودورة التشغيل (مستوى الصوت):

import time
from machine import Pin, PWM

beep = PWM(Pin("BUZZER"), freq=2_000, duty_u16=32768)   # ~50% duty
time.sleep_ms(500)                                      # sound for 0.5 s
beep.deinit()

مستشعر الكاميرا

إن OV5640 هو CSI الأساسي على Pure Thermal — مرّر cid=csi.OV5640 لمخاطبته صراحةً:

import csi

cam = csi.CSI(cid=csi.OV5640)
cam.reset(hard=True)
cam.pixformat(csi.RGB565)
cam.framesize(csi.WVGA)
cam.snapshot(time=2000)       # let auto‑exposure settle

while True:
    img = cam.snapshot()

يحتوي OV5640 على ضاغط JPEG على اللوحة. اضبط csi.CSI.pixformat على csi.JPEG فيقوم المستشعر بتسليم إطارات مضغوطة مباشرة إلى الكاميرا عبر ناقل الكاميرا، مما يجعل الالتقاطات عالية الدقة عملية: تُبثّ جميع csi.HD (1280×720) وcsi.FHD (1920×1080) ودقة 5 ميجابكسل الكاملة csi.WQXGA2 (2592×1944) بصيغة JPEG. اضبط الضغط عبر csi.CSI.quality (0-100، الأعلى = إطارات أكبر وتفاصيل أكثر):

cam.pixformat(csi.JPEG)
cam.framesize(csi.WQXGA2)
cam.quality(90)

يحتوي OV5640 على عدسة تركيز تلقائي مُحرَّكة بمشغّل ملف صوتي. شغّل تمريرة تركيز تلقائي واحدة عبر csi.CSI.ioctl مع csi.IOCTL_TRIGGER_AUTO_FOCUS — يكنس المستشعر محرك التركيز مرة واحدة ويثبّت على أي شيء أمامه:

cam.ioctl(csi.IOCTL_TRIGGER_AUTO_FOCUS)

أعد إصدار ioctl في أي وقت يتغير فيه المشهد — التركيز التلقائي ذو لقطة واحدة، وليس مستمراً.

ملاحظة

مخرج STROBE الخاص بـ OV5640 (يُستخدم للفلاش المتزامن / إضاءة الأشعة تحت الحمراء) مُسلَّك إلى المتحكم الدقيق على Pure Thermal، لكن لم يُضَف بعد دعم البرنامج الثابت له.

مستشعر الكاميرا الحرارية

يظهر مقبس FLIR® Lepton® كـ CSI ثانٍ على واجهة csi --- مستشعرات الكاميرا نفسها. مرّر cid=csi.LEPTON لمخاطبته، وتخطَّ إعادة ضبط العتاد:

import csi

lepton = csi.CSI(cid=csi.LEPTON)
lepton.reset(hard=False)
lepton.pixformat(csi.GRAYSCALE)
lepton.framesize(csi.QVGA)

while True:
    img = lepton.snapshot()

ملاحظة

مخرج VSYNC الخاص بـ Lepton (نبضة واحدة لكل إطار حراري) مُسلَّك إلى المتحكم الدقيق على Pure Thermal، لكن لم يُضَف بعد دعم البرنامج الثابت له.

يمكن تشغيل كلا CSI جنباً إلى جنب. يسحب المثال أدناه إطاراً ملوناً من OV5640 وإطاراً حرارياً من Lepton، ثم يطبق Lepton فوق الإطار الملون باستخدام لوحة ألوان Ironbow وقناع ألفا يتلاشى ليصبح شفافاً عند الكثافات المنخفضة:

import csi
import image
import math

alpha_pal = image.Image(256, 1, image.GRAYSCALE)
for i in range(256):
    alpha_pal[i] = int(math.pow((i / 255), 2) * 255)

csi0 = csi.CSI()
csi0.reset(hard=True)
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.WVGA)

csi1 = csi.CSI(cid=csi.LEPTON)
csi1.reset(hard=False)
csi1.pixformat(csi.GRAYSCALE)
csi1.framesize(csi.QVGA)

img1 = image.Image(csi1.width(), csi1.height(), csi1.pixformat())

while True:
    img0 = csi0.snapshot()
    csi1.snapshot(blocking=False, image=img1)
    img0.draw_image(
        img1, 0, 0,
        color_palette=image.PALETTE_IRONBOW,
        alpha_palette=alpha_pal,
        hint=image.BILINEAR,
    )

تعلّم الآلة

تشغّل ml --- التعلم الآلي نماذج TFLite المُكمَّمة على نواة Cortex‑M7 باستخدام نوى CMSIS‑NN — وهي سريعة بما يكفي للكواشف المدمجة عند بضعة إطارات في الثانية. تُحمَّل النماذج الموجودة على نظام الملفات للقراءة فقط /rom مباشرة من الفلاش دون نسخها إلى RAM. إليك كاشف وجوه BlazeFace بدقة 128×128 يطبق الوجه المكتشف ونقاطه الست المميزة على كل إطار من كاميرا الضوء المرئي:

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

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

# Load built-in face detection model
model = ml.Model("/rom/blazeface_front_128.tflite", postprocess=BlazeFace(threshold=0.4))
print(model)

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

    # faces is a list of ((x, y, w, h), score, keypoints) tuples
    for r, score, keypoints in model.predict([img]):
        ml.utils.draw_predictions(img, [r], ("face",), ((0, 0, 255),), format=None)

        # keypoints is a ndarray of shape (6, 2)
        # 0 - right eye (x, y)
        # 1 - left eye (x, y)
        # 2 - nose (x, y)
        # 3 - mouth (x, y)
        # 4 - right ear (x, y)
        # 5 - left ear (x, y)
        ml.utils.draw_keypoints(img, keypoints, color=(255, 0, 0))

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

مقياس المدى بالليزر

مقياس المدى بزمن الرحلة من نوع ST VL53L1CX على اللوحة مُسلَّك إلى ناقل I²C رقم 2. استخدم المُشغّل المجمَّد vl53l1x --- مشغّل مستشعر المسافة VL53L1X بتقنية ToF للحصول على قراءات المسافة حتى ~4 أمتار:

import time
from machine import I2C
import vl53l1x

bus = I2C(2)
tof = vl53l1x.VL53L1X(bus)

while True:
    print("Distance:", tof.read(), "mm")
    time.sleep_ms(100)

مخرج LCD

شاشة LCD مقاس 4.3" على اللوحة بدقة 800 × 480 (WVGA) ومدفوعة عبر واجهة عرض RGB في وحدة display --- مشغّل العرض — مرّر framesize=display.FWVGA لمطابقة دقتها الأصلية:

import display

lcd = display.RGBDisplay(framesize=display.FWVGA, refresh=60)
lcd.backlight(True)           # turn the LCD backlight on
lcd.write(img)

الإضاءة الخلفية مُسلَّكة إلى GPIO، لذا تقبل backlight() القيمة True / False (أو أي قيمة بين 0–100، حيث 0 يعني إيقاف وأي قيمة غير صفرية تعني تشغيل):

lcd.backlight(False)           # turn the backlight off
lcd.backlight(True)            # back on

شاشة اللمس

متحكم اللمس السعوي هو FT5X06؛ تُعرض مواضع اللمس المتعدد وأحداث الإيماءات عبر ft5x06 --- مشغّل شاشة اللمس. سجّل دالة رد نداء للتفاعل مع اللمسات واقرأ النقاط النشطة بداخلها:

import ft5x06

touch = ft5x06.FT5X06()

def on_touch(n):
    for i in range(n):
        x = touch.get_point_x(i)
        y = touch.get_point_y(i)
        print("touch", i, "at", x, y)

    gesture = touch.get_gesture()
    if gesture != ft5x06.GESTURE_NONE:
        print("gesture:", gesture)

touch.touch_callback(on_touch)

مخرج HDMI

يوزّع البرنامج الثابت أيضاً مخزن إطارات LCD إلى مُسلسِل HDMI من نوع tfp410 --- وحدة تحكم DVI/HDMI على اللوحة، بحيث تعكس شاشة خارجية ما يظهر على LCD. أنشئ نسخة من tfp410.TFP410 لتفعيل مخرج HDMI:

import tfp410

hdmi = tfp410.TFP410()

إذا كنت تريد مخرج HDMI فقط ولا يهمك شاشة LCD على اللوحة، أطفئ الإضاءة الخلفية وارفع دقة مخزن الإطارات فوق WVGA. يدعم TFP410 حتى دقة 1280×720 بتردد 60 Hz، فعلى سبيل المثال:

lcd = display.RGBDisplay(framesize=display.HD, refresh=60)
lcd.backlight(False)         # the on‑board LCD can't render HD
hdmi = tfp410.TFP410()

اللوحة الموجودة على اللوحة الإلكترونية ثابتة عند دقة 800×480، لذا فإن أي دقة أعلى من WVGA لها معنى فقط على شاشة HDMI الخارجية.

لمعرفة متى تم توصيل شاشة HDMI أو فصلها، سجّل دالة رد نداء للتوصيل السريع على TFP410. تُطلَق دالة رد النداء بقيمة True عند التوصيل وFalse عند الفصل:

def on_hotplug(connected):
    print("HDMI", "connected" if connected else "disconnected")

hdmi.hotplug_callback(on_hotplug)

يمكنك أيضاً استطلاع حالة الاتصال في أي وقت باستخدام isconnected() (فقط عند عدم تسجيل دالة رد نداء).

يحمل منفذ HDMI أيضاً قناتي DDC (بيانات العرض) وCEC (التحكم بالإلكترونيات الاستهلاكية)، المعروضتين عبر صنف class DisplayData -- بيانات العرض. استخدمه لقراءة كتلة EDID الخاصة بالشاشة الموصولة (لتتمكن من التكيف مع دقتها الأصلية / معدل تحديثها) أو لإرسال/استقبال إطارات CEC للتحكم بأجهزة HDMI أخرى على السلك نفسه:

from display import DisplayData

dd = DisplayData(cec=True, ddc=True)

edid = dd.display_id()        # EDID bytes from the monitor
print(len(edid), "byte EDID")

# Send a CEC "image view on" command (opcode 0x04) from address 1 to address 0
dd.send_frame(0, 1, b"\x04")

# ...or wait for an incoming CEC frame addressed to us (logical address 1)
src, data = dd.receive_frame(1, timeout=5_000)
print("CEC from", src, ":", data)

Wi‑Fi

يعمل Wi‑Fi عبر وحدة Microchip WINC1500، المعروضة عبر واجهة class WINC -- مشغّل درع WiFi

import network, time

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

ملاحظة

بسبب نقص في القطع، شُحنت بعض وحدات Pure Thermal دون تركيب وحدة WINC1500. إذا أطلقت network.WINC خطأً أو لم تتصل مطلقاً، تحقق من اللوحة بحثاً عن وحدة Wi‑Fi مفقودة — تعمل بقية الكاميرا بالطريقة نفسها تماماً بدونها.

بطاقة microSD

عند إدخال بطاقة، تُركَّب تلقائياً عند /sdcard وتكون قابلة للاستخدام عبر نظام الملفات العادي:

import os

for entry in os.listdir("/sdcard"):
    print(entry)

مرجع النواقل

GPIO

استخدم machine.Pin لقراءة أو دفع أي من الدبابيس المطبوعة بالحرير. المخارج بمنطق CMOS بجهد 3.3 فولت، تتحمل 5 فولت على جانب الإدخال، ويمكنها سحب/مصدرة حتى 25 mA لكل دبوس (120 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

UART1

P1

P0

UART3

P4

P5

from machine import UART

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

I²C

الناقل

SCL

SDA

I2C2

P4

P5

I2C4

P7

P8

from machine import I2C

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

يمكن أيضاً استخدام العتاد نفسه في وضع الهدف (التابع) عبر machine.I2CTarget لعرض منطقة ذاكرة لمتحكم I²C آخر:

from machine import I2CTarget

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

يُخرج موصّل Qwiic على اللوحة أحد ناقلي I²C هذين للوحدات الجاهزة للتوصيل والتشغيل. خط Qwiic مُحوَّل المستوى إلى 5 فولت عبر ترانزستورات مفتوحة المصرف، لذا فإن الناقل محدود بـ الوضع القياسي (100 kHz) والوضع السريع (400 kHz) فقط — لا تحاول تشغيل الوضع السريع‑بلس أو معدلات أعلى عبر ترويسة Qwiic.

يُخرج موصّل Qwiic جهد 5 فولت لتغذية الوحدات الموصولة؛ ولا يمكن استخدامه لتغذية Pure Thermal نفسها — شغّل اللوحة بدلاً من ذلك عبر USB‑C أو موصّل بطارية LiPo.

SPI

الناقل

MOSI

MISO

SCK

CS

SPI2

P0

P1

P2

P3

from machine import SPI
from machine import Pin

spi = SPI(2, 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)

CAN (FDCAN)

الناقل

TX

RX

FDCAN2

P2

P3

from machine import CAN

can = CAN(2, 500_000)
can.set_filters(None)
can.send(0x123, b"\xDE\xAD\xBE\xEF")
print(can.recv())

ADC وDAC

إن P6 هو دبوس المستخدم التناظري الوحيد. يمكن استخدامه إما كمدخل ADC بدقة 12‑بت أو كمخرج DAC.

  • ADC — المقياس الكامل عند 3.3 فولت على الدبوس:

    from machine import ADC
    import time
    
    adc = ADC("P6")
    while True:
        voltage = adc.read_u16() * 3.3 / 65535
        print(voltage)
        time.sleep_ms(100)
    
  • DAC — عبر pyb.DAC. تغطي القيمة ذات 8‑بت النطاق من 0 إلى 3.3 فولت:

    from pyb import DAC
    
    dac = DAC("P6")
    voltage = 1.65
    dac.write(int(voltage / 3.3 * 255))
    

في وضع ADC أو DAC، فإن P6 يتحمل 3.3 فولت فقط — لا تُغذّه بـ 5 فولت.

PWM

الدبوس

المؤقت / القناة

P4

TIM2 CH3

P5

TIM2 CH4

P6

TIM2 CH1

P7

TIM4 CH1

P8

TIM4 CH2

ملاحظة

TIM1 محجوز من قبل البرنامج الثابت لتوليد ساعة بكسل مستشعر الكاميرا، لذا فإن قنوات TIM1 الموجودة فعلياً على P0/P1/P2 لا يمكن استخدامها لـ PWM الخاص بالمستخدم دون تعطيل الكاميرا.

TIM4 مشترك مع pyb.Servo — إنشاء نسخة من servo يعيد ضبط المؤقت بأكمله للعمل عند 50 Hz، لذا لا تخلط بين machine.PWM على P7/P8 وpyb.Servo في البرنامج النصي نفسه.

ادفع أياً منها عبر machine.PWM

from machine import Pin, PWM

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

النواقل المُحاكاة برمجياً ببرمجة البتات

تعمل machine.SoftI2C وmachine.SoftSPI على أي GPIO إذا احتجت إلى ناقل إضافي.

المستشعر الحراري (خارج اللوحة)

بالإضافة إلى FLIR Lepton على اللوحة، يتضمن البرنامج الثابت أيضاً مُشغّل fir --- مشغّل المستشعر الحراري (fir == far infrared) لأجهزة التصوير الحراري عبر I²C الموصولة خارجياً:

  • MLX90621 — مصفوفة أشعة تحت حمراء 16 × 4

  • MLX90640 — مصفوفة أشعة تحت حمراء 32 × 24

  • MLX90641 — مصفوفة أشعة تحت حمراء 16 × 12

  • 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 2 — وصّل الوحدة إلى P4 (SCL) وP5 (SDA).

التوقيت

time

import time

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

start = time.ticks_ms()
elapsed = time.ticks_diff(time.ticks_ms(), start)

المؤقتات الافتراضية

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() لإيقاف الخانة وتحريرها.

ساعة الوقت الحقيقي

from machine import RTC

rtc = RTC()
rtc.datetime((2026, 4, 30, 4, 12, 0, 0, 0))
print(rtc.datetime())

إذا كانت بطارية LiPo موصولة، تحافظ RTC على الوقت حتى أثناء إيقاف خطوط طاقة النظام (مُطفأة عبر زر الطاقة على اللوحة). أما مع توصيل USB فقط، فإن الضغط على زر الطاقة يقطع الطاقة عن RTC أيضاً — لذا لن يبقى وقت الساعة الحائطية بعد دورة طاقة دون بطارية موصولة.

كلب الحراسة (Watchdog)

from machine import WDT

wdt = WDT(timeout=5_000)
while True:
    # ...do work...
    wdt.feed()

معلومات الإقلاع ووقت التشغيل

نافذة محمّل إقلاع USB

عند كل تشغيل، تشغّل الكاميرا محمّل إقلاع قصير (بضع ثوانٍ) يسمح لـ OpenMV IDE بتحديث البرنامج الثابت دون اضطرار المستخدم للدخول إلى وضع DFU. بعد انقضاء النافذة، يسلّم محمّل الإقلاع المهمة إلى boot.py ثم main.py.

يمكن لبرنامج نصي قيد التشغيل إعادة الدخول إلى محمّل الإقلاع عند الطلب باستدعاء machine.bootloader().

نظام الملفات وترتيب الإقلاع

يركّب البرنامج الثابت لـ Pure Thermal ما يصل إلى ثلاثة أنظمة ملفات عند الإقلاع:

  • الفلاش الداخلي — مُركَّب دائماً عند /flash. يحتوي على main.py وREADME.txt افتراضياً؛ يُنشأ عند أول إقلاع على الإطلاق.

  • بطاقة microSD — إذا أُدخلت بطاقة، تُركَّب عند /sdcard.

  • ROMFS — نظام ملفات للقراءة فقط ومُسقَط في الذاكرة عند /rom يُستخدم لشحن أصول البيانات الكبيرة (مثل نماذج الذكاء الاصطناعي) التي تستفيد من الوصول دون نسخ. يُركَّب تلقائياً بواسطة MicroPython عند بدء التشغيل، قبل تشغيل أي كود Python للمستخدم.

بعد التركيب، يُضبط دليل العمل على /sdcard عند وجود البطاقة، وإلا فعلى /flash. ثم يشغّل المفسّر البرامج النصية من ذلك الدليل:

  • يُنفَّذ boot.py عند كل إعادة ضبط ناعمة.

  • يُنفَّذ main.py فقط عند الإقلاع البارد، مباشرة بعد boot.py.

إن وضع boot.py أو main.py على بطاقة SD يتجاوز النسخة الموجودة في الفلاش دون المساس بها.

عند الاتصال عبر USB، يظهر نظام ملفات الإقلاع (/sdcard إن وُجدت بطاقة، وإلا فـ /flash) أيضاً كقرص تخزين USB على المضيف. أخرج القرص قبل إعادة ضبط الكاميرا حتى يفرغ المضيف عمليات الكتابة المخزّنة لديه.

ملاحظة

لن تظهر الملفات التي يُنشئها أو يعدّلها الكود الذي يعمل على OpenMV Cam على المضيف حتى تُعاد عملية تركيب القرص. استخدم بطاقة SD لأي بيانات يكتبها البرنامج النصي، وأعد تركيبها قبل قراءة تلك الملفات من المضيف.

أحجام التخزين

تُشحن Pure Thermal مع:

  • /flash — نظام ملفات FAT بحجم 24 MB، للقراءة/الكتابة.

  • /rom — نظام ملفات ROMFS مُسقَط في الذاكرة وللقراءة فقط بحجم 8 MB، يُستخدم لشحن البرامج النصية ونماذج تعلّم الآلة التي تستفيد من الوصول عبر mmap دون نسخ.

  • /sdcard — الحجم الكامل لأي بطاقة microSD مُدخلة (عند وجودها)، للقراءة/الكتابة.

مؤشر الخطأ الفادح

إذا كان مؤشر LED RGB للمستخدم يتنقل بسرعة عبر جميع الألوان — بسرعة كافية بحيث يبدو وكأنه مؤشر LED أبيض متلألئ بدلاً من ألوان متميزة — فهذا يعني أن البرنامج الثابت قد اصطدم بخطأ فادح غير قابل للاسترداد. أعد تحميل البرنامج الثابت للاسترداد.

قائمة أخطاء العتاد

تُوثَّق حفنة من المراوغات على مستوى اللوحة في قائمة أخطاء عتاد Pure Thermal. أبرز العناصر التي ينبغي الانتباه إليها:

  • تداخل موصّل البطارية — تجلس مكوّنات على لوحة الدارة المطبوعة مباشرة أسفل موصّل بطارية LiPo، ويمكن للإسفين البارز على قابس كابل البطارية أن يعلق بها عند إزالة الكابل، مما يقتلع أحياناً قطعاً من اللوحة. اقطع الإسفين عن قابس الكابل بقصّافة مسطّحة قبل أول استخدام.

  • تتوقف RTC أثناء إيقاف تشغيل اللوحة — سعة الحمل على بلورة 32 kHz (Y2) عالية جداً. تتيح إزالة C96 وC97 (الزوج المحيط بالبلورة بجوار STM32) استمرار عمل RTC على طاقة الاحتياط. تُشحن معظم اللوحات مع إزالة هذين المكثفين مسبقاً؛ إذا فقدت RTC الوقت عند فصل الطاقة، فتحقق من هذين الموضعين. راجع مشكلتي GitHub #1536 و#1600 للاطلاع على النقاش الكامل.

  • يبقى مؤشر LED للشحن أزرق — قد ينهي الشاحن دورة شحنه في أي نقطة بين 4.15 فولت و4.19 فولت دون قلب المؤشر من الأزرق (قيد الشحن) إلى الأخضر (مشحون). تبقى البطارية مشحونة بالكامل في هذه الحالة؛ فثق بقياس الجهد، لا بمؤشر LED.

  • يضع الطبع بالحرير وسماً خاطئاً لـ VIN على أنه VBAT — الوسادة في موضع VIN القياسي لترويسة OpenMV مطبوعة بالحرير VBAT على Pure Thermal. الوسم خاطئ، لكنه لا يهم عملياً لأن الوسادة ليس لها أي اتصال كهربائي في كلتا الحالتين.

مكتبات البرامج

راجع فهرس المكتبات للاطلاع على القائمة الكاملة للوحدات — بما في ذلك تلك الفريدة لبنية Pure Thermal.