Arduino Portenta H7

إن Arduino Portenta H7 هي لوحة تطوير صناعية بأبعاد 66 × 25 مم مبنية حول STMicroelectronics STM32H747XI — وهو نظام على شريحة ثنائي النواة يجمع بين Cortex‑M7 بتردد 400 ميجاهرتز ونواة Cortex‑M4 بتردد 200 ميجاهرتز. يعمل البرنامج الثابت من OpenMV بالكامل على نواة M7 وقد صُمم ليُستخدم مع Portenta Vision Shield (إصدار Ethernet أو LoRa)، الذي يضيف كاميرا Himax HM01B0 / HM0360 وميكروفونين رقميين من نوع PDM وفتحة microSD إلى لوحة Portenta H7 الأساسية.

Arduino Portenta H7

للاطلاع على ورقة البيانات الكاملة والصور والأبعاد، راجع صفحة منتج Arduino Portenta H7.

أبرز الميزات

  • STMicroelectronics STM32H747XI ثنائي النواة Cortex‑M7 (400 ميجاهرتز) + Cortex‑M4 (200 ميجاهرتز). يعمل البرنامج الثابت من OpenMV على نواة M7 فقط؛ أما نواة M4 فهي متاحة عبر openamp للاتصال بين المعالجات.

  • ذاكرة SDRAM خارجية بسعة 8 ميجابايت إضافة إلى ذاكرة فلاش داخلية بسعة 2 ميجابايت وذاكرة فلاش QSPI خارجية بسعة 16 ميجابايت.

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

  • Wi‑Fi b/g/n (2.4 جيجاهرتز) + Bluetooth LE 5.1 عبر وحدة Murata 1DX (CYW4343W) — تتصل بالهوائي المرفق عبر موصّل U.FL مدمج على اللوحة.

  • USB‑C عالي السرعة (480 ميجابت/ثانية).

  • 22 دبوس إدخال/إخراج للمستخدم على رؤوس التوصيل العلوية بنمط Arduino MKR — من D0 إلى D14 (رقمية) إضافة إلى A0 إلى A6 (تماثلية).

  • موصّلان عالي الكثافة بـ 80 دبوسًا في الأسفل يكشفان عن البنية الكاملة لـ STM32H747 — DCMI وDSI وEthernet RMII وFDCAN وSDIO وSAI/I²S وUARTs وSPI/I²C/مؤقتات إضافية، وما إلى ذلك. تتصل الدروع مثل Vision Shield بهذه الموصّلات.

  • JTAG / SWD متاحان على موصّلات عالية الكثافة في الأسفل لأغراض التصحيح المتقدمة.

  • دعم البطارية — موصّل JST لبطارية Li‑Po بجهد 3.7 فولت إضافة إلى شاحن ومراقب بطارية مدمجين على اللوحة.

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

Arduino Portenta H7 Pinout

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

تُتاح 22 دبوسًا للمستخدم على رؤوس التوصيل العلوية بنمط Arduino MKR — 15 رقميًا (D0-D14) إضافة إلى 7 تماثلية (A0-A6). يتوفر عدد أكبر بكثير من دبابيس النظام على شريحة عبر الموصّلات عالية الكثافة بـ 80 دبوسًا في الأسفل لأعمال الدروع؛ راجع ملف PDF لمخطط الدبابيس الكامل من Arduino لهذا التخطيط.

اسم الدبوس

المرجع

الوظيفة

D0

3.3 V

TIM8 CH3N

D1

3.3 V

TIM1 CH1 / SPI5 NSS

D2

3.3 V

TIM1 CH2 / SPI5 MISO

D3

3.3 V

GPIO

D4

3.3 V

TIM3 CH2 / TIM8 CH2 / USART6 RX

D5

3.3 V

TIM3 CH1 / TIM8 CH1 / USART6 TX

D6

3.3 V

TIM1 CH1 / I2C3 SCL

D7

3.3 V

TIM5 CH4 / SPI2 NSS

D8

3.3 V

SPI2 MOSI (مشترك مع A3 / A5)

