Arduino Portenta H7

ה‑Arduino Portenta H7 הוא לוח פיתוח תעשייתי בגודל 66 × 25 מ“מ הבנוי סביב STMicroelectronics STM32H747XI — שבב SoC דו‑ליבתי המשלב ליבת Cortex‑M7 ב‑400 MHz עם ליבת Cortex‑M4 ב‑200 MHz. קושחת OpenMV רצה כולה על ליבת ה‑M7 ותוכננה לשימוש עם ה‑Portenta Vision Shield (מהדורת Ethernet או LoRa), המוסיף מצלמת Himax HM01B0 / HM0360, זוג מיקרופוני PDM וחריץ microSD ללוח ה‑Portenta H7 הבסיסי.

Arduino Portenta H7

ל‑datasheet מלא, תמונות ומידות ראו את דף המוצר של Arduino Portenta H7.

עיקרי הדברים

  • STMicroelectronics STM32H747XI דו‑ליבתי Cortex‑M7 (400 MHz) + Cortex‑M4 (200 MHz). קושחת OpenMV רצה על ליבת ה‑M7 בלבד; ליבת ה‑M4 נחשפת דרך openamp עבור תקשורת בין‑מעבדים.

  • 8 MB של SDRAM חיצוני בתוספת 2 MB של flash פנימי ו‑16 MB של QSPI flash חיצוני.

  • מקודד/מפענח JPEG חומרתי.

  • Wi‑Fi b/g/n (2.4 GHz) + Bluetooth LE 5.1 דרך מודול Murata 1DX (CYW4343W) — מתחבר לאנטנה המצורפת דרך מחבר U.FL מובנה.

  • USB‑C במהירות גבוהה (480 Mb/s).

  • 22 פיני קלט/פלט למשתמש בכותרות העליונות בסגנון Arduino MKR — D0–D14 (דיגיטליים) בתוספת A0–A6 (אנלוגיים).

  • שני מחברים בצפיפות גבוהה של 80 פינים בתחתית חושפים את כל מארג ה‑STM32H747 — DCMI, DSI, Ethernet RMII, FDCAN, SDIO, SAI/I²S, ערוצי UART, SPI/I²C/טיימרים נוספים וכן הלאה. מגנים כמו ה‑Vision Shield מתחברים למחברים אלה.

  • JTAG / SWD מוצאים אל מחברי ה‑HD בתחתית עבור ניפוי שגיאות מתקדם.

  • תמיכה בסוללה — מחבר JST ל‑Li‑Po של 3.7 V בתוספת מטען ומנטר סוללה מובנים.

מפת פינים

Arduino Portenta H7 Pinout

סימוכין לפינים

22 פיני משתמש נחשפים בכותרות הקצה העליונות בסגנון Arduino MKR — 15 דיגיטליים (D0-D14) בתוספת 7 אנלוגיים (A0-A6). פינים רבים נוספים של ה‑SoC זמינים דרך מחברי ה‑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 נמצא על מחברי ה‑HD בתחתית.

פיני הספקה

פיני כותרת MKR:

  • VIN — מסילת המערכת הראשית אל ה‑PMIC המובנה. ניזונה דרך דיודה ממסילת ה‑+5V, מפין ה‑VIN של MKR, או ממחברי ה‑80 פינים HD בתחתית.

  • +5V — מסילת 5 V הניזונה מ‑USB, ממחבר ה‑ESLOV, או מפין ה‑+5V של MKR עצמו.

  • +3V3 — מסילת 3.3 V הראשית (פלט וסת מיתוג של ה‑PMIC).

  • AREF — מקור מתח ייחוס אנלוגי עבור פיני ה‑ADC. ברירת מחדל 3.3 V; הניעו חיצונית כדי להשתמש בייחוס אחר.

  • GND — הארקה משותפת.

כניסת סוללה:

  • JST ל‑Li‑Po בחזית הלוח מקבל תא Li‑Po של 3.7 V. ה‑PMIC טוען אותו בכל פעם ש‑+5V או VIN נוכחים.

ניתן להזין את ה‑Portenta H7 דרך כל אחת מהדרכים האלה:

  • USB‑C — מספק 5 V ל‑PMIC המובנה.

  • מחבר ESLOV — עד 5 V על VESLOV (ראו מחבר ESLOV).

  • פין VIN — הניעו ישירות אספקת 5 V מיוצבת.

  • סוללת Li‑Po — חברו ל‑JST שבחזית.

מחבר ESLOV

בצד הלוח נמצא מחבר ESLOV בן 5 פינים ללא הלחמה:

פין

שם

פונקציה

1

VESLOV

