Arduino Portenta H7

De Arduino Portenta H7 is een industrieel ontwikkelbord van 66 × 25 mm, opgebouwd rond de STMicroelectronics STM32H747XI — een dual‑core SoC die een Cortex‑M7 op 400 MHz combineert met een Cortex‑M4 op 200 MHz. De OpenMV-firmware draait volledig op de M7-kern en is ontworpen om gebruikt te worden met het Portenta Vision Shield (Ethernet- of LoRa-editie), dat een Himax HM01B0 / HM0360 camera, dubbele PDM-microfoons en een microSD-slot toevoegt aan de basis-Portenta H7.

Arduino Portenta H7

Voor de volledige datasheet, foto’s en afmetingen, zie de Arduino Portenta H7 productpagina.

Hoogtepunten

  • STMicroelectronics STM32H747XI dual Cortex‑M7 (400 MHz) + Cortex‑M4 (200 MHz). De OpenMV-firmware draait alleen op de M7-kern; de M4-kern wordt blootgesteld via openamp voor communicatie tussen processoren.

  • 8 MB extern SDRAM plus 2 MB intern flashgeheugen en 16 MB extern QSPI-flashgeheugen.

  • Hardware JPEG-encoder/decoder.

  • Wi‑Fi b/g/n (2,4 GHz) + Bluetooth LE 5.1 via de Murata 1DX (CYW4343W) module — verbindt via een U.FL-connector op het bord met de meegeleverde antenne.

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

  • 22 gebruikers-I/O-pinnen op de Arduino MKR‑stijl bovenste headers — D0–D14 (digitaal) plus A0–A6 (analoog).

  • Twee 80‑pins high‑density-connectoren aan de onderkant stellen de volledige STM32H747-fabric bloot — DCMI, DSI, Ethernet RMII, FDCAN, SDIO, SAI/I²S, UART’s, extra SPI/I²C/timers, enzovoort. Shields zoals het Vision Shield koppelen aan deze connectoren.

  • JTAG / SWD uitgebracht op de onderste HD-connectoren voor geavanceerd debuggen.

  • Accu-ondersteuning — 3,7 V Li‑Po JST-connector plus oplader en accumonitor op het bord.

Pinout

Arduino Portenta H7 Pinout

Pinreferentie

22 gebruikerspinnen worden blootgesteld op de Arduino MKR‑stijl bovenrand-headers — 15 digitale (D0-D14) plus 7 analoge (A0-A6). Veel meer SoC-pinnen zijn beschikbaar via de onderste 80‑pins high‑density-connectoren voor shieldwerk; zie Arduino’s volledige pinout-PDF voor die toewijzing.

Pinnaam

Referentie

Functie

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 (gedeeld met A3 / A5)

D9

3,3 V

SPI2 SCK

D10

3,3 V

