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 หลัก
สำหรับ 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¶
อ้างอิงพิน¶
พิน 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 |
D21 |
3.3 V |
alias of |
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พิน MKRVINหรือ 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 เดียวกับ |
2 |
INT |
อินพุต external interrupt บน |
3 |
SCL_EXT |
แชร์กับแพด |
4 |
SDA_EXT |
แชร์กับแพด |
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— NRSTJ1‑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 |
เหตุผล |
|---|---|
|
TIM1 CH1 — clock หลักของกล้อง |
|
TIM1 CH1 (alt) — clock หลักของกล้อง |
|
I²C 3 SDA — แชร์กับกล้อง บัสสามารถใช้งานได้แต่หลีกเลี่ยง I²C address ของเซนเซอร์ ( |
|
I²C 3 SCL — แชร์กับกล้อง บัสสามารถใช้งานได้แต่หลีกเลี่ยง I²C address ของเซนเซอร์ ( |
|
DCMI HSYNC — ปิดใช้งาน DAC ด้วย |
|
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 |
เหตุผล |
|---|---|
|
พิน BOOT ของโมดูล LoRa |
|
พิน 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 V — read_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และD6TIM1 CH2 อยู่บน
D2และD14TIM8 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 ที่
/sdcardROMFS — ระบบไฟล์ 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.pysoft 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