D9

3.3 V

SPI2 SCK

D10

3.3 V

SPI2 MISO (مشترك مع A2 / A4)

D11

3.3 V

I2C3 SDA

D12

3.3 V

I2C3 SCL

D13

3.3 V

USART1 RX / TIM1 CH3

D14

3.3 V

USART1 TX / TIM1 CH2

A0

3.3 V

ADC12 IN0 (تماثلي فقط)

A1

3.3 V

ADC12 IN1 (تماثلي فقط)

A2

3.3 V

ADC123 IN12 (تماثلي فقط؛ مشترك مع D10)

A3

3.3 V

ADC12 IN13 (تماثلي فقط؛ مشترك مع D8)

A4

3.3 V

ADC123 IN12 (مشترك مع D10)

A5

3.3 V

ADC12 IN13 (مشترك مع D8)

A6

3.3 V

DAC1 OUT1 / ADC12 IN18

A7

3.3 V

TIM3 CH1 / ADC12 IN3 (غير متاح على رؤوس التوصيل)

D20

3.3 V

اسم بديل لـ D8 / A3 / A5

D21

3.3 V

اسم بديل لـ A6 — DAC1 OUT1

RESET

3.3 V

اضغط المفتاح المدمج على اللوحة أو اسحب الدبوس إلى GND لإعادة التعيين

LED_RED

3.3 V

القناة الحمراء للـ RGB LED (نشطة عند المستوى المنخفض)

LED_GREEN

3.3 V

القناة الخضراء للـ RGB LED (نشطة عند المستوى المنخفض)

LED_BLUE

3.3 V

القناة الزرقاء للـ RGB LED (نشطة عند المستوى المنخفض)

ملاحظة

إن A0-A3 هي وسادات تماثلية فقط على STM32H747 من دون وظيفة GPIO — تعامل معها كمدخلات ADC فقط. تتشارك A2/A4 وA3/A5 دبابيسها المادية مع D10 وD8 على التوالي، لذا لا يمكنك تشغيل PWM أو SPI عليها أثناء قراءتها كقيم تماثلية. أما A7 فتقع على الموصّلات عالية الكثافة في الأسفل.

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

دبابيس رأس التوصيل MKR:

  • VIN — قضيب النظام الرئيسي المغذّي لدائرة PMIC المدمجة على اللوحة. يُغذّى عبر صمام ثنائي من قضيب +5V أو دبوس MKR VIN أو الموصّلات عالية الكثافة بـ 80 دبوسًا في الأسفل.

  • +5V — قضيب 5 فولت مُغذّى من USB أو موصّل ESLOV أو دبوس MKR +5V نفسه.

  • +3V3 — قضيب 3.3 فولت الرئيسي (خرج منظّم التبديل في PMIC).

  • AREF — الجهد المرجعي التماثلي لدبابيس ADC. القيمة الافتراضية 3.3 فولت؛ قُد الدبوس خارجيًا لاستخدام مرجع مختلف.

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

دخل البطارية:

  • موصّل JST لبطارية Li‑Po في مقدمة اللوحة يقبل خلية Li‑Po بجهد 3.7 فولت. تشحنها دائرة PMIC كلما كان +5V أو VIN متوفرًا.

يمكن تشغيل Portenta H7 عبر أي من هذه المسارات:

  • USB‑C — يوفّر 5 فولت لدائرة PMIC المدمجة على اللوحة.

  • موصّل ESLOV — حتى 5 فولت على VESLOV (راجع موصّل ESLOV).

  • دبوس VIN — قُد مصدر تغذية منظّم بجهد 5 فولت مباشرة.

  • بطارية Li‑Po — صِلها بموصّل JST في المقدمة.

موصّل ESLOV

على جانب اللوحة يوجد موصّل ESLOV بخمسة دبابيس لا يتطلب لحامًا:

الدبوس

الاسم

الوظيفة

1

VESLOV

خرج طاقة 5 فولت (القضيب نفسه الخاص بـ +5V في رأس التوصيل MKR)

2

INT