SPI2 MISO (gedeeld met 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 (alleen analoog)

A1

3,3 V

ADC12 IN1 (alleen analoog)

A2

3,3 V

ADC123 IN12 (alleen analoog; gedeeld met D10)

A3

3,3 V

ADC12 IN13 (alleen analoog; gedeeld met D8)

A4

3,3 V

ADC123 IN12 (gedeeld met D10)

A5

3,3 V

ADC12 IN13 (gedeeld met D8)

A6

3,3 V

DAC1 OUT1 / ADC12 IN18

A7

3,3 V

TIM3 CH1 / ADC12 IN3 (niet blootgesteld op de headers)

D20

3,3 V

alias van D8 / A3 / A5

D21

3,3 V

alias van A6 — DAC1 OUT1

RESET

3,3 V

druk op de schakelaar op het bord of trek naar GND om te resetten

LED_RED

3,3 V

rode kanaal van de RGB-LED (actief laag)

LED_GREEN

3,3 V

groene kanaal van de RGB-LED (actief laag)

LED_BLUE

3,3 V

blauwe kanaal van de RGB-LED (actief laag)

Notitie

A0-A3 zijn alleen-analoge pads op de STM32H747 zonder GPIO-functie — behandel ze uitsluitend als ADC-ingangen. A2/A4 en A3/A5 delen hun fysieke pinnen met respectievelijk D10 en D8, dus je kunt er geen PWM of SPI op aansturen terwijl je ze als analoog uitleest. A7 bevindt zich op de onderste HD-connectoren.

Voedingspinnen

MKR-headerpinnen:

  • VIN — hoofdsysteemrail naar de PMIC op het bord. Gevoed via een diode vanaf de +5V-rail, de MKR VIN-pin, of de onderste 80‑pins HD-connectoren.

  • +5V — 5 V-rail gevoed vanaf USB, de ESLOV-connector, of de MKR +5V-pin zelf.

  • +3V3 — hoofd 3,3 V-rail (uitgang van de PMIC-schakelregelaar).

  • AREF — analoge spanningsreferentie voor de ADC-pinnen. Standaard 3,3 V; stuur deze extern aan om een andere referentie te gebruiken.

  • GND — gemeenschappelijke massa.

Accu-ingang:

  • Li‑Po JST aan de voorkant van het bord accepteert een 3,7 V Li‑Po-cel. De PMIC laadt deze op zodra +5V of VIN aanwezig is.

De Portenta H7 kan via elk van deze paden van stroom worden voorzien:

  • USB‑C — levert 5 V aan de PMIC op het bord.

  • ESLOV-connector — tot 5 V op VESLOV (zie ESLOV-connector).

  • VIN-pin — stuur er rechtstreeks een gereguleerde 5 V-voeding op.

  • Li‑Po-accu — sluit aan op de JST aan de voorkant.

ESLOV-connector

Aan de zijkant van het bord bevindt zich een 5‑pins soldeervrije ESLOV-connector:

Pin

Naam

Functie

1

VESLOV

5 V voedingsuitgang (dezelfde rail als de +5V van de MKR-header)

2

INT

externe interrupt-ingang op D7

3

SCL_EXT

gedeeld met de MKR-header D12-pad — dezelfde I²C 3-bus als de gebruikersheader

4

SDA_EXT

gedeeld met de MKR-header D11-pad — dezelfde I²C 3-bus als de gebruikersheader

5

GND

gemeenschappelijke massa

De SCL_EXT/SDA_EXT van ESLOV en de D12/D11 van de MKR-header zijn dezelfde pinnen — één I²C 3-bus blootgesteld op twee connectoren.

Tip

Gebruik de accu-levensduurschatter om te modelleren hoe lang de Portenta H7 op een accu zal draaien voor een gegeven actieve / deepsleep-bedrijfscyclus.

Herstel- en debug-pinnen

  • RESET — zowel een blootgestelde pin op de bovenste header als een drukschakelaar aan de zijkant van het bord, verbonden met de NRST-lijn van de SoC. Trek naar GND of druk op de knop om te resetten.

De Portenta H7 gebruikt Arduino’s standaard dubbele-tik-reset om de bootloader van Arduino te betreden. Druk snel tweemaal op de resetknop — het bord wordt opnieuw geënumereerd via USB als een DFU-apparaat en OpenMV IDE kan een nieuwe firmware-image flashen.

De STM32 SWD-signalen zijn blootgesteld op de onderste HD-connector J1:

  • J1‑73 — NRST

  • J1‑75 — SWDIO (PA13)

  • J1‑77 — SWCLK (PA14)

  • J1‑79 — SWO (PB3)

Sluit ze aan via een Portenta Breakout, de officiële Arduino debug-adapter, of een aangepaste carrier met een 1,27 mm header. Alle debug-signalen zijn 3,3 V gerefereerd.

Notitie

Wanneer het Portenta Vision Shield is aangesloten, worden dezelfde SWD/JTAG-signalen doorgeleid naar de standaard 20‑pins ARM Cortex Debug JTAG-header op het shield (1,27 mm / 0,05″ steek).

Randapparaten op het bord

LED’s

De Portenta H7 heeft één RGB-gebruikers-LED, softwarematig bestuurbaar via machine.LED

from machine import LED

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

Een aparte oranje laad-LED naast de accu-JST gaat branden wanneer de oplader op het bord stroom levert aan een aangesloten Li‑Po; deze is niet door de gebruiker bestuurbaar.

Camerasensor (Vision Shield)

Met het Portenta Vision Shield (Ethernet- of LoRa-editie) aangesloten, wordt de Himax-sensor aangestuurd via de csi — camerasensoren module:

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

Twee Vision Shield-revisies worden ondersteund:

  • HM01B0 — 320 × 320 monochroom.

  • HM0360 — 640 × 480 monochroom.

Waarschuwing

Terwijl de Vision Shield-camera geïnitialiseerd is, worden de volgende MKR-headerpinnen door de firmware geclaimd en kunnen ze niet worden gebruikt:

MKR-pin

Reden

D1

TIM1 CH1 — master-klok van de camera

D6

TIM1 CH1 (alt) — master-klok van de camera

D11

I²C 3 SDA — gedeeld met de camera; de bus is bruikbaar maar vermijd het I²C-adres van de sensor (0x24)

D12

I²C 3 SCL — gedeeld met de camera; de bus is bruikbaar maar vermijd het I²C-adres van de sensor (0x24)

A6 / D21

DCMI HSYNC — schakelt ook de DAC uit

A7

DCMI PXCLK

Machine learning

ml — Machine Learning draait gekwantiseerde TFLite-modellen op de Cortex‑M7 met CMSIS‑NN-kernels — snel genoeg voor compacte detectoren bij enkele frames per seconde. Modellen op het alleen-lezen /rom-bestandssysteem worden rechtstreeks vanuit flash geladen zonder kopiëren naar RAM. Hier is een 128×128 BlazeFace-detector die het gedetecteerde gezicht en de zes oriëntatiepunten ervan op elk frame van de Vision Shield-camera overlayt:

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

De Cortex‑M4-kern wordt blootgesteld via openamp voor communicatie tussen processoren. De OpenMV-firmware draait alleen op de M7; de M4 heeft geen eigen MicroPython-runtime, dus het gebruik ervan betekent dat je een aparte C-firmware-image bouwt en deze vanaf het bestandssysteem laadt via openamp.RemoteProc. Vooraf gebouwde voorbeeldfirmware die een virtueel UART-eindpunt implementeert, is beschikbaar in de openamp_vuart repository — volg de README ervan om vuart.elf te bouwen:

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 de praktijk kan deze ondersteuning het best worden beschouwd als een demonstratie van de openamp-interface in plaats van een werkend dual‑core-platform — de M4 kan niet onafhankelijk van de M7 worden gereset, dus het stoppen van de M4 dwingt een volledige systeem-herstart af.

Microfoon (Vision Shield)

Het Vision Shield draagt dubbele PDM-microfoons die worden vastgelegd via audio — Audio Module over het SAI4-randapparaat van de STM32. Elke buffer arriveert als signed‑16‑bit PCM bytearray, klaar om in te voeren in ulab/numpy voor DSP — bijvoorbeeld een eenvoudige luidheidsdetector:

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

Geef channels=2 door aan audio.init om geïnterleavede samples van beide microfoons te ontvangen.

Accu-brandstofmeter

De Maxim MAX17262 ModelGauge m5 brandstofmeter houdt de spanning, stroom, temperatuur en laadtoestand van de Li‑Po-accu bij. Deze bevindt zich op I²C 1 op adres 0x36.

De MAX17262 heeft interne stroommeting, dus het stroomregister leest rechtstreeks in microampère uit zonder dat er een externe Rsense-factor toegepast hoeft te worden. Het uitlezen van de brandstofmeter is onschadelijk — er wordt geen driver meegeleverd, maar de registers gedocumenteerd in de MAX17262 datasheet kunnen rechtstreeks worden uitgelezen:

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 is signed two’s-complement: positief tijdens het opladen, negatief tijdens het ontladen. TTE is alleen zinvol wanneer de stroom negatief is; TTF alleen wanneer de stroom positief is.

Voedingsbeheer-IC

De NXP PF1550 PMIC beheert elke regelaar op de Portenta H7 — de +3V3 hoofdrail, de +1V8 SoC-kern / I/O-rail, en de Li‑Po-oplader. Deze bevindt zich op I²C 1 op adres 0x08.

Waarschuwing

PMIC-registers uitlezen is prima; ernaar schrijven is gevaarlijk. Het verkeerd configureren van een buck-regelaar of een opladerinstelling kan het bord, de accu, of beide permanent beschadigen. Behandel de PMIC als alleen-lezen, tenzij je precies weet wat je doet.

Het nuttigste dat de PMIC je vertelt en wat de brandstofmeter niet kan, is de toestandsmachine van de oplader — of het bord momenteel draait op USB / ESLOV / VIN, in welke fase van de laadcyclus de Li‑Po zich bevindt, en of de oplader in een thermische of watchdog-fout zit. De opladerregisters bevinden zich op een offset van 0x80 in de hoofd-I²C-adresruimte van de PF1550 (zie §22.2 van de PF1550 datasheet), dus bijvoorbeeld CHG_INT_OK op opladeradres 0x04 wordt uitgelezen uit PMIC-register 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)

