Arduino Portenta H7

Das Arduino Portenta H7 ist ein 66 × 25 mm großes industrielles Entwicklerboard rund um den STMicroelectronics STM32H747XI — ein Dual‑Core‑SoC, das einen Cortex‑M7 mit 400 MHz und einen Cortex‑M4 mit 200 MHz kombiniert. Die OpenMV‑Firmware läuft vollständig auf dem M7‑Kern und ist für die Verwendung mit dem Portenta Vision Shield (Ethernet‑ oder LoRa‑Edition) ausgelegt, das dem Basis‑Portenta H7 eine Himax‑HM01B0‑/HM0360‑Kamera, zwei PDM‑Mikrofone und einen microSD‑Slot hinzufügt.

Arduino Portenta H7

Für das vollständige Datenblatt, Fotos und Abmessungen siehe die Arduino Portenta H7 Produktseite.

Highlights

  • STMicroelectronics STM32H747XI dual Cortex‑M7 (400 MHz) + Cortex‑M4 (200 MHz). Die OpenMV‑Firmware läuft nur auf dem M7‑Kern; der M4‑Kern wird über openamp für die Inter‑Prozessor‑Kommunikation bereitgestellt.

  • 8 MB externes SDRAM plus 2 MB internes Flash und 16 MB externes QSPI‑Flash.

  • Hardware‑JPEG‑Encoder/‑Decoder.

  • Wi‑Fi b/g/n (2,4 GHz) + Bluetooth LE 5.1 über das Murata‑1DX‑Modul (CYW4343W) — verbindet sich über einen On‑Board‑U.FL‑Stecker mit der mitgelieferten Antenne.

  • High‑Speed‑USB‑C (480 Mb/s).

  • 22 Nutzer‑I/O‑Pins auf den Arduino‑MKR‑artigen oberen Stiftleisten — D0–D14 (digital) plus A0–A6 (analog).

  • Zwei 80‑polige Hochdichte‑Steckverbinder an der Unterseite legen die vollständige STM32H747‑Peripherie offen — DCMI, DSI, Ethernet RMII, FDCAN, SDIO, SAI/I²S, UARTs, zusätzliche SPI/I²C/Timer und so weiter. Shields wie das Vision Shield werden mit diesen Steckverbindern verbunden.

  • JTAG / SWD auf den unteren HD‑Steckverbindern herausgeführt für erweitertes Debugging.

  • Akku‑Unterstützung — 3,7‑V‑Li‑Po‑JST‑Stecker plus On‑Board‑Ladegerät und Akku‑Überwachung.

Pinbelegung

Arduino Portenta H7 Pinbelegung

Pin‑Referenz

22 Nutzer‑Pins sind auf den Arduino‑MKR‑artigen oberen Randleisten herausgeführt — 15 digitale (D0-D14) plus 7 analoge (A0-A6). Viele weitere SoC‑Pins stehen über die unteren 80‑poligen Hochdichte‑Steckverbinder für Shield‑Arbeiten zur Verfügung; siehe Arduinos vollständiges Pinbelegungs‑PDF für diese Zuordnung.

Pin‑Name

Referenz

Funktion

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 (geteilt mit A3 / A5)

D9

3,3 V

SPI2 SCK

D10

3,3 V