مدخل مقاطعة خارجية على D7

3

SCL_EXT

مشترك مع وسادة D12 في رأس التوصيل MKR — نفس ناقل I²C 3 الخاص برأس توصيل المستخدم

4

SDA_EXT

مشترك مع وسادة D11 في رأس التوصيل MKR — نفس ناقل I²C 3 الخاص برأس توصيل المستخدم

5

GND

الأرضي المشترك

إن SCL_EXT/SDA_EXT في ESLOV وD12/D11 في رأس التوصيل MKR هي الدبابيس نفسها — ناقل I²C 3 واحد متاح على موصّلين.

نصيحة

استخدم مُقدّر عمر البطارية لتقدير المدة التي ستعمل فيها Portenta H7 على البطارية ضمن دورة عمل معينة بين الحالة النشطة والسبات العميق.

دبابيس الاستعادة والتصحيح

  • RESET — دبوس متاح على رأس التوصيل العلوي ومفتاح لحظي على جانب اللوحة في آنٍ معًا، مرتبط بخط NRST الخاص بالنظام على شريحة. اسحب الدبوس إلى GND أو اضغط الزر لإعادة التعيين.

تستخدم Portenta H7 آلية النقر المزدوج لإعادة التعيين القياسية من Arduino للدخول إلى محمّل إقلاع Arduino. اضغط زر إعادة التعيين مرتين بسرعة — تُعاد اللوحة للظهور عبر USB كجهاز DFU ويستطيع OpenMV IDE تحميل صورة برنامج ثابت جديدة.

إشارات SWD الخاصة بـ STM32 متاحة على الموصّل عالي الكثافة J1 في الأسفل:

  • J1‑73 — NRST

  • J1‑75 — SWDIO (PA13)

  • J1‑77 — SWCLK (PA14)

  • J1‑79 — SWO (PB3)

صِلها عبر Portenta Breakout أو مُحوّل التصحيح الرسمي من Arduino أو لوحة حاملة مخصّصة برأس توصيل بمسافة 1.27 مم. جميع إشارات التصحيح مرجعها 3.3 فولت.

ملاحظة

عند توصيل Portenta Vision Shield، تُوجَّه إشارات SWD/JTAG نفسها إلى رأس توصيل ARM Cortex Debug JTAG القياسي بـ 20 دبوسًا على الدرع (بمسافة 1.27 مم / 0.05 بوصة).

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

مصابيح LED

تحتوي Portenta H7 على RGB LED واحد للمستخدم، يمكن التحكم فيه برمجيًا عبر machine.LED

from machine import LED

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

يضيء مصباح الشحن البرتقالي المنفصل بجوار موصّل JST للبطارية عندما يضخّ الشاحن المدمج على اللوحة تيارًا إلى بطارية Li‑Po موصولة؛ وهو غير قابل للتحكم من قِبل المستخدم.

مستشعر الكاميرا (Vision Shield)

عند توصيل Portenta Vision Shield (إصدار Ethernet أو LoRa)، يُشغَّل مستشعر Himax عبر وحدة csi --- مستشعرات الكاميرا

import csi

cam = csi.CSI()
cam.reset()
cam.pixformat(csi.GRAYSCALE)
cam.framesize(csi.QVGA)
cam.snapshot(time=2000)       # let auto‑exposure settle

while True:
    img = cam.snapshot()

يُدعَم إصداران من Vision Shield:

  • HM01B0 — أحادي اللون بدقة 320 × 320.

  • HM0360 — أحادي اللون بدقة 640 × 480.

تحذير

أثناء تهيئة كاميرا Vision Shield، يطالب البرنامج الثابت بدبابيس رأس التوصيل MKR التالية ولا يمكن استخدامها:

دبوس MKR

السبب

D1

TIM1 CH1 — ساعة الكاميرا الرئيسية

D6

TIM1 CH1 (بديل) — ساعة الكاميرا الرئيسية

D11

I²C 3 SDA — مشترك مع الكاميرا؛ الناقل قابل للاستخدام لكن تجنّب عنوان I²C الخاص بالمستشعر (0x24)