Andere alleen-lezen registers die de moeite waard zijn om in de datasheet te bekijken (alle op opladeroffset 0x80): 0x80 CHG_INT (vergrendelde opladerinterrupts — foutvlaggen), 0x86 VBUS_SNS (de multi‑bit VBUS-toestand inclusief OVLO / UVLO / DPM), en 0x88 BATT_SNS (aanwezigheid van de accu en overstroomtoestand).

Wi‑Fi

De Murata 1DX (CYW4343W) op het bord wordt blootgesteld via network — netwerkconfiguratie als een station-interface. Sluit de meegeleverde antenne aan op de U.FL-connector op het bord voordat je de radio inschakelt:

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

Dezelfde Murata 1DX stelt ook Bluetooth LE 5.1 bloot. Gebruik aioble — Async BLE voor asyncio‑vriendelijke BLE — bijvoorbeeld, adverteren als randapparaat en wachten tot een central verbinding maakt:

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)

De LoRa-editie van het Vision Shield voegt een Murata CMWX1ZZABZ LoRaWAN-module toe die via UART aan de Portenta H7 is bedraad. De lora-module omhult de AT‑command-firmware en ondersteunt OTAA- of ABP-join, uplink en 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()

Gebruik BAND_US915 / BAND_AS923 / BAND_AU915 enz. voor niet‑EU-regio’s, en schakel over naar lora.Lora.join_ABP() als je netwerkserver ABP-activering gebruikt.

