Arduino Portenta H7

Arduino Portenta H7 คือบอร์ดพัฒนาอุตสาหกรรมขนาด 66 × 25 มม. ที่ใช้ชิป STMicroelectronics STM32H747XI ซึ่งเป็น SoC แบบ dual-core รวม Cortex-M7 ที่ 400 MHz กับ Cortex-M4 ที่ 200 MHz เข้าด้วยกัน เฟิร์มแวร์ OpenMV ทำงานบน M7 core เพียงอย่างเดียว และออกแบบมาให้ใช้งานร่วมกับ Portenta Vision Shield (รุ่น Ethernet หรือ LoRa) ซึ่งเพิ่มกล้อง Himax HM01B0 / HM0360 ไมโครโฟน PDM สองตัว และช่องเสียบ microSD ให้กับ Portenta H7 หลัก

Arduino Portenta H7

สำหรับ datasheet ฉบับเต็ม ภาพถ่าย และขนาด โปรดดูที่ Arduino Portenta H7 product page

ไฮไลต์

  • STMicroelectronics STM32H747XI dual Cortex-M7 (400 MHz) + Cortex-M4 (200 MHz) เฟิร์มแวร์ OpenMV รันบน M7 core เท่านั้น ส่วน M4 core ถูกเปิดเผยผ่าน openamp สำหรับการสื่อสารระหว่างโปรเซสเซอร์

  • SDRAM ภายนอก 8 MB บวกกับ แฟลชภายใน 2 MB และ แฟลช QSPI ภายนอก 16 MB

  • ตัวเข้ารหัส/ถอดรหัส JPEG แบบฮาร์ดแวร์

  • Wi-Fi b/g/n (2.4 GHz) + Bluetooth LE 5.1 ผ่านโมดูล Murata 1DX (CYW4343W) — เชื่อมต่อกับเสาอากาศที่มาให้ผ่าน U.FL connector บนบอร์ด

  • USB-C ความเร็วสูง (480 Mb/s)

  • พิน I/O ผู้ใช้ 22 พิน บน Arduino MKR-style top headers — D0–D14 (ดิจิทัล) บวก A0–A6 (อนาล็อก)

  • คอนเน็กเตอร์ความหนาแน่นสูง 80 พิน สองตัว ด้านล่างเปิดเผย STM32H747 fabric ทั้งหมด — DCMI, DSI, Ethernet RMII, FDCAN, SDIO, SAI/I²S, UART, SPI/I²C/ตัวจับเวลาเพิ่มเติม และอื่น ๆ Shield เช่น Vision Shield เชื่อมต่อผ่านคอนเน็กเตอร์เหล่านี้

  • JTAG / SWD เปิดเผยบน HD connectors ด้านล่างสำหรับการดีบักขั้นสูง

  • รองรับแบตเตอรี่ — คอนเน็กเตอร์ JST Li-Po 3.7 V บวกตัวชาร์จและมอนิเตอร์แบตเตอรี่บนบอร์ด

Pinout

Arduino Portenta H7 Pinout

อ้างอิงพิน

พิน 22 ตัวของผู้ใช้เปิดเผยบน Arduino MKR-style top edge headers — 15 ดิจิทัล (D0-D14) บวก 7 อนาล็อก (A0-A6) พิน SoC เพิ่มเติมจำนวนมากพร้อมใช้ผ่าน 80-pin high-density connectors ด้านล่างสำหรับงาน shield ดู full pinout 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 (shared with A3 / A5)

D9

3.3 V

SPI2 SCK

D10

3.3 V