D12

I²C 3 SCL — مشترك مع الكاميرا؛ الناقل قابل للاستخدام لكن تجنّب عنوان I²C الخاص بالمستشعر (0x24)

A6 / D21

DCMI HSYNC — يعطّل أيضًا DAC

A7

DCMI PXCLK

تعلّم الآلة

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

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

# Initialize the sensor.
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.GRAYSCALE)
csi0.framesize(csi.QVGA)
csi0.window((240, 240))

# 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)
        ml.utils.draw_keypoints(img, keypoints, color=(255, 0, 0))

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

نواة M4

نواة Cortex‑M4 متاحة عبر openamp للاتصال بين المعالجات. يعمل البرنامج الثابت من OpenMV على نواة M7 فقط؛ ولا تملك نواة M4 بيئة تشغيل MicroPython خاصة بها، لذا فإن استخدامها يعني بناء صورة برنامج ثابت منفصلة بلغة C وتحميلها من نظام الملفات عبر openamp.RemoteProc. يتوفر برنامج ثابت تجريبي مبني مسبقًا يُنفّذ نقطة طرفية لـ UART افتراضي في مستودع openamp_vuart — اتبع ملف README الخاص به لبناء vuart.elf

import openamp
import time

def ept_recv_callback(src_addr, data):
    print("Received:", data.decode())

ept = openamp.Endpoint("vuart-channel", callback=ept_recv_callback)

rproc = openamp.RemoteProc("vuart.elf")
rproc.start()

count = 0
while True:
    if ept.is_ready():
        ept.send("Hello World %d!" % count, timeout=1000)
        count += 1
    time.sleep_ms(1000)

في الواقع العملي، يُفضَّل التعامل مع هذا الدعم كعرض توضيحي لواجهة openamp بدلًا من اعتباره منصة ثنائية النواة عاملة — إذ لا يمكن إعادة تعيين نواة M4 بشكل مستقل عن نواة M7، لذا فإن إيقاف M4 يفرض إعادة تشغيل كاملة للنظام.

الميكروفون (Vision Shield)

يحمل Vision Shield ميكروفونين رقميين من نوع PDM يُلتقطان عبر audio --- وحدة الصوت من خلال طرفية SAI4 الخاصة بـ STM32. يصل كل مخزن مؤقت كبيانات PCM ذات 16 بت مع إشارة على هيئة bytearray، جاهزة لتغذيتها إلى ulab/numpy لمعالجة الإشارات الرقمية — على سبيل المثال كاشف صوت بسيط للجهارة:

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

مرّر channels=2 إلى audio.init لاستقبال عينات متشابكة من كلا الميكروفونين.

مقياس شحن البطارية

يتتبع مقياس الشحن MAX17262 من Maxim بتقنية ModelGauge m5 جهد بطارية Li‑Po وتيارها ودرجة حرارتها وحالة شحنها. وهو موجود على I²C 1 عند العنوان 0x36.

يمتلك MAX17262 استشعار تيار داخلي، لذا فإن سجل التيار يُقرأ مباشرة بوحدة الميكروأمبير من دون الحاجة إلى تطبيق عامل Rsense خارجي. إن قراءة مقياس الشحن غير مؤذية — لا يُشحَن أي مشغّل معه، لكن يمكن قراءة السجلات الموثقة في ورقة بيانات MAX17262 مباشرة:

import time
import struct
from machine import I2C

FUEL_GAUGE = 0x36   # MAX17262

def read_reg(bus, addr, reg):
    return struct.unpack("<H", bus.readfrom_mem(addr, reg, 2))[0]

def read_signed(bus, addr, reg):
    v = read_reg(bus, addr, reg)
    return v - 0x10000 if v & 0x8000 else v

bus = I2C(1)