Waarschuwing

Terwijl de LoRa-module in gebruik is, claimt de driver de volgende MKR-headerpinnen als stuurlijnen voor de Murata CMWX1ZZABZ — ze kunnen niet worden gebruikt:

MKR-pin

Reden

D3

LoRa-module BOOT-pin

D5

LoRa-module RST-pin

Ethernet (Vision Shield)

De Ethernet-editie van het Vision Shield voegt een RJ45-aansluiting met magnetics toe die via RMII aan de 10/100 Ethernet-MAC van de STM32H747 is bedraad. Sluit een Ethernet-kabel aan en de PHY verschijnt als een LAN-interface; DHCP draait automatisch zodra de link tot stand komt:

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

Wanneer een kaart wordt ingestoken, wordt deze automatisch gemount op /sdcard en is bruikbaar via het reguliere bestandssysteem:

import os

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

Busreferentie

GPIO

Gebruik machine.Pin om elk van de op de zeefdruk aangegeven pinnen uit te lezen of aan te sturen. Uitgangen zijn 3,3 V CMOS en kunnen tot 20 mA per pin opnemen/leveren (140 mA totaal over de hele 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())

Elke ingangspin kan ook een interrupt afvuren bij randovergangen:

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

De D11/D12-pads op de MKR-header en de SDA_EXT/SCL_EXT-pinnen van de ESLOV-connector landen op dezelfde I²C 3-bus — zie ESLOV-connector hierboven voor de ESLOV-pinout.