SPI2 MISO (shared with 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 (analog only)

A1

3.3 V

ADC12 IN1 (analog only)

A2

3.3 V

ADC123 IN12 (analog only; shared with D10)

A3

3.3 V

ADC12 IN13 (analog only; shared with D8)

A4

3.3 V

ADC123 IN12 (shared with D10)

A5

3.3 V

ADC12 IN13 (shared with D8)

A6

3.3 V

DAC1 OUT1 / ADC12 IN18

A7

3.3 V

TIM3 CH1 / ADC12 IN3 (not exposed on the headers)

D20

3.3 V

alias of D8 / A3 / A5

D21

3.3 V

alias of A6 — DAC1 OUT1

RESET

3.3 V

กดสวิตช์บนบอร์ดหรือดึงไปยัง GND เพื่อรีเซ็ต

LED_RED

3.3 V

ช่องแดงของ RGB LED (active low)

LED_GREEN

3.3 V

ช่องเขียวของ RGB LED (active low)

LED_BLUE

3.3 V

ช่องน้ำเงินของ RGB LED (active low)

Note

A0-A3 เป็นแพด analog-only บน STM32H747 ที่ไม่มีฟังก์ชัน GPIO — ใช้เป็น ADC input เท่านั้น A2/A4 และ A3/A5 แชร์พินทางกายภาพกับ D10 และ D8 ตามลำดับ ดังนั้นจึงไม่สามารถขับ PWM หรือ SPI บนพินเหล่านั้นขณะอ่านเป็น analog ได้ A7 อยู่บน HD connectors ด้านล่าง

พินพลังงาน

พินบน MKR header:

  • VIN — ราง system หลักเข้า PMIC บนบอร์ด จ่ายผ่าน diode จากราง +5V พิน MKR VIN หรือ HD connectors 80 พินด้านล่าง

  • +5V — ราง 5 V จ่ายจาก USB คอนเน็กเตอร์ ESLOV หรือพิน MKR +5V เอง

  • +3V3 — ราง 3.3 V หลัก (เอาต์พุต switching regulator ของ PMIC)

  • AREF — แรงดันอ้างอิงสำหรับพิน ADC ค่าเริ่มต้นคือ 3.3 V สามารถขับจากภายนอกเพื่อใช้อ้างอิงอื่น

  • GND — กราวด์ร่วม

อินพุตแบตเตอรี่:

  • Li-Po JST ด้านหน้าของบอร์ดรองรับเซลล์ Li-Po 3.7 V PMIC ชาร์จเมื่อมี +5V หรือ VIN

Portenta H7 สามารถจ่ายไฟผ่านทางใดทางหนึ่งเหล่านี้:

  • USB-C — จ่าย 5 V ให้ PMIC บนบอร์ด

  • ESLOV connector — สูงสุด 5 V บน VESLOV (ดู ESLOV connector)

  • พิน VIN — ต่อแหล่งจ่าย 5 V แบบรีกูเลตโดยตรง

  • Li-Po battery — เชื่อมต่อกับ JST ด้านหน้า

ESLOV connector

ด้านข้างของบอร์ดมีคอนเน็กเตอร์ ESLOV 5 พินแบบไม่ต้องบัดกรี:

พิน

ชื่อ

ฟังก์ชัน

1

VESLOV

เอาต์พุตพลังงาน 5 V (ราง rail เดียวกับ +5V ของ MKR header)

2

INT

อินพุต external interrupt บน D7

3

SCL_EXT

แชร์กับแพด D12 ของ MKR header — บัส I²C 3 เดียวกับ user header

4

SDA_EXT

แชร์กับแพด D11 ของ MKR header — บัส I²C 3 เดียวกับ user header

5

GND

กราวด์ร่วม

SCL_EXT/SDA_EXT ของ ESLOV และ D12/D11 ของ MKR header เป็นพินเดียวกัน — บัส I²C 3 หนึ่งตัวเปิดเผยบนคอนเน็กเตอร์สองตัว

Tip

ใช้ battery life estimator เพื่อจำลองว่า Portenta H7 จะรันบนแบตเตอรี่ได้นานแค่ไหนสำหรับ duty cycle active/deep-sleep ที่กำหนด

พินรีคัฟเวอรีและดีบัก

  • RESET — ทั้งพินที่เปิดเผยบน top header และสวิตช์ momentary ด้านข้างของบอร์ด เชื่อมกับสาย NRST ของ SoC ดึงไปยัง GND หรือกดปุ่มเพื่อรีเซ็ต

Portenta H7 ใช้ double-tap reset มาตรฐานของ Arduino เพื่อเข้า Arduino's bootloader กดปุ่ม reset สองครั้งอย่างรวดเร็ว — บอร์ดจะ enumerate ใหม่ผ่าน USB เป็นอุปกรณ์ DFU และ OpenMV IDE สามารถแฟลชเฟิร์มแวร์ภาพใหม่ได้

สัญญาณ STM32 SWD เปิดเผยบน HD connector J1 ด้านล่าง:

  • J1‑73 — NRST

  • J1‑75 — SWDIO (PA13)

  • J1‑77 — SWCLK (PA14)

  • J1‑79 — SWO (PB3)

เชื่อมต่อผ่าน Portenta Breakout, Arduino debug adapter อย่างเป็นทางการ หรือ carrier แบบกำหนดเองที่มีหัว 1.27 มม. สัญญาณดีบักทั้งหมดเป็น 3.3 V referenced

Note

เมื่อ Portenta Vision Shield ถูกติดตั้ง สัญญาณ SWD/JTAG เดียวกันจะถูกส่งไปยัง 20-pin ARM Cortex Debug JTAG header มาตรฐานบน shield (pitch 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()

LED charge สีส้มแยกต่างหากถัดจาก 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 monochrome

  • HM0360 — 640 × 480 monochrome

Warning

ขณะที่กล้อง Vision Shield กำลัง initialize พินบน MKR header ต่อไปนี้จะถูกเฟิร์มแวร์จับจองและ ไม่สามารถใช้งานได้:

พิน MKR

เหตุผล

D1

TIM1 CH1 — clock หลักของกล้อง

D6

TIM1 CH1 (alt) — clock หลักของกล้อง

D11

I²C 3 SDA — แชร์กับกล้อง บัสสามารถใช้งานได้แต่หลีกเลี่ยง I²C address ของเซนเซอร์ (0x24)

D12

I²C 3 SCL — แชร์กับกล้อง บัสสามารถใช้งานได้แต่หลีกเลี่ยง I²C address ของเซนเซอร์ (0x24)

A6 / D21

DCMI HSYNC — ปิดใช้งาน DAC ด้วย

A7

DCMI PXCLK

Machine learning

ml --- Machine Learning รันโมเดล TFLite แบบ quantised บน Cortex-M7 ด้วย kernel CMSIS-NN — เร็วพอสำหรับ detector ขนาดกะทัดรัดที่ความเร็วสองสามเฟรมต่อวินาที โมเดลบนระบบไฟล์ read-only /rom โหลดโดยตรงจากแฟลชโดยไม่ต้องคัดลอกไปยัง RAM ต่อไปนี้คือ BlazeFace detector ขนาด 128×128 ที่วาดทับใบหน้าที่ตรวจพบและ landmark หกจุดในทุกเฟรมจากกล้อง 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 core

Cortex-M4 core เปิดเผยผ่าน openamp สำหรับการสื่อสารระหว่างโปรเซสเซอร์ เฟิร์มแวร์ OpenMV รันบน M7 เท่านั้น M4 ไม่มี MicroPython runtime เป็นของตัวเอง ดังนั้นการใช้งานหมายถึงการสร้างเฟิร์มแวร์ C แยกต่างหากและโหลดจากระบบไฟล์ผ่าน openamp.RemoteProc เฟิร์มแวร์ตัวอย่างที่สร้างไว้แล้วซึ่ง implement virtual UART endpoint มีให้ใน repository 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 interface มากกว่า platform dual-core ที่ใช้งานได้จริง — M4 ไม่สามารถรีเซ็ตแยกจาก M7 ได้ ดังนั้นการหยุด M4 จะบังคับให้รีบูตระบบทั้งหมด

ไมโครโฟน (Vision Shield)

Vision Shield มี PDM microphone สองตัว ที่รับสัญญาณผ่าน audio --- โมดูล Audio บน peripheral SAI4 ของ STM32 บัฟเฟอร์แต่ละอันมาเป็น PCM bytearray แบบ signed 16-bit พร้อมป้อนเข้า 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 เพื่อรับตัวอย่างแบบ interleaved จากไมโครโฟนทั้งสอง

Battery fuel gauge

MAX17262 ModelGauge m5 fuel gauge ของ Maxim ติดตามแรงดัน กระแส อุณหภูมิ และสถานะการชาร์จของแบตเตอรี่ Li-Po อยู่บน I²C 1 ที่ address 0x36

MAX17262 มีการวัดกระแส ภายใน ดังนั้น current register จะอ่านออกมาโดยตรงในหน่วย microamp โดยไม่ต้องใช้ Rsense factor ภายนอก การอ่าน fuel gauge ปลอดภัย — ไม่มีไดรเวอร์มาให้ แต่ register ที่ระบุไว้ใน MAX17262 datasheet สามารถอ่านได้โดยตรง:

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 เป็น signed two's-complement: บวกขณะชาร์จ ลบขณะคายประจุ TTE มีความหมายเฉพาะเมื่อกระแสเป็นลบ TTF เฉพาะเมื่อกระแสเป็นบวก

Power management IC

PF1550 PMIC ของ NXP จัดการ regulator ทุกตัวบน Portenta H7 — ราง +3V3 หลัก ราง +1V8 SoC core/I/O และตัวชาร์จ Li-Po อยู่บน I²C 1 ที่ address 0x08

Warning

การอ่าน PMIC register ปลอดภัย แต่การเขียนเป็นอันตราย การกำหนดค่า buck regulator หรือตั้งค่าตัวชาร์จผิดพลาดอาจทำให้บอร์ด แบตเตอรี่ หรือทั้งสองเสียหายถาวร ถือว่า PMIC เป็น read-only ยกเว้นคุณรู้ว่ากำลังทำอะไรอยู่

สิ่งที่ PMIC บอกคุณได้ดีที่สุดซึ่ง fuel gauge ทำไม่ได้คือ charger state machine — ว่าบอร์ดกำลังทำงานบน USB / ESLOV / VIN อยู่หรือเปล่า บน Li-Po อยู่ในขั้นตอนไหนของรอบการชาร์จ และตัวชาร์จอยู่ในสภาวะผิดพลาดทางความร้อนหรือ watchdog หรือไม่ charger register อยู่ที่ offset 0x80 ใน I²C address space หลักของ PF1550 (ดู §22.2 ของ PF1550 datasheet) ดังนั้นตัวอย่าง CHG_INT_OK ที่ charger address 0x04 อ่านจาก 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)

register อื่นที่ควรดูใน datasheet แบบ read-only (ทั้งหมดที่ charger-offset 0x80): 0x80 CHG_INT (latched charger interrupts — fault flags), 0x86 VBUS_SNS (multi-bit VBUS state รวมถึง OVLO / UVLO / DPM), และ 0x88 BATT_SNS (การตรวจสอบแบตเตอรี่และสถานะ overcurrent)

Wi-Fi

Murata 1DX (CYW4343W) บนบอร์ดเปิดเผยผ่าน network --- การกำหนดค่าเครือข่าย เป็น station interface เชื่อมต่อเสาอากาศที่มาให้กับ U.FL connector บนบอร์ดก่อนเปิดใช้งานวิทยุ:

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 --- Async BLE สำหรับ BLE แบบ asyncio-friendly — ตัวอย่างเช่น advertise เป็น peripheral และรอ central เชื่อมต่อ:

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 edition ของ Vision Shield เพิ่มโมดูล Murata CMWX1ZZABZ LoRaWAN ที่ต่อสายกับ Portenta H7 ผ่าน UART โมดูล lora ครอบ AT-command firmware และรองรับ OTAA หรือ ABP join, 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 ฯลฯ สำหรับภูมิภาคนอก EU และเปลี่ยนไปใช้ lora.Lora.join_ABP() หากเซิร์ฟเวอร์เครือข่ายของคุณใช้การ activate แบบ ABP

Warning

ขณะที่โมดูล LoRa กำลังใช้งาน ไดรเวอร์จะจับจองพินต่อไปนี้บน MKR header เป็นสายควบคุมสำหรับ Murata CMWX1ZZABZ — พินเหล่านี้ ไม่สามารถใช้งานได้:

พิน MKR

เหตุผล

D3

พิน BOOT ของโมดูล LoRa

D5

พิน RST ของโมดูล LoRa

Ethernet (Vision Shield)

Ethernet edition ของ Vision Shield เพิ่ม RJ45 jack พร้อม magnetics ที่ต่อสายกับ 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 card (Vision Shield)

เมื่อใส่การ์ด มันจะถูก mount อัตโนมัติที่ /sdcard และใช้งานได้ผ่านระบบไฟล์ปกติ:

import os

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

อ้างอิงบัส

GPIO

ใช้ machine.Pin เพื่ออ่านหรือขับพินที่มี silkscreen ใดก็ได้ เอาต์พุตเป็น 3.3 V CMOS และสามารถ sink/source ได้สูงสุด 20 mA ต่อพิน (140 mA รวมทั้ง 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())

พินอินพุตใดก็ได้สามารถ fire interrupt บน edge transitions ได้:

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 header และพิน SDA_EXT/SCL_EXT ของ ESLOV connector อยู่บนบัส I²C 3 เดียวกัน — ดู ESLOV connector ด้านบนสำหรับ pinout ของ ESLOV

ฮาร์ดแวร์เดียวกันยังสามารถใช้ในโหมด target (slave) ผ่าน machine.I2CTarget เพื่อเปิดเผย memory region ให้ I²C controller อื่น:

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 channel 12-bit แปดช่องบน 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 channel 12-bit หนึ่งช่องเปิดเผยบน 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)