while True:
    # 0x05 RepCap — remaining capacity, raw × 0.5 mAh
    rep_cap   = read_reg(bus, FUEL_GAUGE, 0x05) * 0.5
    # 0x06 RepSOC — state of charge, raw / 256 %
    soc       = read_reg(bus, FUEL_GAUGE, 0x06) / 256
    # 0x08 Temp — die temperature, signed, raw / 256 °C
    temp      = read_signed(bus, FUEL_GAUGE, 0x08) / 256
    # 0x09 VCell — battery voltage, raw × 78.125 µV
    vcell     = read_reg(bus, FUEL_GAUGE, 0x09) * 78.125 / 1_000_000
    # 0x0A Current — signed, raw × 156.25 µA
    current   = read_signed(bus, FUEL_GAUGE, 0x0A) * 156.25 / 1000
    # 0x0B AvgCurrent — averaged current
    avg_curr  = read_signed(bus, FUEL_GAUGE, 0x0B) * 156.25 / 1000
    # 0x10 FullCapRep — learned full capacity, raw × 0.5 mAh
    full_cap  = read_reg(bus, FUEL_GAUGE, 0x10) * 0.5
    # 0x11 TTE — time-to-empty (valid while discharging), raw × 5.625 s
    tte_s     = read_reg(bus, FUEL_GAUGE, 0x11) * 5.625
    # 0x20 TTF — time-to-full   (valid while charging),  raw × 5.625 s
    ttf_s     = read_reg(bus, FUEL_GAUGE, 0x20) * 5.625
    # 0x17 Cycles — charge-cycle counter, 1% per LSB
    cycles    = read_reg(bus, FUEL_GAUGE, 0x17) / 100

    print("V:        %.3f V" % vcell)
    print("Capacity: %.1f / %.1f mAh (%.1f %%)" % (rep_cap, full_cap, soc))
    print("Temp:     %.1f C" % temp)
    print("Current:  %.1f mA  (avg %.1f mA)" % (current, avg_curr))
    print("TTE:      %.0f s   TTF: %.0f s" % (tte_s, ttf_s))
    print("Cycles:   %.2f" % cycles)
    print()
    time.sleep_ms(1000)

إن Current بقيمة متمّمة لاثنين مع إشارة: موجبة أثناء الشحن، وسالبة أثناء التفريغ. ولا يكون TTE ذا معنى إلا عندما يكون التيار سالبًا؛ بينما TTF يكون ذا معنى فقط عندما يكون التيار موجبًا.

دائرة إدارة الطاقة

تتولى دائرة PMIC من نوع PF1550 من NXP إدارة كل منظّم على Portenta H7 — قضيب +3V3 الرئيسي، وقضيب +1V8 لنواة النظام على شريحة/الإدخال والإخراج، وشاحن Li‑Po. وهي موجودة على I²C 1 عند العنوان 0x08.

تحذير

قراءة سجلات PMIC أمر آمن؛ أما الكتابة إليها فخطيرة. يمكن أن يؤدي الإعداد الخاطئ لمنظّم خفض الجهد أو إعداد الشاحن إلى تلف دائم في اللوحة أو البطارية أو كليهما. تعامل مع PMIC على أنها للقراءة فقط ما لم تكن تعرف تمامًا ما تفعله.

أنفع ما تخبرك به PMIC ولا يستطيع مقياس الشحن إخبارك به هو آلة حالات الشاحن — أي ما إذا كانت اللوحة تعمل حاليًا على USB / ESLOV / VIN، وفي أي مرحلة من دورة الشحن توجد بطارية Li‑Po، وما إذا كان الشاحن في خطأ حراري أو خطأ مراقب. تقع سجلات الشاحن عند إزاحة 0x80 ضمن مساحة عنوان I²C الرئيسية لـ PF1550 (راجع §22.2 من ورقة بيانات PF1550)، فعلى سبيل المثال يُقرأ CHG_INT_OK عند عنوان الشاحن 0x04 من سجل PMIC 0x84

import time
from machine import I2C

PMIC = 0x08