Dezelfde hardware kan ook in target- (slave-) modus worden gebruikt via machine.I2CTarget om een geheugengebied bloot te stellen aan een andere I²C-controller:

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

De Portenta H7 stelt acht 12‑bit ADC-kanalen bloot op A0–A7. Alle zijn 3,3 V gerefereerdread_u16 geeft 0–65535 terug over 0–3,3 V op de pin:

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

Eén 12‑bit DAC-kanaal wordt blootgesteld op DAC1 (A6 / D21) via pyb.DAC

from pyb import DAC

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

PWM

Pin

Timer / kanaal

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

Stuur ze aan via machine.PWM

from machine import Pin, PWM

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

Notitie

Verschillende pinnen delen timerkanalen:

  • TIM1 CH1 zit op D1 en D6.

  • TIM1 CH2 zit op D2 en D14.

  • TIM8 CH3N zit op D0 en D1.

Kies één verbruiker per timerkanaal.

Waarschuwing

TIM1 is gereserveerd voor de master-klok van de camera wanneer het Vision Shield wordt geïnitialiseerd via csi — camerasensorenD1, D2, D6, D13 en D14 kunnen niet PWM‑aangestuurd worden terwijl de camera actief is.

Softwarematig bit‑banged bussen

machine.SoftI2C en machine.SoftSPI werken op elke GPIO als je een extra bus nodig hebt.

Thermische sensor (extern)

De firmware bevat de fir — thermische sensor-driver (fir == far infrared) driver voor extern bedrade thermische beeldsensoren:

  • MLX90621 — 16 × 4 IR-array

  • MLX90640 — 32 × 24 IR-array

  • MLX90641 — 16 × 12 IR-array

  • AMG8833 — 8 × 8 IR-array

Bedraad de module naar de I²C-bus van het bord en lees frames met 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())

De fir-driver communiceert alleen met de sensor over I²C 3 — bedraad de module naar D12 (SCL) en D11 (SDA).

Timing

time

De time module dekt blokkerende vertragingen, monotone ticks en het meten van verstreken tijd:

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)

Virtuele timers

machine.Timer plant periodieke of eenmalige callbacks zonder een hardware-timerslot te verbruiken. Geef -1 door als id om een virtuele (software-) timer te gebruiken:

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

Periodewaarden zijn in milliseconden. Roep deinit() aan om te stoppen en het slot vrij te geven.

Realtimeklok

machine.RTC houdt de kloktijd bij over resets heen. De HD-connector stelt ook een COINCELL-pad bloot die de RTC vanaf een CR2032 kan voeden bij stroomuitval:

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 reset het bord als de applicatie vastloopt. Eenmaal gestart kan deze niet worden gestopt of opnieuw geconfigureerd — voed hem periodiek binnen je hoofdlus:

from machine import WDT

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

Boot- en runtime-informatie

Firmware-update (DFU)

De Portenta H7 gebruikt Arduino’s standaard dubbele-tik-reset om de bootloader van Arduino te betreden. Druk snel tweemaal op de resetknop — het bord wordt opnieuw geënumereerd via USB als een DFU-apparaat en OpenMV IDE kan een nieuwe firmware-image flashen.

Een draaiend script kan op verzoek opnieuw de bootloader betreden door machine.bootloader() aan te roepen:

import machine

machine.bootloader()

Bestandssysteem en bootvolgorde

De Portenta H7-firmware mount bij het opstarten maximaal drie bestandssystemen:

  • Intern flashgeheugen — altijd gemount op /flash. Bevat standaard main.py en README.txt; aangemaakt bij de allereerste boot.

  • microSD-kaart — als een Vision Shield is aangesloten en een kaart is ingestoken, wordt deze gemount op /sdcard.

  • ROMFS — alleen-lezen, in geheugen gemapt bestandssysteem op /rom dat automatisch door MicroPython bij het opstarten wordt gemount.