Note

พินหลายตัวแชร์ timer channel:

  • TIM1 CH1 อยู่บน D1 และ D6

  • TIM1 CH2 อยู่บน D2 และ D14

  • TIM8 CH3N อยู่บน D0 และ D1

เลือก consumer หนึ่งตัวต่อ timer channel

Warning

TIM1 ถูกสงวนไว้สำหรับ camera master clock เมื่อ Vision Shield ถูก initialize ผ่าน csi --- เซ็นเซอร์กล้องD1, D2, D6, D13, และ D14 ไม่สามารถขับ PWM ขณะที่กล้องทำงานอยู่

บัส bit-banged ด้วยซอฟต์แวร์

machine.SoftI2C และ machine.SoftSPI ทำงานบน GPIO ใดก็ได้หากคุณต้องการบัสเพิ่มเติม

เซนเซอร์ความร้อน (นอกบอร์ด)

เฟิร์มแวร์รวมไดรเวอร์ fir --- ไดรเวอร์เซนเซอร์ความร้อน (fir == far infrared) สำหรับ thermal imager ที่ต่อสายจากภายนอก:

  • 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 ครอบคลุม blocking delays, monotonic ticks และการวัดเวลาที่ผ่านไป:

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 แบบ periodic หรือ one-shot โดยไม่ใช้ hardware timer slot ส่ง -1 เป็น id เพื่อใช้ตัวจับเวลาเสมือน (software):

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