# Charger state machine (low nibble of CHG_SNS, register 0x87)
CHG_STATES = {
    0x0: "precharge",
    0x1: "fast charge (constant current)",
    0x2: "fast charge (constant voltage)",
    0x3: "end of charge",
    0x4: "done",
    0x6: "timer fault",
    0x7: "thermistor suspend",
    0x8: "off — input invalid or charger disabled",
    0x9: "battery overvoltage",
    0xA: "thermal shutdown",
    0xC: "linear mode (not charging)",
}

bus = I2C(1)

while True:
    # 0x84 CHG_INT_OK — single-bit indicators
    ok = bus.readfrom_mem(PMIC, 0x84, 1)[0]
    vbus_ok = bool(ok & (1 << 5))   # bit 5 — VBUS valid (USB/VIN)
    bat_ok  = bool(ok & (1 << 2))   # bit 2 — battery OK
    chg_ok  = bool(ok & (1 << 3))   # bit 3 — charger actively charging
    thm_ok  = bool(ok & (1 << 7))   # bit 7 — thermistor in normal range

    # 0x87 CHG_SNS — charger state + thermal regulation flag
    chg_sns = bus.readfrom_mem(PMIC, 0x87, 1)[0]
    state   = CHG_STATES.get(chg_sns & 0x0F, "reserved")
    treg    = bool(chg_sns & (1 << 7))   # thermal regulation active

    print("VBUS valid:         ", vbus_ok)
    print("battery OK:         ", bat_ok)
    print("charger active:     ", chg_ok)
    print("thermistor normal:  ", thm_ok)
    print("thermal reg active: ", treg)
    print("state:              ", state)
    print()
    time.sleep_ms(1000)

سجلات أخرى للقراءة فقط تستحق الاطلاع عليها في ورقة البيانات (جميعها عند إزاحة الشاحن 0x80): 0x80 CHG_INT (مقاطعات الشاحن المثبَّتة — أعلام الأخطاء)، و0x86 VBUS_SNS (حالة VBUS متعددة البتات بما في ذلك OVLO / UVLO / DPM)، و0x88 BATT_SNS (وجود البطارية وحالة التيار الزائد).

Wi‑Fi

وحدة Murata 1DX (CYW4343W) المدمجة على اللوحة متاحة عبر network --- تهيئة الشبكة كواجهة محطة. صِل الهوائي المرفق بـ موصّل U.FL المدمج على اللوحة قبل تشغيل الراديو:

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

تكشف وحدة Murata 1DX نفسها أيضًا عن Bluetooth LE 5.1. استخدم aioble --- BLE غير المتزامن للحصول على BLE متوافق مع asyncio — على سبيل المثال، أعلن عن الجهاز كطرفية وانتظر اتصال جهاز مركزي:

import asyncio
import aioble

async def run():
    while True:
        conn = await aioble.advertise(250_000, name="Portenta-H7")
        print("Connected:", conn.device)
        await conn.disconnected()

asyncio.run(run())

LoRa (Vision Shield)

يضيف إصدار LoRa من Vision Shield وحدة Murata CMWX1ZZABZ لشبكة LoRaWAN موصولة بـ Portenta H7 عبر UART. تغلّف وحدة lora البرنامج الثابت لأوامر AT وتدعم الانضمام عبر OTAA أو ABP، والوصلة الصاعدة، والوصلة الهابطة:

from lora import Lora
from lora import BAND_EU868
from lora import LoraErrorTimeout

lora = Lora(band=BAND_EU868, poll_ms=60000)
print("Device EUI:", lora.get_device_eui())

appEui = "1234567890123456"
appKey = "12345678901234567890123456789012"

try:
    lora.join_OTAA(appEui, appKey)
except LoraErrorTimeout as e:
    print("Join timed out — try moving near a window:", e)

lora.set_port(3)
lora.send_data("HeLoRA world!", True)

while True:
    if lora.available():
        data = lora.receive_data()
        if data:
            print("Port:", data["port"], "Data:", data["data"])
    lora.poll()

استخدم BAND_US915 / BAND_AS923 / BAND_AU915 وغيرها للمناطق خارج الاتحاد الأوروبي، وبدّل إلى lora.Lora.join_ABP() إذا كان خادم شبكتك يستخدم تنشيط ABP.