SPI2 MISO (geteilt mit 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 (nur analog)

A1

3,3 V

ADC12 IN1 (nur analog)

A2

3,3 V

ADC123 IN12 (nur analog; geteilt mit D10)

A3

3,3 V

ADC12 IN13 (nur analog; geteilt mit D8)

A4

3,3 V

ADC123 IN12 (geteilt mit D10)

A5

3,3 V

ADC12 IN13 (geteilt mit D8)

A6

3,3 V

DAC1 OUT1 / ADC12 IN18

A7

3,3 V

TIM3 CH1 / ADC12 IN3 (nicht auf den Stiftleisten herausgeführt)

D20

3,3 V

Alias von D8 / A3 / A5

D21

3,3 V

Alias von A6 — DAC1 OUT1

RESET

3,3 V

den On‑Board‑Schalter drücken oder auf GND ziehen, um zurückzusetzen

LED_RED

3,3 V

RGB‑LED roter Kanal (aktiv low)

LED_GREEN

3,3 V

RGB‑LED grüner Kanal (aktiv low)

LED_BLUE

3,3 V

RGB‑LED blauer Kanal (aktiv low)

Bemerkung

A0-A3 sind rein analoge Pads am STM32H747 ohne GPIO‑Funktion — behandeln Sie sie nur als ADC‑Eingänge. A2/A4 und A3/A5 teilen sich ihre physischen Pins mit D10 bzw. D8, daher können Sie auf diesen kein PWM oder SPI betreiben, während Sie sie analog auslesen. A7 liegt auf den unteren HD‑Steckverbindern.

Stromversorgungs‑Pins

MKR‑Header‑Pins:

  • VIN — Hauptsystemschiene in das On‑Board‑PMIC. Wird über eine Diode von der +5V‑Schiene, dem MKR‑VIN‑Pin oder den unteren 80‑poligen HD‑Steckverbindern gespeist.

  • +5V — 5‑V‑Schiene, gespeist von USB, dem ESLOV‑Stecker oder dem MKR‑+5V‑Pin selbst.

  • +3V3 — 3,3‑V‑Hauptschiene (Ausgang des PMIC‑Schaltreglers).

  • AREF — analoge Spannungsreferenz für die ADC‑Pins. Standardmäßig 3,3 V; extern ansteuern, um eine andere Referenz zu verwenden.

  • GND — gemeinsame Masse.

Akku‑Eingang:

  • Li‑Po‑JST an der Vorderseite des Boards nimmt eine 3,7‑V‑Li‑Po‑Zelle auf. Das PMIC lädt sie, wann immer +5V oder VIN anliegt.

Das Portenta H7 kann über jeden dieser Pfade mit Strom versorgt werden:

  • USB‑C — liefert 5 V an das On‑Board‑PMIC.

  • ESLOV‑Stecker — bis zu 5 V auf VESLOV (siehe ESLOV‑Stecker).

  • VIN‑Pin — eine geregelte 5‑V‑Versorgung direkt anlegen.

  • Li‑Po‑Akku — an den JST an der Vorderseite anschließen.

ESLOV‑Stecker

An der Seite des Boards befindet sich ein 5‑poliger lötfreier ESLOV‑Stecker:

Pin

Name

Funktion

1

VESLOV

5‑V‑Stromausgang (gleiche Schiene wie +5V des MKR‑Headers)

2

INT

externer Interrupt‑Eingang auf D7

3

SCL_EXT

geteilt mit dem MKR‑Header‑Pad D12 — gleicher I²C‑3‑Bus wie der Nutzer‑Header

4

SDA_EXT

geteilt mit dem MKR‑Header‑Pad D11 — gleicher I²C‑3‑Bus wie der Nutzer‑Header

5

GND

gemeinsame Masse

ESLOVs SCL_EXT/SDA_EXT und die D12/D11 des MKR‑Headers sind dieselben Pins — ein I²C‑3‑Bus, der auf zwei Steckverbindern herausgeführt ist.

Tipp

Verwenden Sie den Akkulaufzeit‑Schätzer, um zu modellieren, wie lange das Portenta H7 für einen gegebenen Aktiv‑/Tiefschlaf‑Arbeitszyklus mit einem Akku läuft.

Recovery‑ und Debug‑Pins

  • RESET — sowohl ein herausgeführter Pin auf dem oberen Header als auch ein Taster an der Seite des Boards, mit der NRST‑Leitung des SoC verbunden. Auf GND ziehen oder den Knopf drücken, um zurückzusetzen.

Das Portenta H7 verwendet Arduinos standardmäßigen Double‑Tap‑Reset, um in Arduinos Bootloader zu gelangen. Drücken Sie den Reset‑Knopf schnell zweimal — das Board meldet sich über USB als DFU‑Gerät neu an, und die OpenMV IDE kann ein neues Firmware‑Image flashen.

Die STM32‑SWD‑Signale sind auf dem unteren HD‑Steckverbinder J1 herausgeführt:

  • J1‑73 — NRST

  • J1‑75 — SWDIO (PA13)

  • J1‑77 — SWCLK (PA14)

  • J1‑79 — SWO (PB3)

Verdrahten Sie sie über ein Portenta Breakout, den offiziellen Arduino‑Debug‑Adapter oder einen eigenen Carrier mit einer 1,27‑mm‑Stiftleiste. Alle Debug‑Signale sind auf 3,3 V referenziert.

Bemerkung

Wenn das Portenta Vision Shield angeschlossen ist, werden dieselben SWD‑/JTAG‑Signale auf den standardmäßigen 20‑poligen ARM‑Cortex‑Debug‑JTAG‑Header auf dem Shield geführt (1,27 mm / 0,05″ Rastermaß).

Onboard‑Peripherie

LEDs

Das Portenta H7 hat eine einzelne Nutzer‑RGB‑LED, softwaregesteuert über machine.LED:

from machine import LED

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

Eine separate orangefarbene Lade‑LED neben dem Akku‑JST leuchtet, wenn das On‑Board‑Ladegerät Strom in einen angeschlossenen Li‑Po einspeist; sie ist nicht nutzersteuerbar.

Kamerasensor (Vision Shield)

Mit dem angeschlossenen Portenta Vision Shield (Ethernet‑ oder LoRa‑Edition) wird der Himax‑Sensor über das Modul csi — Kamerasensoren angesteuert:

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

Zwei Vision‑Shield‑Revisionen werden unterstützt:

  • HM01B0 — 320 × 320 monochrom.

  • HM0360 — 640 × 480 monochrom.

Warnung

Während die Vision‑Shield‑Kamera initialisiert ist, werden die folgenden MKR‑Header‑Pins von der Firmware beansprucht und können nicht verwendet werden:

MKR‑Pin

Grund

D1

TIM1 CH1 — Kamera‑Mastertakt

D6

TIM1 CH1 (alt) — Kamera‑Mastertakt

D11

I²C 3 SDA — geteilt mit der Kamera; Bus ist nutzbar, aber vermeiden Sie die I²C‑Adresse des Sensors (0x24)

D12

I²C 3 SCL — geteilt mit der Kamera; Bus ist nutzbar, aber vermeiden Sie die I²C‑Adresse des Sensors (0x24)

A6 / D21

DCMI HSYNC — deaktiviert außerdem den DAC

A7

DCMI PXCLK

Maschinelles Lernen

ml — Maschinelles Lernen führt quantisierte TFLite‑Modelle auf dem Cortex‑M7 mit CMSIS‑NN‑Kernels aus — schnell genug für kompakte Detektoren bei einigen Einzelbildern pro Sekunde. Modelle auf dem schreibgeschützten /rom‑Dateisystem werden direkt aus dem Flash geladen, ohne in den RAM kopiert zu werden. Hier ein 128×128‑BlazeFace‑Detektor, der das erkannte Gesicht und seine sechs Landmarken über jedes Einzelbild der Vision‑Shield‑Kamera legt:

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

Der Cortex‑M4‑Kern wird über openamp für die Inter‑Prozessor‑Kommunikation bereitgestellt. Die OpenMV‑Firmware läuft nur auf dem M7; der M4 hat keine eigene MicroPython‑Laufzeitumgebung, daher bedeutet seine Nutzung, ein separates C‑Firmware‑Image zu erstellen und es über openamp.RemoteProc aus dem Dateisystem zu laden. Vorgebaute Beispiel‑Firmware, die einen virtuellen UART‑Endpunkt implementiert, ist im Repository openamp_vuart verfügbar — folgen Sie dessen README, um vuart.elf zu bauen:

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)