ค่า period เป็นมิลลิวินาที เรียก deinit() เพื่อหยุดและปล่อย slot

Real-time clock

machine.RTC เก็บเวลาตามนาฬิกาแขวนตลอดการรีเซ็ต HD connector ยังเปิดเผยแพด 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 รีเซ็ตบอร์ดหากแอปพลิเคชันค้าง เมื่อเริ่มแล้วไม่สามารถหยุดหรือกำหนดค่าใหม่ได้ — ป้อนมันเป็นระยะภายใน main loop:

from machine import WDT

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

ข้อมูลการบูตและ runtime

อัปเดตเฟิร์มแวร์ (DFU)

Portenta H7 ใช้ double-tap reset มาตรฐานของ Arduino เพื่อเข้า Arduino's bootloader กดปุ่ม reset สองครั้งอย่างรวดเร็ว — บอร์ดจะ enumerate ใหม่ผ่าน USB เป็นอุปกรณ์ DFU และ OpenMV IDE สามารถแฟลชเฟิร์มแวร์ภาพใหม่ได้

สคริปต์ที่กำลังรันสามารถเข้า bootloader ได้ตามต้องการโดยเรียก machine.bootloader()

import machine

machine.bootloader()

ระบบไฟล์และลำดับการบูต

เฟิร์มแวร์ Portenta H7 mount ระบบไฟล์สูงสุดสามระบบตอนบูต:

  • แฟลชภายใน — mount ที่ /flash เสมอ เก็บ main.py และ README.txt ตามค่าเริ่มต้น สร้างขึ้นในการบูตครั้งแรก

  • microSD card — หาก Vision Shield ติดตั้งอยู่และมีการ์ดใส่ไว้ จะถูก mount ที่ /sdcard

  • ROMFS — ระบบไฟล์ read-only แบบ memory-mapped ที่ /rom ถูก mount อัตโนมัติโดย MicroPython ตอนเริ่มต้น