تحذير

أثناء استخدام وحدة LoRa، يطالب المشغّل بدبابيس رأس التوصيل MKR التالية كخطوط تحكم لوحدة Murata CMWX1ZZABZ — ولا يمكن استخدامها:

دبوس MKR

السبب

D3

دبوس BOOT لوحدة LoRa

D5

دبوس RST لوحدة LoRa

Ethernet (Vision Shield)

يضيف إصدار Ethernet من Vision Shield مقبس RJ45 مع مغناطيسات موصولة بوحدة Ethernet MAC بسرعة 10/100 الخاصة بـ STM32H747 عبر RMII. صِل كابل Ethernet فيظهر طبقة PHY كواجهة LAN؛ ويعمل DHCP تلقائيًا بمجرد تفعيل الوصلة:

import network
import time

lan = network.LAN()
lan.active(True)
while not lan.isconnected():
    time.sleep(1)
print("Ethernet IP:", lan.ipconfig("addr4")[0])

بطاقة microSD (Vision Shield)

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

import os

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

مرجع النواقل

GPIO

استخدم machine.Pin لقراءة أو قيادة أي من الدبابيس المطبوعة على اللوحة. المخارج من نوع 3.3 فولت CMOS ويمكنها سحب/تزويد ما يصل إلى 20 مللي أمبير لكل دبوس (140 مللي أمبير إجمالًا عبر رأس التوصيل بأكمله).

from machine import Pin

out = Pin("D0", Pin.OUT)
out.on()
out.off()
out.value(1)

inp = Pin("D1", Pin.IN, Pin.PULL_UP)
print(inp.value())

يمكن لأي دبوس إدخال أيضًا إطلاق مقاطعة عند انتقالات الحافة:

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

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

UART

الناقل

TX

RX

UART1

D14

D13

UART6

D5

D4

from machine import UART

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

I²C

الناقل

SCL

SDA

I2C3

D12

D11

from machine import I2C

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

وسادتا D11/D12 على رأس التوصيل MKR ودبوسا SDA_EXT/SCL_EXT في موصّل ESLOV يقعان على ناقل I²C 3 نفسه — راجع موصّل ESLOV أعلاه لمخطط دبابيس ESLOV.

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

from machine import I2CTarget

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

SPI

الناقل

MOSI

MISO

SCK

CS

SPI2

D8

D10

D9

D7

from machine import SPI
from machine import Pin

spi = SPI(2, baudrate=10_000_000)
cs = Pin("D7", Pin.OUT, value=1)   # CS is not driven by the SPI peripheral

cs.value(0)
spi.write(b"hello")
cs.value(1)

ADC

تكشف Portenta H7 عن ثماني قنوات ADC بدقة 12 بت على A0–A7. جميعها مرجعها 3.3 فولت — يُرجِع read_u16 قيمة بين 0 و65535 عبر النطاق 0–3.3 فولت عند الدبوس:

from machine import ADC
import time

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

DAC

تُتاح قناة DAC واحدة بدقة 12 بت على DAC1 (A6 / D21) عبر pyb.DAC

from pyb import DAC

dac = DAC("DAC1")
dac.write(int(0.5 * 255))   # 8‑bit output, ~1.65 V

PWM

الدبوس

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

D0

TIM8 CH3N

D1

TIM1 CH1, TIM8 CH3N

D2

TIM1 CH2, TIM8 CH2N

D4

TIM3 CH2, TIM8 CH2

D5

TIM3 CH1, TIM8 CH1

D6

TIM1 CH1

D7

TIM5 CH4

D13

TIM1 CH3

D14

TIM1 CH2

A7

TIM3 CH1

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

from machine import Pin, PWM

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

ملاحظة

تتشارك عدة دبابيس قنوات المؤقتات:

  • TIM1 CH1 موجود على D1 و D6.

  • TIM1 CH2 موجود على D2 و D14.

  • TIM8 CH3N موجود على D0 و D1.

اختر مستهلكًا واحدًا لكل قناة مؤقت.

تحذير