In der Praxis sollte diese Unterstützung am besten als Demonstration der openamp‑Schnittstelle und nicht als funktionierende Dual‑Core‑Plattform betrachtet werden — der M4 kann nicht unabhängig vom M7 zurückgesetzt werden, sodass das Stoppen des M4 einen vollständigen Systemneustart erzwingt.

Mikrofon (Vision Shield)

Das Vision Shield trägt zwei PDM‑Mikrofone, die über audio — Audio-Modul über die SAI4‑Peripherie des STM32 erfasst werden. Jeder Puffer kommt als vorzeichenbehaftetes 16‑Bit‑PCM‑bytearray an, bereit zur Einspeisung in ulab/numpy für die DSP — zum Beispiel ein einfacher Lautstärke‑Detektor:

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

Übergeben Sie channels=2 an audio.init, um verschachtelte Samples von beiden Mikrofonen zu erhalten.

Akku‑Füllstandsanzeige

Die Maxim‑MAX17262‑ModelGauge‑m5‑Füllstandsanzeige verfolgt Spannung, Strom, Temperatur und Ladezustand des Li‑Po‑Akkus. Sie sitzt auf I²C 1 an Adresse 0x36.

Der MAX17262 verfügt über interne Strommessung, sodass das Stromregister direkt in Mikroampere ausgelesen wird, ohne dass ein externer Rsense‑Faktor anzuwenden ist. Das Auslesen der Füllstandsanzeige ist unbedenklich — es wird kein Treiber mitgeliefert, aber die im MAX17262‑Datenblatt dokumentierten Register können direkt gelesen werden:

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 ist vorzeichenbehaftetes Zweierkomplement: positiv beim Laden, negativ beim Entladen. TTE ist nur aussagekräftig, wenn der Strom negativ ist; TTF nur, wenn der Strom positiv ist.