หลังจาก mounting working directory จะตั้งเป็น /sdcard เมื่อมีการ์ด ไม่เช่นนั้นเป็น /flash จากนั้น interpreter จะรันสคริปต์จากไดเรกทอรีนั้น:

  • boot.py รันทุก soft reset (cold boot, Ctrl‑D จาก REPL หรือเมื่อสคริปต์ที่รันอยู่ return)

  • main.py รัน เฉพาะ cold boot ทันทีหลัง boot.py soft reset ครั้งถัดไปจะรัน boot.py อีกครั้งแต่ตกลงไปยัง REPL โดยตรง — หากต้องการรัน main.py ใหม่ต้องรีเซ็ตบอร์ดเต็มรูปแบบ

การวาง boot.py หรือ main.py ลงในการ์ด SD จะ override สำเนาในแฟลชโดยไม่แตะต้องมัน — ทั้งสองไฟล์จะถูกค้นหาในไดเรกทอรีบูต (/sdcard เมื่อ mount การ์ดแล้ว ไม่เช่นนั้น /flash)

main.py ค่าเริ่มต้นที่มาพร้อมกับบอร์ดที่แฟลชใหม่เพียงแค่กะพริบช่อง blue ของ RGB LED ผู้ใช้เป็น heartbeat (สองพัลส์สั้น ช่วงพักสั้น) เพื่อให้รู้ว่าเฟิร์มแวร์บูตสำเร็จโดยไม่ต้องต่อกับ host