إن TIM1 محجوز لـ ساعة الكاميرا الرئيسية عند تهيئة Vision Shield عبر csi --- مستشعرات الكاميرا — لا يمكن قيادة D1 وD2 وD6 وD13 وD14 بـ PWM أثناء نشاط الكاميرا.

النواقل البرمجية بأسلوب bit‑banging

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

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

يتضمن البرنامج الثابت مشغّل fir --- مشغّل المستشعر الحراري (fir == far infrared) للمصوّرات الحرارية الموصولة خارجيًا:

  • 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 3 فقط — صِل الوحدة بـ D12 (SCL) وD11 (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 على وقت الساعة الجدارية عبر عمليات إعادة التعيين. يكشف الموصّل عالي الكثافة أيضًا عن وسادة COINCELL يمكنها تغذية RTC من بطارية CR2032 عند انقطاع الطاقة:

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

مراقب التشغيل (Watchdog)

تعيد machine.WDT تعيين اللوحة إذا تعلّق التطبيق. وبمجرد بدء تشغيلها لا يمكن إيقافها أو إعادة تهيئتها — غذِّها بشكل دوري داخل حلقتك الرئيسية:

from machine import WDT

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

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

تحديث البرنامج الثابت (DFU)

تستخدم Portenta H7 آلية النقر المزدوج لإعادة التعيين القياسية من Arduino للدخول إلى محمّل إقلاع Arduino. اضغط زر إعادة التعيين مرتين بسرعة — تُعاد اللوحة للظهور عبر USB كجهاز DFU ويستطيع OpenMV IDE تحميل صورة برنامج ثابت جديدة.

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

import machine

machine.bootloader()

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

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

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

  • بطاقة microSD — إذا كان Vision Shield موصولًا وأُدخلت بطاقة، فإنها تُركَّب عند /sdcard.

  • ROMFS — نظام ملفات للقراءة فقط ومُربَط بالذاكرة عند /rom تركّبه MicroPython تلقائيًا عند بدء التشغيل.

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

  • يُنفَّذ boot.py عند كل إعادة تعيين ناعمة (الإقلاع البارد، أو Ctrl‑D من REPL، أو كلما عاد البرنامج النصي قيد التشغيل).

  • يُنفَّذ main.py فقط عند الإقلاع البارد، مباشرة بعد boot.py. أما عمليات إعادة التعيين الناعمة اللاحقة فتعيد تشغيل boot.py لكنها تنتقل مباشرة إلى REPL — ولإعادة تشغيل main.py عليك إعادة تعيين اللوحة بالكامل.

إن إسقاط ملف boot.py أو main.py على بطاقة SD يتجاوز النسخة الموجودة في الفلاش من دون المساس بها — إذ يُبحث عن كلا الملفين في دليل الإقلاع (/sdcard عند تركيب البطاقة، وإلا /flash).

يكتفي ملف main.py الافتراضي المُزوَّد على لوحة حُمِّل عليها البرنامج الثابت حديثًا بوميض القناة الزرقاء للـ RGB LED الخاص بالمستخدم كنبضة قلب (نبضتان قصيرتان، فاصل قصير)، فيمكنك معرفة أن البرنامج الثابت أقلع بشكل سليم من دون توصيل أي مضيف.

يُوسَّع sys.path ليشمل أنظمة الملفات الثلاثة جميعها وأدلتها الفرعية lib/، فيمكن أن توجد الوحدات القابلة للاستيراد في /flash/lib أو /sdcard/lib أو /rom/lib.

لإجبار النظام على تجاهل بطاقة SD مُدخلة (على سبيل المثال لتشغيل main.py الموجود في الفلاش حتى مع وجود بطاقة)، أنشئ ملفًا فارغًا باسم SKIPSD في جذر /flash.

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

ملاحظة

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

ملاحظة

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

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

تأتي Portenta H7 مزوّدة بـ:

  • /flash — نظام ملفات FAT بسعة 11 ميجابايت، للقراءة والكتابة.

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

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

مؤشر الخطأ الجسيم (Hard‑fault)

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

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

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