Power‑Management‑IC

Das NXP‑PF1550‑PMIC steuert jeden Regler auf dem Portenta H7 — die +3V3‑Hauptschiene, die +1V8‑SoC‑Kern‑/‑I/O‑Schiene und das Li‑Po‑Ladegerät. Es sitzt auf I²C 1 an Adresse 0x08.

Warnung

Das Lesen von PMIC‑Registern ist in Ordnung; das Schreiben in sie ist gefährlich. Eine Fehlkonfiguration eines Abwärtsreglers oder einer Ladegerät‑Einstellung kann das Board, den Akku oder beide dauerhaft beschädigen. Behandeln Sie das PMIC als schreibgeschützt, sofern Sie nicht genau wissen, was Sie tun.

Das Nützlichste, was Ihnen das PMIC mitteilt und die Füllstandsanzeige nicht kann, ist die Ladegerät‑Zustandsmaschine — ob das Board derzeit über USB / ESLOV / VIN läuft, in welcher Phase des Ladezyklus sich der Li‑Po befindet und ob das Ladegerät einen thermischen oder Watchdog‑Fehler hat. Die Ladegerät‑Register liegen mit einem Offset von 0x80 im Haupt‑I²C‑Adressraum des PF1550 (siehe §22.2 des PF1550‑Datenblatts), sodass beispielsweise CHG_INT_OK an der Ladegerät‑Adresse 0x04 aus dem PMIC‑Register 0x84 gelesen wird:

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)

Weitere schreibgeschützte Register, die einen Blick ins Datenblatt wert sind (alle mit Ladegerät‑Offset 0x80): 0x80 CHG_INT (gerastete Ladegerät‑Interrupts — Fehlerflags), 0x86 VBUS_SNS (der Mehrbit‑VBUS‑Zustand einschließlich OVLO / UVLO / DPM) und 0x88 BATT_SNS (Akku‑Anwesenheit und Überstromzustand).

Wi‑Fi