sys.path ถูกขยายให้รวมระบบไฟล์ทั้งสามและ subdirectory lib/ ของมัน ดังนั้นโมดูลที่ import ได้อาจอยู่ใน /flash/lib, /sdcard/lib หรือ /rom/lib

หากต้องการบังคับให้ระบบเพิกเฉยต่อการ์ด SD ที่ใส่ไว้ (ตัวอย่างเช่น เพื่อรัน main.py ในแฟลชแม้จะมีการ์ดอยู่) ให้สร้างไฟล์เปล่าชื่อ SKIPSD ที่ root ของ /flash

เมื่อเชื่อมต่อผ่าน USB boot filesystem (/sdcard หากมีการ์ด ไม่เช่นนั้น /flash) ยัง enumerate เป็น USB mass-storage drive บน host ช่วยให้แก้ไข boot.py, main.py และไฟล์อื่น ๆ ได้โดยตรง Eject drive ก่อนรีเซ็ตบอร์ด เพื่อให้ host flush cached writes

Note

เนื่องจาก OS ถือว่า drive เป็น passive block device ไฟล์ที่สร้างหรือแก้ไขโดยโค้ดที่รันบนกล้องจะไม่ปรากฏจนกว่า host จะ remount drive หาก OS และกล้องเขียน filesystem เดียวกันพร้อมกัน OS จะชนะและเขียนทับการเปลี่ยนแปลงของกล้อง ใช้ SD card สำหรับข้อมูลที่สคริปต์เขียนกลับ และ remount ก่อนอ่านไฟล์เหล่านั้นจาก host

Note

ช่อง red ของ RGB LED ผู้ใช้อาจสว่างชั่วคราวขณะที่ host กำลังอ่านจากหรือเขียนไปยัง USB mass-storage drive — นี่เป็นตัวบ่งชี้กิจกรรมที่ขับโดยเฟิร์มแวร์ ไม่ใช่ข้อผิดพลาด

ขนาดพื้นที่เก็บข้อมูล

Portenta H7 มาพร้อมกับ:

  • /flash — ระบบไฟล์ FAT 11 MB อ่าน/เขียน

  • /rom — ROMFS แบบ read-only memory-mapped ขนาด 4 MB ใช้สำหรับจัดส่งสคริปต์และโมเดล ML ที่ได้ประโยชน์จากการเข้าถึง mmap แบบ zero-copy

  • /sdcard — ขนาดเต็มของ microSD card ที่ใส่ใน Vision Shield (เมื่อมี) อ่าน/เขียน

ตัวบ่งชี้ hard-fault

หาก RGB LED ผู้ใช้กำลังวนรอบสีทั้งหมดอย่างรวดเร็ว — เร็วพอที่มักดูเหมือน LED สีขาวกระพริบ มากกว่าสีแยกกัน — เฟิร์มแวร์ประสบ hard fault ที่ไม่สามารถกู้คืนได้ Reflash เฟิร์มแวร์เพื่อกู้คืน หากการ reflash ไม่ช่วย บอร์ดอาจเสียหายทางกายภาพ

ไลบรารีซอฟต์แวร์

ดู library index สำหรับรายการโมดูลทั้งหมด — รวมถึงรายการที่เป็นเอกลักษณ์ของ Portenta H7 build