פלט הספק 5 V (אותה מסילה כמו ה‑+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 של ה‑SoC. משכו ל‑GND או לחצו על הכפתור כדי לאפס.

ה‑Portenta H7 משתמש ב‑איפוס לחיצה כפולה הסטנדרטי של Arduino כדי להיכנס ל‑bootloader של Arduino. לחצו במהירות על כפתור האיפוס פעמיים — הלוח נספר מחדש דרך USB כהתקן DFU ו‑OpenMV IDE יכול לצרוב תמונת firmware חדשה.

אותות ה‑SWD של ה‑STM32 חשופים על מחבר ה‑HD J1 בתחתית:

  • J1‑73 — NRST

  • J1‑75 — SWDIO (PA13)

  • J1‑77 — SWCLK (PA14)

  • J1‑79 — SWO (PB3)

חברו אותם דרך Portenta Breakout, מתאם ניפוי השגיאות הרשמי של Arduino, או נושאת מותאמת אישית עם כותרת בצעד 1.27 מ“מ. כל אותות ניפוי השגיאות הם בייחוס 3.3 V.

הערה

כאשר ה‑Portenta Vision Shield מחובר, אותם אותות SWD/JTAG מנותבים מעלה אל כותרת ה‑JTAG הסטנדרטית בת 20 הפינים של ARM Cortex Debug שעל המגן (צעד 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 לקריאה בלבד נטענים ישירות מ‑flash ללא העתקה ל‑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, כך ששימוש בו פירושו בניית תמונת firmware נפרדת ב‑C וטעינתה ממערכת הקבצים דרך openamp.RemoteProc. firmware לדוגמה בנוי מראש המממש נקודת קצה של 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 עבור DSP — למשל, גלאי עוצמת קול פשוט:

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 כדי לקבל דגימות משולבות משני המיקרופונים.

מד דלק של סוללה

מד הדלק Maxim MAX17262 ModelGauge m5 עוקב אחר המתח, הזרם, הטמפרטורה ומצב הטעינה של סוללת ה‑Li‑Po. הוא יושב על I²C 1 בכתובת 0x36.

ל‑MAX17262 יש חישת זרם פנימית, כך שאוגר הזרם נקרא ישירות במיקרו‑אמפר ללא גורם Rsense חיצוני להחיל. קריאת מד הדלק אינה מזיקה — אין מנהל התקן הנשלח, אך ניתן לקרוא ישירות את האוגרים המתועדים ב‑datasheet של 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 מסוג NXP PF1550 מטפל בכל וסת ב‑Portenta H7 — מסילת ה‑+3V3 הראשית, מסילת ה‑+1V8 של ליבת/קלט‑פלט ה‑SoC, ומטען ה‑Li‑Po. הוא יושב על I²C 1 בכתובת 0x08.

אזהרה

קריאת אוגרי PMIC היא בסדר; כתיבה אליהם מסוכנת. הגדרה שגויה של וסת buck או של הגדרת מטען עלולה לגרום נזק קבוע ללוח, לסוללה, או לשניהם. התייחסו ל‑PMIC כאל קריאה בלבד אלא אם אתם יודעים בדיוק מה אתם עושים.

הדבר השימושי ביותר שה‑PMIC מספר לכם ושמד הדלק אינו יכול הוא מכונת המצבים של המטען — האם הלוח רץ כעת על USB / ESLOV / VIN, באיזה שלב של מחזור הטעינה נמצא ה‑Li‑Po, והאם המטען נמצא בתקלה תרמית או של watchdog. אוגרי המטען נמצאים בהיסט של 0x80 במרחב כתובות ה‑I²C הראשי של ה‑PF1550 (ראו §22.2 ב‑datasheet של 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)

אוגרים נוספים לקריאה בלבד ששווה לעיין בהם ב‑datasheet (כולם בהיסט מטען 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 מוסיפה מודול LoRaWAN מסוג Murata CMWX1ZZABZ המחווט ל‑Portenta H7 מעל UART. מודול ה‑lora עוטף את קושחת פקודות ה‑AT ותומך בהצטרפות OTAA או ABP, uplink ו‑downlink:

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 עם מגנטיקה המחווט אל ה‑MAC של Ethernet 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 כדי לקרוא או להניע כל אחד מהפינים המסומנים בהדפס המשי. הפלטים הם CMOS של 3.3 V ויכולים לשקוע/לספק עד 20 mA לפין (140 mA סך הכל על פני כל הכותרת).

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.

ניתן להשתמש באותה חומרה גם במצב יעד (slave) דרך 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 Vread_u16 מחזיר 0–65535 על פני 0–3.3 V בפין:

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‑bang

machine.SoftI2C ו‑machine.SoftSPI עובדים על כל GPIO אם אתם זקוקים לאפיק נוסף.

חיישן תרמי (חיצוני)

הקושחה כוללת את מנהל ההתקן fir — מנהל התקן לחיישן תרמי (fir == far infrared) עבור מצלמות תרמיות המחווטות חיצונית:

  • MLX90621 — מערך IR בגודל 16 × 4

  • MLX90640 — מערך IR בגודל 32 × 24

  • MLX90641 — מערך IR בגודל 16 × 12

  • AMG8833 — מערך IR בגודל 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 מתזמן פונקציות callback מחזוריות או חד‑פעמיות בלי לצרוך חריץ טיימר חומרתי. העבירו -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 שומר על זמן שעון קיר על פני איפוסים. מחבר ה‑HD חושף גם רפידת 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()

מידע על אתחול וזמן ריצה

עדכון firmware (DFU)

ה‑Portenta H7 משתמש ב‑איפוס לחיצה כפולה הסטנדרטי של Arduino כדי להיכנס ל‑bootloader של Arduino. לחצו במהירות על כפתור האיפוס פעמיים — הלוח נספר מחדש דרך USB כהתקן DFU ו‑OpenMV IDE יכול לצרוב תמונת firmware חדשה.

סקריפט רץ יכול להיכנס מחדש ל‑bootloader לפי דרישה על ידי קריאה ל‑machine.bootloader()

import machine

machine.bootloader()

מערכת קבצים וסדר אתחול

קושחת ה‑Portenta H7 ממטמנת עד שלוש מערכות קבצים באתחול:

  • flash פנימי — תמיד ממוטמן ב‑/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 עוקפת את העותק שב‑flash מבלי לגעת בו — שני הקבצים מחופשים בספריית האתחול (/sdcard כאשר הכרטיס ממוטמן, אחרת /flash).

ברירת המחדל של main.py הנשלחת על לוח שזה עתה נצרב פשוט מהבהבת את הערוץ ה‑כחול של נורית ה‑RGB LED למשתמש כדופק לב (שני פולסים קצרים, מרווח קצר), כך שתוכלו לדעת שהקושחה אותחלה בנקיון ללא מארח כלשהו מחובר.

sys.path מורחב כך שיכלול את כל שלוש מערכות הקבצים ואת תת‑הספריות lib/ שלהן, כך שמודולים הניתנים לייבוא יכולים לשכון ב‑/flash/lib, /sdcard/lib, או /rom/lib.

כדי לאלץ את המערכת להתעלם מכרטיס SD מוכנס (למשל כדי להריץ את main.py שב‑flash גם כאשר כרטיס נוכח), צרו קובץ ריק בשם SKIPSD בשורש של /flash.

כאשר מחובר דרך USB, מערכת קבצי האתחול (/sdcard אם כרטיס נוכח, אחרת /flash) נספרת גם כן ככונן אחסון המוני USB במארח, ומאפשרת לכם לערוך את boot.py, main.py וכל קובץ אחר ישירות. הוציאו את הכונן לפני איפוס הלוח כדי שהמארח ישטוף את הכתיבות השמורות במטמון שלו.

הערה

מכיוון שמערכת ההפעלה מתייחסת לכונן כאל התקן בלוקים פסיבי, קבצים שנוצרו או שונו על ידי קוד הרץ על המצלמה לא יופיעו עד שהמארח יטמין מחדש את הכונן. אם גם מערכת ההפעלה וגם המצלמה כותבות לאותה מערכת קבצים באותו זמן, מערכת ההפעלה תנצח ותדרוס שינויים שנעשו על ידי המצלמה. השתמשו בכרטיס ה‑SD עבור כל נתון שהסקריפט כותב בחזרה, והטמינו מחדש לפני קריאת קבצים אלה מהמארח.

הערה

הערוץ ה‑אדום של נורית ה‑RGB LED למשתמש עשוי להידלק לרגע בזמן שהמארח קורא או כותב לכונן אחסון ההמוני של USB — זהו מחוון פעילות מונע‑קושחה, ולא תקלה.

גדלי אחסון

ה‑Portenta H7 נשלח עם:

  • /flash — מערכת קבצים FAT בגודל 11 MB, קריאה/כתיבה.

  • /rom — ROMFS בגודל 4 MB לקריאה בלבד הממופה לזיכרון, משמש לשליחת סקריפטים ומודלי ML שמרוויחים מגישת mmap ללא העתקה.

  • /sdcard — הגודל המלא של כל כרטיס microSD המוכנס ב‑Vision Shield (כאשר נוכח), קריאה/כתיבה.

מחוון תקלה קשה

אם נורית ה‑RGB LED למשתמש מתחלפת במהירות בין כל הצבעים — מהיר מספיק כך שהיא נוטה להיראות כ‑נורית LED לבנה מנצנצת ולא כגוונים נפרדים — הקושחה נתקלה בתקלה קשה בלתי ניתנת לשחזור. צרבו מחדש את הקושחה כדי להתאושש; אם צריבה מחדש אינה עוזרת, ייתכן שהלוח ניזוק פיזית.

ספריות תוכנה

ראו את אינדקס הספרייה עבור הרשימה המלאה של המודולים — כולל אילו מהם ייחודיים לבניית ה‑Portenta H7.