Das On‑Board‑Murata‑1DX (CYW4343W) wird über network — Netzwerkkonfiguration als Station‑Schnittstelle bereitgestellt. Schließen Sie die mitgelieferte Antenne an den On‑Board‑U.FL‑Stecker an, bevor Sie den Funk in Betrieb nehmen:

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

Dasselbe Murata 1DX stellt auch Bluetooth LE 5.1 bereit. Verwenden Sie aioble — Async BLE für asyncio‑freundliches BLE — zum Beispiel als Peripheriegerät werben und warten, bis sich ein Central verbindet:

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)

Die LoRa‑Edition des Vision Shields fügt ein Murata‑CMWX1ZZABZ‑LoRaWAN‑Modul hinzu, das über UART mit dem Portenta H7 verdrahtet ist. Das lora‑Modul umhüllt die AT‑Command‑Firmware und unterstützt OTAA‑ oder ABP‑Join, Uplink und 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()

Verwenden Sie BAND_US915 / BAND_AS923 / BAND_AU915 usw. für Regionen außerhalb der EU und wechseln Sie zu lora.Lora.join_ABP(), wenn Ihr Netzwerkserver die ABP‑Aktivierung verwendet.

Warnung

Während das LoRa‑Modul in Verwendung ist, beansprucht der Treiber die folgenden MKR‑Header‑Pins als Steuerleitungen für das Murata CMWX1ZZABZ — sie können nicht verwendet werden:

MKR‑Pin

Grund

D3

LoRa‑Modul‑BOOT‑Pin

D5

LoRa‑Modul‑RST‑Pin

Ethernet (Vision Shield)

Die Ethernet‑Edition des Vision Shields fügt eine RJ45‑Buchse mit Magnetik hinzu, die über RMII mit dem 10/100‑Ethernet‑MAC des STM32H747 verdrahtet ist. Stecken Sie ein Ethernet‑Kabel ein, und der PHY erscheint als LAN‑Schnittstelle; DHCP läuft automatisch, sobald die Verbindung steht:

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‑Karte (Vision Shield)

Wenn eine Karte eingelegt wird, wird sie automatisch unter /sdcard eingehängt und ist über das reguläre Dateisystem nutzbar:

import os

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

Bus‑Referenz

GPIO

Verwenden Sie machine.Pin, um beliebige der bedruckten Pins zu lesen oder anzusteuern. Ausgänge sind 3,3‑V‑CMOS und können bis zu 20 mA pro Pin senken/quellen (140 mA gesamt über den ganzen Header).

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

Jeder Eingangs‑Pin kann auch bei Flankenübergängen einen Interrupt auslösen:

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

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

UART

Bus

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

Bus

SCL

SDA

I2C3

D12

D11

from machine import I2C

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

Die Pads D11/D12 am MKR‑Header und die Pins SDA_EXT/SCL_EXT des ESLOV‑Steckers landen auf demselben I²C‑3‑Bus — siehe ESLOV‑Stecker oben für die ESLOV‑Pinbelegung.

Dieselbe Hardware kann auch im Target‑(Slave‑)Modus über machine.I2CTarget verwendet werden, um einem anderen I²C‑Controller einen Speicherbereich bereitzustellen:

from machine import I2CTarget

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

SPI

Bus

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

Das Portenta H7 stellt acht 12‑Bit‑ADC‑Kanäle auf A0–A7 bereit. Alle sind auf 3,3 V referenziertread_u16 gibt 0–65535 über 0–3,3 V am Pin zurück:

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

Ein einzelner 12‑Bit‑DAC‑Kanal wird auf DAC1 (A6 / D21) über pyb.DAC bereitgestellt:

from pyb import DAC

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

PWM

Pin

Timer / Kanal

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

Steuern Sie beliebige davon über machine.PWM an:

from machine import Pin, PWM

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

Bemerkung

Mehrere Pins teilen sich Timer‑Kanäle:

  • TIM1 CH1 liegt auf D1 und D6.

  • TIM1 CH2 liegt auf D2 und D14.

  • TIM8 CH3N liegt auf D0 und D1.