Na het mounten wordt de werkmap ingesteld op /sdcard wanneer de kaart aanwezig is, anders op /flash. De interpreter draait vervolgens scripts vanuit die map:

  • boot.py wordt uitgevoerd bij elke soft reset (koude boot, Ctrl‑D vanaf de REPL, of telkens wanneer het draaiende script terugkeert).

  • main.py wordt alleen bij een koude boot uitgevoerd, onmiddellijk na boot.py. Daaropvolgende soft resets voeren boot.py opnieuw uit maar vallen direct terug naar de REPL — om main.py opnieuw uit te voeren moet je het bord volledig resetten.

Het neerzetten van een boot.py of main.py op de SD-kaart overschrijft de kopie in flash zonder deze aan te raken — beide bestanden worden opgezocht in de bootmap (/sdcard wanneer de kaart is gemount, anders /flash).

De standaard main.py die op een vers geflasht bord wordt meegeleverd, laat alleen het blauwe kanaal van de RGB-gebruikers-LED knipperen als een hartslag (twee korte pulsen, korte pauze), zodat je kunt zien dat de firmware schoon is opgestart zonder dat er een host is aangesloten.

sys.path wordt uitgebreid om alle drie de bestandssystemen en hun lib/-submappen te bevatten, zodat importeerbare modules in /flash/lib, /sdcard/lib of /rom/lib kunnen staan.

Om het systeem te dwingen een ingestoken SD-kaart te negeren (bijvoorbeeld om de flash-main.py te draaien zelfs met een kaart aanwezig), maak je een leeg bestand met de naam SKIPSD aan in de hoofdmap van /flash.

Wanneer verbonden via USB, wordt het bootbestandssysteem (/sdcard als er een kaart aanwezig is, anders /flash) ook geënumereerd als een USB-massaopslagstation op de host, zodat je boot.py, main.py en alle andere bestanden rechtstreeks kunt bewerken. Werp het station uit voordat je het bord reset zodat de host zijn gebufferde schrijfacties doorvoert.

Notitie

Omdat het besturingssysteem het station als een passief blokapparaat behandelt, zullen bestanden die zijn aangemaakt of gewijzigd door code die op de camera draait, niet verschijnen totdat de host het station opnieuw mount. Als zowel het besturingssysteem als de camera tegelijkertijd naar hetzelfde bestandssysteem schrijven, wint het besturingssysteem en overschrijft het de wijzigingen die door de camera zijn aangebracht. Gebruik de SD-kaart voor alle gegevens die het script terugschrijft, en mount opnieuw voordat je die bestanden vanaf de host leest.

Notitie

Het rode kanaal van de RGB-gebruikers-LED kan kort oplichten terwijl de host van of naar het USB-massaopslagstation leest of schrijft — dit is een door de firmware aangestuurde activiteitsindicator, geen fout.

Opslaggroottes

De Portenta H7 wordt geleverd met:

  • /flash11 MB FAT-bestandssysteem, lezen/schrijven.

  • /rom4 MB alleen-lezen in geheugen gemapt ROMFS, gebruikt om scripts en ML-modellen te leveren die profiteren van zero-copy mmap-toegang.

  • /sdcard — volledige grootte van welke microSD-kaart dan ook is ingestoken in een Vision Shield (indien aanwezig), lezen/schrijven.

Hard‑fault-indicator

Als de RGB-gebruikers-LED snel door alle kleuren cycelt — snel genoeg dat het eerder op een fonkelende witte LED lijkt dan op afzonderlijke tinten — dan heeft de firmware een onherstelbare hard fault bereikt. Flash de firmware opnieuw om te herstellen; als opnieuw flashen niet helpt, is het bord mogelijk fysiek beschadigd.

Softwarebibliotheken

Zie de bibliotheekindex voor de volledige lijst met modules — inclusief welke uniek zijn voor de Portenta H7-build.