Wählen Sie einen Verbraucher pro Timer‑Kanal.

Warnung

TIM1 ist für den Kamera‑Mastertakt reserviert, wenn das Vision Shield über csi — Kamerasensoren initialisiert wird — D1, D2, D6, D13 und D14 können nicht PWM‑gesteuert werden, während die Kamera aktiv ist.

Software‑Bit‑Banging‑Busse

machine.SoftI2C und machine.SoftSPI funktionieren auf jedem GPIO, falls Sie einen zusätzlichen Bus benötigen.

Thermosensor (extern)

Die Firmware enthält den Treiber fir — Wärmesensortreiber (fir == far infrared) für extern verdrahtete Wärmebildkameras:

  • MLX90621 — 16 × 4 IR‑Array

  • MLX90640 — 32 × 24 IR‑Array

  • MLX90641 — 16 × 12 IR‑Array

  • AMG8833 — 8 × 8 IR‑Array

Verdrahten Sie das Modul mit dem I²C‑Bus des Boards und lesen Sie Einzelbilder mit 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())

Der fir‑Treiber kommuniziert mit dem Sensor nur über I²C 3 — verdrahten Sie das Modul mit D12 (SCL) und D11 (SDA).

Timing

time

Das Modul time deckt blockierende Verzögerungen, monotone Ticks und die Messung verstrichener Zeit ab:

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)

Virtuelle Timer

machine.Timer plant periodische oder einmalige Callbacks, ohne einen Hardware‑Timer‑Slot zu belegen. Übergeben Sie -1 als id, um einen virtuellen (Software‑)Timer zu verwenden:

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

Periodenwerte sind in Millisekunden. Rufen Sie deinit() auf, um den Slot zu stoppen und freizugeben.

Echtzeituhr

machine.RTC hält die Wanduhrzeit über Resets hinweg. Der HD‑Steckverbinder stellt außerdem ein COINCELL‑Pad bereit, das die RTC bei Stromausfall von einer CR2032 versorgen kann:

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 setzt das Board zurück, wenn die Anwendung hängt. Einmal gestartet, kann er nicht gestoppt oder neu konfiguriert werden — versorgen Sie ihn regelmäßig innerhalb Ihrer Hauptschleife:

from machine import WDT

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

Boot‑ und Laufzeitinformationen

Firmware‑Update (DFU)

Das Portenta H7 verwendet Arduinos standardmäßigen Double‑Tap‑Reset, um in Arduinos Bootloader zu gelangen. Drücken Sie den Reset‑Knopf schnell zweimal — das Board meldet sich über USB als DFU‑Gerät neu an, und die OpenMV IDE kann ein neues Firmware‑Image flashen.

Ein laufendes Skript kann bei Bedarf erneut in den Bootloader gelangen, indem es machine.bootloader() aufruft:

import machine

machine.bootloader()

Dateisystem und Boot‑Reihenfolge

Die Portenta‑H7‑Firmware hängt beim Booten bis zu drei Dateisysteme ein:

  • Internes Flash — immer unter /flash eingehängt. Enthält standardmäßig main.py und README.txt; wird beim allerersten Boot erstellt.

  • microSD‑Karte — wenn ein Vision Shield angeschlossen ist und eine Karte eingelegt ist, wird sie unter /sdcard eingehängt.

  • ROMFS — schreibgeschütztes, speichergemapptes Dateisystem unter /rom, das von MicroPython beim Start automatisch eingehängt wird.

Nach dem Einhängen wird das Arbeitsverzeichnis auf /sdcard gesetzt, wenn die Karte vorhanden ist, andernfalls auf /flash. Der Interpreter führt dann Skripte aus diesem Verzeichnis aus:

  • boot.py wird bei jedem Soft‑Reset ausgeführt (Kaltstart, Ctrl‑D aus der REPL oder immer wenn das laufende Skript zurückkehrt).

  • main.py wird nur beim Kaltstart ausgeführt, unmittelbar nach boot.py. Nachfolgende Soft‑Resets führen boot.py erneut aus, fallen aber direkt in die REPL — um main.py erneut auszuführen, müssen Sie das Board vollständig zurücksetzen.

Wenn Sie eine boot.py oder main.py auf die SD‑Karte legen, überschreibt dies die Kopie im Flash, ohne sie anzutasten — beide Dateien werden im Boot‑Verzeichnis gesucht (/sdcard, wenn die Karte eingehängt ist, andernfalls /flash).

Die standardmäßige main.py, die auf einem frisch geflashten Board ausgeliefert wird, lässt lediglich den blauen Kanal der Nutzer‑RGB‑LED als Herzschlag blinken (zwei kurze Impulse, kurze Pause), sodass Sie ohne angeschlossenen Host erkennen können, dass die Firmware sauber gebootet ist.

sys.path wird erweitert, um alle drei Dateisysteme und ihre lib/‑Unterverzeichnisse einzuschließen, sodass importierbare Module in /flash/lib, /sdcard/lib oder /rom/lib liegen können.

Um das System zu zwingen, eine eingelegte SD‑Karte zu ignorieren (zum Beispiel um die main.py im Flash auch bei vorhandener Karte auszuführen), erstellen Sie eine leere Datei namens SKIPSD im Stammverzeichnis von /flash.

Bei Verbindung über USB meldet sich das Boot‑Dateisystem (/sdcard, wenn eine Karte vorhanden ist, andernfalls /flash) zusätzlich als USB‑Massenspeicherlaufwerk auf dem Host an, sodass Sie boot.py, main.py und beliebige andere Dateien direkt bearbeiten können. Werfen Sie das Laufwerk aus, bevor Sie das Board zurücksetzen, damit der Host seine zwischengespeicherten Schreibvorgänge übernimmt.

Bemerkung

Da das Betriebssystem das Laufwerk als passives Blockgerät behandelt, werden Dateien, die von auf der Kamera laufendem Code erstellt oder geändert wurden, erst angezeigt, wenn der Host das Laufwerk erneut einhängt. Wenn sowohl das Betriebssystem als auch die Kamera dasselbe Dateisystem gleichzeitig beschreiben, gewinnt das Betriebssystem und überschreibt von der Kamera vorgenommene Änderungen. Verwenden Sie die SD‑Karte für alle Daten, die das Skript zurückschreibt, und hängen Sie sie erneut ein, bevor Sie diese Dateien vom Host aus lesen.

Bemerkung

Der rote Kanal der Nutzer‑RGB‑LED kann kurz aufleuchten, während der Host vom USB‑Massenspeicherlaufwerk liest oder darauf schreibt — dies ist eine firmwaregesteuerte Aktivitätsanzeige, kein Fehler.

Speichergrößen

Das Portenta H7 wird ausgeliefert mit:

  • /flash11 MB FAT‑Dateisystem, Lesen/Schreiben.

  • /rom4 MB schreibgeschütztes, speichergemapptes ROMFS, verwendet, um Skripte und ML‑Modelle auszuliefern, die von Zero‑Copy‑mmap‑Zugriff profitieren.

  • /sdcard — volle Größe der jeweils in einem Vision Shield eingelegten microSD‑Karte (sofern vorhanden), Lesen/Schreiben.

Hard‑Fault‑Anzeige

Wenn die Nutzer‑RGB‑LED schnell alle Farben durchläuft — schnell genug, dass sie eher wie eine funkelnde weiße LED als wie einzelne Farbtöne aussieht — ist die Firmware auf einen nicht behebbaren Hard Fault gestoßen. Flashen Sie die Firmware neu, um sie wiederherzustellen; wenn das Neuflashen nicht hilft, ist das Board möglicherweise physisch beschädigt.

Software‑Bibliotheken

Siehe den Bibliotheksindex für die vollständige Liste der Module — einschließlich der Module, die nur im Portenta‑H7‑Build vorkommen.