Arduino Portenta H7¶
Arduino Portenta H7는 STMicroelectronics STM32H747XI를 중심으로 설계된 66 × 25 mm 산업용 개발 보드로, 이 칩은 400 MHz의 Cortex-M7과 200 MHz의 Cortex-M4를 결합한 듀얼 코어 SoC입니다. OpenMV 펌웨어는 전적으로 M7 코어에서 실행되며, 기본 Portenta H7에 Himax HM01B0 / HM0360 카메라, 듀얼 PDM 마이크, microSD 슬롯을 추가하는 Portenta Vision Shield(Ethernet 또는 LoRa 에디션)와 함께 사용하도록 설계되었습니다.
전체 데이터시트, 사진, 치수는 Arduino Portenta H7 제품 페이지를 참조하세요.
주요 특징¶
STMicroelectronics STM32H747XI 듀얼 Cortex‑M7 (400 MHz) + Cortex‑M4 (200 MHz). OpenMV 펌웨어는 M7 코어에서만 실행되며, M4 코어는 프로세서 간 통신을 위해 openamp를 통해 노출됩니다.
8 MB 외부 SDRAM과 2 MB 내부 플래시, 16 MB 외부 QSPI 플래시.
하드웨어 JPEG 인코더/디코더.
Murata 1DX (CYW4343W) 모듈을 통한 Wi‑Fi b/g/n (2.4 GHz) + Bluetooth LE 5.1 — 온보드 U.FL 커넥터를 통해 제공된 안테나에 연결됩니다.
고속 USB‑C (480 Mb/s).
Arduino MKR 스타일 상단 헤더의 22개 사용자 I/O 핀 — D0–D14(디지털)과 A0–A6(아날로그).
하단의 두 개의 80핀 고밀도 커넥터는 STM32H747의 전체 패브릭을 노출합니다 — DCMI, DSI, 이더넷 RMII, FDCAN, SDIO, SAI/I²S, UART, 추가 SPI/I²C/타이머 등. Vision Shield 같은 실드는 이 커넥터에 결합됩니다.
고급 디버그를 위해 하단 HD 커넥터에 JTAG / SWD가 노출되어 있습니다.
배터리 지원 — 3.7 V Li‑Po JST 커넥터와 온보드 충전기 및 배터리 모니터.
핀아웃¶
핀 레퍼런스¶
22개의 사용자 핀이 Arduino MKR 스타일 상단 에지 헤더에 노출되어 있습니다 — 15개의 디지털 핀(D0-D14)과 7개의 아날로그 핀(A0-A6). 실드 작업을 위해 하단 80핀 고밀도 커넥터를 통해 훨씬 더 많은 SoC 핀을 사용할 수 있습니다. 해당 매핑은 Arduino의 전체 핀아웃 PDF를 참조하세요.
핀 이름 |
레퍼런스 |
기능 |
|---|---|---|
D0 |
3.3 V |
TIM8 CH3N |
D1 |
3.3 V |
TIM1 CH1 / SPI5 NSS |
D2 |
3.3 V |
TIM1 CH2 / SPI5 MISO |
D3 |
3.3 V |
GPIO |
D4 |
3.3 V |
TIM3 CH2 / TIM8 CH2 / USART6 RX |
D5 |
3.3 V |
TIM3 CH1 / TIM8 CH1 / USART6 TX |
D6 |
3.3 V |
TIM1 CH1 / I2C3 SCL |
D7 |
3.3 V |
TIM5 CH4 / SPI2 NSS |
D8 |
3.3 V |
SPI2 MOSI (A3 / A5와 공유) |
D9 |
3.3 V |
SPI2 SCK |
D10 |
3.3 V |
SPI2 MISO (A2 / A4와 공유) |
D11 |
3.3 V |
I2C3 SDA |
D12 |
3.3 V |
I2C3 SCL |
D13 |
3.3 V |
USART1 RX / TIM1 CH3 |
D14 |
3.3 V |
USART1 TX / TIM1 CH2 |
A0 |
3.3 V |
ADC12 IN0 (아날로그 전용) |
A1 |
3.3 V |
ADC12 IN1 (아날로그 전용) |
A2 |
3.3 V |
ADC123 IN12 (아날로그 전용; D10과 공유) |
A3 |
3.3 V |
ADC12 IN13 (아날로그 전용; D8과 공유) |
A4 |
3.3 V |
ADC123 IN12 (D10과 공유) |
A5 |
3.3 V |
ADC12 IN13 (D8과 공유) |
A6 |
3.3 V |
DAC1 OUT1 / ADC12 IN18 |
A7 |
3.3 V |
TIM3 CH1 / ADC12 IN3 (헤더에 노출되지 않음) |
D20 |
3.3 V |
|
D21 |
3.3 V |
|
RESET |
3.3 V |
온보드 스위치를 누르거나 GND로 당겨 리셋 |
LED_RED |
3.3 V |
RGB LED 빨강 채널 (액티브 로우) |
LED_GREEN |
3.3 V |
RGB LED 초록 채널 (액티브 로우) |
LED_BLUE |
3.3 V |
RGB LED 파랑 채널 (액티브 로우) |
참고
A0-A3은 STM32H747의 아날로그 전용 패드로 GPIO 기능이 없습니다 — ADC 입력으로만 취급하세요. A2/A4와 A3/A5는 각각 D10 및 D8과 물리적 핀을 공유하므로, 이를 아날로그로 읽는 동안에는 해당 핀에서 PWM이나 SPI를 구동할 수 없습니다. A7은 하단 HD 커넥터에 있습니다.
전원 핀¶
MKR 헤더 핀:
VIN — 온보드 PMIC로 들어가는 주 시스템 레일입니다.
+5V레일, MKRVIN핀, 또는 하단 80핀 HD 커넥터로부터 다이오드를 통해 공급됩니다.+5V — USB, ESLOV 커넥터, 또는 MKR
+5V핀 자체로부터 공급되는 5 V 레일입니다.+3V3 — 주 3.3 V 레일 (PMIC 스위칭 레귤레이터 출력).
AREF — ADC 핀용 아날로그 전압 기준입니다. 기본값은 3.3 V이며, 다른 기준을 사용하려면 외부에서 구동하세요.
GND — 공통 그라운드.
배터리 입력:
보드 전면의 Li‑Po JST는 3.7 V Li‑Po 셀을 받습니다.
+5V또는VIN이 있을 때마다 PMIC가 충전합니다.
Portenta H7은 다음 경로 중 어느 것으로든 전원을 공급받을 수 있습니다:
USB‑C — 온보드 PMIC에 5 V를 공급합니다.
ESLOV 커넥터 —
VESLOV에서 최대 5 V (ESLOV 커넥터 참조).VIN 핀 — 조정된 5 V 전원을 직접 구동합니다.
Li‑Po 배터리 — 전면의 JST에 연결합니다.
ESLOV 커넥터¶
보드 측면에는 5핀 무납땜 ESLOV 커넥터가 있습니다:
핀 |
이름 |
기능 |
|---|---|---|
1 |
VESLOV |
5 V 전원 출력 (MKR 헤더의 |
2 |
INT |
|
3 |
SCL_EXT |
MKR 헤더 |
4 |
SDA_EXT |
MKR 헤더 |
5 |
GND |
공통 그라운드 |
ESLOV의 SCL_EXT/SDA_EXT와 MKR 헤더의 D12/D11은 동일한 핀입니다 — 하나의 I²C 3 버스가 두 커넥터에 노출됩니다.
팁
주어진 활성 / 딥 슬립 듀티 사이클에서 Portenta H7이 배터리로 얼마나 오래 동작할지 모델링하려면 배터리 수명 추정기를 사용하세요.
복구 및 디버그 핀¶
RESET — 상단 헤더에 노출된 핀이자 보드 측면의 모멘터리 스위치로, SoC의 NRST 라인에 연결되어 있습니다. GND로 당기거나 버튼을 눌러 리셋합니다.
Portenta H7은 Arduino의 부트로더에 진입하기 위해 Arduino의 표준 더블‑탭 리셋을 사용합니다. 리셋 버튼을 빠르게 두 번 누르면 보드가 USB를 통해 DFU 장치로 다시 열거되며, OpenMV IDE가 새 펌웨어 이미지를 플래시할 수 있습니다.
STM32 SWD 신호는 하단 HD 커넥터 J1에 노출되어 있습니다:
J1‑73— NRSTJ1‑75— SWDIO (PA13)J1‑77— SWCLK (PA14)J1‑79— SWO (PB3)
Portenta Breakout, 공식 Arduino 디버그 어댑터, 또는 1.27 mm 헤더가 있는 커스텀 캐리어를 통해 연결하세요. 모든 디버그 신호는 3.3 V 기준입니다.
참고
Portenta Vision Shield가 장착되면, 동일한 SWD/JTAG 신호가 실드의 표준 20핀 ARM Cortex Debug JTAG 헤더(1.27 mm / 0.05″ 피치)로 라우팅됩니다.
온보드 주변장치¶
LED¶
Portenta H7에는 machine.LED를 통해 소프트웨어로 제어 가능한 단일 사용자 RGB LED가 있습니다:
from machine import LED
LED("LED_RED").on()
LED("LED_GREEN").on()
LED("LED_BLUE").on()
배터리 JST 옆의 별도 주황색 충전 LED는 온보드 충전기가 연결된 Li‑Po에 전류를 공급할 때 켜집니다. 이 LED는 사용자가 제어할 수 없습니다.
카메라 센서 (Vision Shield)¶
Portenta Vision Shield(Ethernet 또는 LoRa 에디션)가 장착되면, Himax 센서는 csi — 카메라 센서 모듈을 통해 구동됩니다:
import csi
cam = csi.CSI()
cam.reset()
cam.pixformat(csi.GRAYSCALE)
cam.framesize(csi.QVGA)
cam.snapshot(time=2000) # let auto‑exposure settle
while True:
img = cam.snapshot()
두 가지 Vision Shield 리비전이 지원됩니다:
HM01B0 — 320 × 320 모노크롬.
HM0360 — 640 × 480 모노크롬.
경고
Vision Shield 카메라가 초기화되는 동안, 다음 MKR 헤더 핀은 펌웨어가 점유하므로 사용할 수 없습니다:
MKR 핀 |
이유 |
|---|---|
|
TIM1 CH1 — 카메라 마스터 클럭 |
|
TIM1 CH1 (대체) — 카메라 마스터 클럭 |
|
I²C 3 SDA — 카메라와 공유; 버스는 사용 가능하나 센서의 I²C 주소( |
|
I²C 3 SCL — 카메라와 공유; 버스는 사용 가능하나 센서의 I²C 주소( |
|
DCMI HSYNC — DAC도 비활성화됩니다 |
|
DCMI PXCLK |
머신 러닝¶
ml — 머신 러닝은 CMSIS‑NN 커널과 함께 Cortex‑M7에서 양자화된 TFLite 모델을 실행합니다 — 초당 몇 프레임으로 컴팩트한 검출기를 돌릴 만큼 충분히 빠릅니다. 읽기 전용 /rom 파일 시스템의 모델은 RAM으로 복사하지 않고 플래시에서 직접 로드됩니다. 다음은 Vision Shield 카메라의 모든 프레임에서 검출된 얼굴과 그 여섯 개의 랜드마크를 오버레이하는 128×128 BlazeFace 검출기입니다:
import csi
import time
import ml
from ml.postprocessing.mediapipe import BlazeFace
# Initialize the sensor.
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.GRAYSCALE)
csi0.framesize(csi.QVGA)
csi0.window((240, 240))
# Load built-in face detection model
model = ml.Model("/rom/blazeface_front_128.tflite", postprocess=BlazeFace(threshold=0.4))
print(model)
clock = time.clock()
while True:
clock.tick()
img = csi0.snapshot()
# faces is a list of ((x, y, w, h), score, keypoints) tuples
for r, score, keypoints in model.predict([img]):
ml.utils.draw_predictions(img, [r], ("face",), ((0, 0, 255),), format=None)
# keypoints is a ndarray of shape (6, 2)
ml.utils.draw_keypoints(img, keypoints, color=(255, 0, 0))
print(clock.fps(), "fps")
M4 코어¶
Cortex‑M4 코어는 프로세서 간 통신을 위해 openamp를 통해 노출됩니다. OpenMV 펌웨어는 M7에서만 실행되며, M4에는 자체 MicroPython 런타임이 없으므로 이를 사용하려면 별도의 C 펌웨어 이미지를 빌드하여 openamp.RemoteProc를 통해 파일 시스템에서 로드해야 합니다. 가상 UART 엔드포인트를 구현하는 사전 빌드된 예제 펌웨어는 openamp_vuart 저장소에서 제공됩니다 — README를 따라 vuart.elf를 빌드하세요:
import openamp
import time
def ept_recv_callback(src_addr, data):
print("Received:", data.decode())
ept = openamp.Endpoint("vuart-channel", callback=ept_recv_callback)
rproc = openamp.RemoteProc("vuart.elf")
rproc.start()
count = 0
while True:
if ept.is_ready():
ept.send("Hello World %d!" % count, timeout=1000)
count += 1
time.sleep_ms(1000)
실제로 이 지원은 작동하는 듀얼 코어 플랫폼이라기보다 openamp 인터페이스의 데모로 보는 것이 가장 좋습니다 — M4는 M7과 독립적으로 리셋할 수 없으므로, M4를 정지시키면 전체 시스템이 재부팅됩니다.
마이크 (Vision Shield)¶
Vision Shield에는 STM32의 SAI4 주변장치를 통해 audio — 오디오 모듈로 캡처되는 듀얼 PDM 마이크가 탑재되어 있습니다. 각 버퍼는 부호 있는 16비트 PCM bytearray로 도착하여, DSP를 위해 ulab/numpy에 바로 공급할 수 있습니다 — 예를 들어, 간단한 음량 검출기는 다음과 같습니다:
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
두 마이크의 인터리브된 샘플을 받으려면 audio.init에 channels=2를 전달하세요.
배터리 연료 게이지¶
Maxim MAX17262 ModelGauge m5 연료 게이지는 Li‑Po 배터리의 전압, 전류, 온도, 충전 상태를 추적합니다. I²C 1의 0x36 주소에 있습니다.
MAX17262는 내부 전류 감지 기능을 갖추고 있어, 적용할 외부 Rsense 계수 없이 전류 레지스터가 마이크로암페어 단위로 직접 읽힙니다. 연료 게이지를 읽는 것은 무해합니다 — 제공되는 드라이버는 없지만, MAX17262 데이터시트에 문서화된 레지스터를 직접 읽을 수 있습니다:
import time
import struct
from machine import I2C
FUEL_GAUGE = 0x36 # MAX17262
def read_reg(bus, addr, reg):
return struct.unpack("<H", bus.readfrom_mem(addr, reg, 2))[0]
def read_signed(bus, addr, reg):
v = read_reg(bus, addr, reg)
return v - 0x10000 if v & 0x8000 else v
bus = I2C(1)
while True:
# 0x05 RepCap — remaining capacity, raw × 0.5 mAh
rep_cap = read_reg(bus, FUEL_GAUGE, 0x05) * 0.5
# 0x06 RepSOC — state of charge, raw / 256 %
soc = read_reg(bus, FUEL_GAUGE, 0x06) / 256
# 0x08 Temp — die temperature, signed, raw / 256 °C
temp = read_signed(bus, FUEL_GAUGE, 0x08) / 256
# 0x09 VCell — battery voltage, raw × 78.125 µV
vcell = read_reg(bus, FUEL_GAUGE, 0x09) * 78.125 / 1_000_000
# 0x0A Current — signed, raw × 156.25 µA
current = read_signed(bus, FUEL_GAUGE, 0x0A) * 156.25 / 1000
# 0x0B AvgCurrent — averaged current
avg_curr = read_signed(bus, FUEL_GAUGE, 0x0B) * 156.25 / 1000
# 0x10 FullCapRep — learned full capacity, raw × 0.5 mAh
full_cap = read_reg(bus, FUEL_GAUGE, 0x10) * 0.5
# 0x11 TTE — time-to-empty (valid while discharging), raw × 5.625 s
tte_s = read_reg(bus, FUEL_GAUGE, 0x11) * 5.625
# 0x20 TTF — time-to-full (valid while charging), raw × 5.625 s
ttf_s = read_reg(bus, FUEL_GAUGE, 0x20) * 5.625
# 0x17 Cycles — charge-cycle counter, 1% per LSB
cycles = read_reg(bus, FUEL_GAUGE, 0x17) / 100
print("V: %.3f V" % vcell)
print("Capacity: %.1f / %.1f mAh (%.1f %%)" % (rep_cap, full_cap, soc))
print("Temp: %.1f C" % temp)
print("Current: %.1f mA (avg %.1f mA)" % (current, avg_curr))
print("TTE: %.0f s TTF: %.0f s" % (tte_s, ttf_s))
print("Cycles: %.2f" % cycles)
print()
time.sleep_ms(1000)
Current는 부호 있는 2의 보수입니다: 충전 중에는 양수, 방전 중에는 음수입니다. TTE는 전류가 음수일 때만 의미가 있고, TTF는 전류가 양수일 때만 의미가 있습니다.
전원 관리 IC¶
NXP PF1550 PMIC는 Portenta H7의 모든 레귤레이터를 처리합니다 — +3V3 주 레일, +1V8 SoC 코어 / I/O 레일, 그리고 Li‑Po 충전기. I²C 1의 0x08 주소에 있습니다.
경고
PMIC 레지스터를 읽는 것은 괜찮지만, 쓰는 것은 위험합니다. 벅 레귤레이터나 충전기 설정을 잘못 구성하면 보드, 배터리, 또는 둘 다를 영구적으로 손상시킬 수 있습니다. 정확히 무엇을 하는지 알지 못한다면 PMIC를 읽기 전용으로 취급하세요.
PMIC가 연료 게이지로는 알 수 없는 가장 유용한 정보는 충전기 상태 머신입니다 — 보드가 현재 USB / ESLOV / VIN으로 동작 중인지, Li‑Po가 충전 사이클의 어느 단계에 있는지, 충전기가 열 또는 워치독 결함 상태인지 등입니다. 충전기 레지스터는 PF1550의 주 I²C 주소 공간에서 0x80 오프셋에 위치하므로(PF1550 데이터시트의 §22.2 참조), 예를 들어 충전기 주소 0x04의 CHG_INT_OK는 PMIC 레지스터 0x84에서 읽힙니다:
import time
from machine import I2C
PMIC = 0x08
# Charger state machine (low nibble of CHG_SNS, register 0x87)
CHG_STATES = {
0x0: "precharge",
0x1: "fast charge (constant current)",
0x2: "fast charge (constant voltage)",
0x3: "end of charge",
0x4: "done",
0x6: "timer fault",
0x7: "thermistor suspend",
0x8: "off — input invalid or charger disabled",
0x9: "battery overvoltage",
0xA: "thermal shutdown",
0xC: "linear mode (not charging)",
}
bus = I2C(1)
while True:
# 0x84 CHG_INT_OK — single-bit indicators
ok = bus.readfrom_mem(PMIC, 0x84, 1)[0]
vbus_ok = bool(ok & (1 << 5)) # bit 5 — VBUS valid (USB/VIN)
bat_ok = bool(ok & (1 << 2)) # bit 2 — battery OK
chg_ok = bool(ok & (1 << 3)) # bit 3 — charger actively charging
thm_ok = bool(ok & (1 << 7)) # bit 7 — thermistor in normal range
# 0x87 CHG_SNS — charger state + thermal regulation flag
chg_sns = bus.readfrom_mem(PMIC, 0x87, 1)[0]
state = CHG_STATES.get(chg_sns & 0x0F, "reserved")
treg = bool(chg_sns & (1 << 7)) # thermal regulation active
print("VBUS valid: ", vbus_ok)
print("battery OK: ", bat_ok)
print("charger active: ", chg_ok)
print("thermistor normal: ", thm_ok)
print("thermal reg active: ", treg)
print("state: ", state)
print()
time.sleep_ms(1000)
데이터시트에서 살펴볼 만한 다른 읽기 전용 레지스터들(모두 충전기 오프셋 0x80 기준): 0x80 CHG_INT(래치된 충전기 인터럽트 — 오류 플래그), 0x86 VBUS_SNS(OVLO / UVLO / DPM을 포함한 다중 비트 VBUS 상태), 0x88 BATT_SNS(배터리 존재 여부 및 과전류 상태).
Wi‑Fi¶
온보드 Murata 1DX (CYW4343W)는 network — 네트워크 구성를 통해 스테이션 인터페이스로 노출됩니다. 라디오를 켜기 전에 제공된 안테나를 온보드 U.FL 커넥터에 연결하세요:
import network, time
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("ssid", "password")
while not wlan.isconnected():
time.sleep(1)
print("Wi‑Fi IP:", wlan.ipconfig("addr4")[0])
Bluetooth¶
동일한 Murata 1DX는 Bluetooth LE 5.1도 노출합니다. asyncio 친화적인 BLE를 위해 aioble — 비동기 BLE를 사용하세요 — 예를 들어, 주변장치로 광고하고 센트럴이 연결될 때까지 기다립니다:
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)¶
Vision Shield의 LoRa 에디션은 UART를 통해 Portenta H7에 연결된 Murata CMWX1ZZABZ LoRaWAN 모듈을 추가합니다. lora 모듈은 AT 명령어 펌웨어를 래핑하며 OTAA 또는 ABP 조인, 업링크, 다운링크를 지원합니다:
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()
비‑EU 지역에는 BAND_US915 / BAND_AS923 / BAND_AU915 등을 사용하고, 네트워크 서버가 ABP 활성화를 사용하는 경우 lora.Lora.join_ABP()로 전환하세요.
경고
LoRa 모듈이 사용 중인 동안, 드라이버는 Murata CMWX1ZZABZ의 제어 라인으로 다음 MKR 헤더 핀을 점유합니다 — 이들은 사용할 수 없습니다:
MKR 핀 |
이유 |
|---|---|
|
LoRa 모듈 BOOT 핀 |
|
LoRa 모듈 RST 핀 |
이더넷 (Vision Shield)¶
Vision Shield의 이더넷 에디션은 RMII를 통해 STM32H747의 10/100 이더넷 MAC에 연결된 마그네틱 포함 RJ45 잭을 추가합니다. 이더넷 케이블을 꽂으면 PHY가 LAN 인터페이스로 나타나며, 링크가 올라오면 DHCP가 자동으로 실행됩니다:
import network
import time
lan = network.LAN()
lan.active(True)
while not lan.isconnected():
time.sleep(1)
print("Ethernet IP:", lan.ipconfig("addr4")[0])
microSD 카드 (Vision Shield)¶
카드가 삽입되면 자동으로 /sdcard에 마운트되며 일반 파일 시스템을 통해 사용할 수 있습니다:
import os
for entry in os.listdir("/sdcard"):
print(entry)
버스 레퍼런스¶
GPIO¶
실크스크린된 핀 중 어느 것이든 읽거나 구동하려면 machine.Pin을 사용하세요. 출력은 3.3 V CMOS이며 핀당 최대 20 mA를 싱크/소스할 수 있습니다(헤더 전체에서 총 140 mA).
from machine import Pin
out = Pin("D0", Pin.OUT)
out.on()
out.off()
out.value(1)
inp = Pin("D1", Pin.IN, Pin.PULL_UP)
print(inp.value())
모든 입력 핀은 에지 전환 시 인터럽트를 발생시킬 수도 있습니다:
def handler(pin):
print("triggered:", pin)
Pin("D1", Pin.IN, Pin.PULL_UP).irq(
handler, Pin.IRQ_FALLING | Pin.IRQ_RISING,
)
UART¶
버스 |
TX |
RX |
|---|---|---|
UART1 |
D14 |
D13 |
UART6 |
D5 |
D4 |
from machine import UART
uart = UART(1, baudrate=115200)
uart.write("hello")
uart.read(5)
I²C¶
버스 |
SCL |
SDA |
|---|---|---|
I2C3 |
D12 |
D11 |
from machine import I2C
i2c = I2C(3, freq=400_000)
i2c.scan()
i2c.writeto(0x76, b"hi")
MKR 헤더의 D11/D12 패드와 ESLOV 커넥터의 SDA_EXT/SCL_EXT 핀은 동일한 I²C 3 버스에 연결됩니다 — ESLOV 핀아웃은 위의 ESLOV 커넥터를 참조하세요.
동일한 하드웨어는 machine.I2CTarget를 통해 타깃(슬레이브) 모드로도 사용하여 다른 I²C 컨트롤러에 메모리 영역을 노출할 수 있습니다:
from machine import I2CTarget
buf = bytearray(32)
target = I2CTarget(3, addr=0x42, mem=buf)
SPI¶
버스 |
MOSI |
MISO |
SCK |
CS |
|---|---|---|---|---|
SPI2 |
D8 |
D10 |
D9 |
D7 |
from machine import SPI
from machine import Pin
spi = SPI(2, baudrate=10_000_000)
cs = Pin("D7", Pin.OUT, value=1) # CS is not driven by the SPI peripheral
cs.value(0)
spi.write(b"hello")
cs.value(1)
ADC¶
Portenta H7은 A0–A7에 여덟 개의 12비트 ADC 채널을 노출합니다. 모두 3.3 V 기준입니다 — read_u16은 핀에서 0–3.3 V에 걸쳐 0–65535를 반환합니다:
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¶
단일 12비트 DAC 채널이 pyb.DAC를 통해 DAC1(A6 / D21)에 노출됩니다:
from pyb import DAC
dac = DAC("DAC1")
dac.write(int(0.5 * 255)) # 8‑bit output, ~1.65 V
PWM¶
핀 |
타이머 / 채널 |
|---|---|
D0 |
TIM8 CH3N |
D1 |
TIM1 CH1, TIM8 CH3N |
D2 |
TIM1 CH2, TIM8 CH2N |
D4 |
TIM3 CH2, TIM8 CH2 |
D5 |
TIM3 CH1, TIM8 CH1 |
D6 |
TIM1 CH1 |
D7 |
TIM5 CH4 |
D13 |
TIM1 CH3 |
D14 |
TIM1 CH2 |
A7 |
TIM3 CH1 |
machine.PWM를 통해 이들 중 어느 것이든 구동하세요:
from machine import Pin, PWM
pwm = PWM(Pin("D4"), freq=1_000, duty_u16=32768)
참고
여러 핀이 타이머 채널을 공유합니다:
TIM1 CH1은
D1그리고D6에 있습니다.TIM1 CH2는
D2그리고D14에 있습니다.TIM8 CH3N은
D0그리고D1에 있습니다.
타이머 채널당 하나의 소비자를 선택하세요.
경고
Vision Shield가 csi — 카메라 센서를 통해 초기화될 때 TIM1은 카메라 마스터 클럭용으로 예약됩니다 — 카메라가 활성화된 동안에는 D1, D2, D6, D13, D14를 PWM으로 구동할 수 없습니다.
소프트웨어 비트뱅 버스¶
추가 버스가 필요한 경우 machine.SoftI2C와 machine.SoftSPI는 모든 GPIO에서 동작합니다.
열 센서 (외부 보드)¶
펌웨어에는 외부에 연결된 열화상 카메라를 위한 fir — 열 센서 드라이버 (fir == far infrared, 원적외선) 드라이버가 포함되어 있습니다:
MLX90621 — 16 × 4 IR 어레이
MLX90640 — 32 × 24 IR 어레이
MLX90641 — 16 × 12 IR 어레이
AMG8833 — 8 × 8 IR 어레이
모듈을 보드의 I²C 버스에 연결하고 fir.init() + fir.snapshot()으로 프레임을 읽으세요:
import time
import image
import fir
fir.init() # auto‑detects the sensor
clock = time.clock()
while True:
clock.tick()
try:
img = fir.snapshot(x_scale=5, y_scale=5,
color_palette=image.PALETTE_IRONBOW,
hint=image.BICUBIC,
copy_to_fb=True)
except OSError:
continue
print(clock.fps())
fir 드라이버는 I²C 3을 통해서만 센서와 통신합니다 — 모듈을 D12(SCL)와 D11(SDA)에 연결하세요.
타이밍¶
time¶
time 모듈은 블로킹 지연, 모노토닉 틱, 경과 시간 측정을 다룹니다:
import time
time.sleep(1) # seconds
time.sleep_ms(500)
time.sleep_us(10)
start = time.ticks_ms()
# ...do work...
elapsed = time.ticks_diff(time.ticks_ms(), start)
가상 타이머¶
machine.Timer는 하드웨어 타이머 슬롯을 소비하지 않고 주기적 또는 일회성 콜백을 스케줄링합니다. 가상(소프트웨어) 타이머를 사용하려면 id로 -1을 전달하세요:
from machine import Timer
one_shot = Timer(-1)
one_shot.init(period=5_000, mode=Timer.ONE_SHOT,
callback=lambda t: print("once"))
periodic = Timer(-1)
periodic.init(period=2_000, mode=Timer.PERIODIC,
callback=lambda t: print("tick"))
주기 값은 밀리초 단위입니다. 슬롯을 정지하고 해제하려면 deinit()를 호출하세요.
실시간 클럭¶
machine.RTC는 리셋을 넘어 벽시계 시간을 유지합니다. HD 커넥터는 전원 손실 시 CR2032로 RTC를 백업할 수 있는 COINCELL 패드도 노출합니다:
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())
워치독¶
machine.WDT는 애플리케이션이 멈추면 보드를 리셋합니다. 일단 시작되면 정지하거나 재구성할 수 없으므로, 메인 루프 내에서 주기적으로 피드하세요:
from machine import WDT
wdt = WDT(timeout=5_000) # 5 second window
while True:
# ...do work...
wdt.feed()
부팅 및 런타임 정보¶
펌웨어 업데이트 (DFU)¶
Portenta H7은 Arduino의 부트로더에 진입하기 위해 Arduino의 표준 더블‑탭 리셋을 사용합니다. 리셋 버튼을 빠르게 두 번 누르면 보드가 USB를 통해 DFU 장치로 다시 열거되며, OpenMV IDE가 새 펌웨어 이미지를 플래시할 수 있습니다.
실행 중인 스크립트는 machine.bootloader()를 호출하여 요청 시 부트로더로 다시 진입할 수 있습니다:
import machine
machine.bootloader()
파일 시스템 및 부팅 순서¶
Portenta H7 펌웨어는 부팅 시 최대 세 개의 파일 시스템을 마운트합니다:
내부 플래시 — 항상
/flash에 마운트됩니다. 기본적으로main.py와README.txt를 담고 있으며, 최초 부팅 시 생성됩니다.microSD 카드 — Vision Shield가 부착되고 카드가 삽입되어 있으면
/sdcard에 마운트됩니다.ROMFS — 시작 시 MicroPython이 자동으로
/rom에 마운트하는 읽기 전용 메모리 매핑 파일 시스템입니다.
마운트 후, 카드가 있으면 작업 디렉터리가 /sdcard로 설정되고, 그렇지 않으면 /flash로 설정됩니다. 그런 다음 인터프리터는 해당 디렉터리에서 스크립트를 실행합니다:
boot.py는 모든 소프트 리셋 시 실행됩니다(콜드 부팅, REPL에서의Ctrl‑D, 또는 실행 중인 스크립트가 반환될 때마다).main.py는boot.py직후 콜드 부팅 시에만 실행됩니다. 이후의 소프트 리셋은boot.py를 다시 실행하지만 바로 REPL로 떨어집니다 —main.py를 다시 실행하려면 보드를 완전히 리셋해야 합니다.
boot.py 또는 main.py를 SD 카드에 넣으면 플래시의 사본을 건드리지 않고 재정의합니다 — 두 파일 모두 부팅 디렉터리(카드가 마운트되면 /sdcard, 그렇지 않으면 /flash)에서 조회됩니다.
갓 플래시된 보드에 기본 제공되는 main.py는 단순히 사용자 RGB LED의 파랑 채널을 하트비트로 깜빡입니다(짧은 펄스 두 번, 짧은 간격). 따라서 호스트가 연결되지 않아도 펌웨어가 깔끔하게 부팅되었는지 알 수 있습니다.
sys.path는 세 파일 시스템과 그 lib/ 하위 디렉터리를 모두 포함하도록 확장되므로, 임포트 가능한 모듈은 /flash/lib, /sdcard/lib, 또는 /rom/lib에 둘 수 있습니다.
삽입된 SD 카드를 시스템이 무시하도록 강제하려면(예를 들어 카드가 있어도 플래시의 main.py를 실행하려면), /flash의 루트에 SKIPSD라는 빈 파일을 생성하세요.
USB로 연결되면, 부팅 파일 시스템(카드가 있으면 /sdcard, 그렇지 않으면 /flash)이 호스트에서 USB 대용량 저장 드라이브로도 열거되어 boot.py, main.py 및 기타 파일을 직접 편집할 수 있습니다. 보드를 리셋하기 전에 드라이브를 꺼내기(eject)하여 호스트가 캐시된 쓰기를 플러시하도록 하세요.
참고
OS가 드라이브를 수동 블록 장치로 취급하기 때문에, 카메라에서 실행되는 코드가 생성하거나 수정한 파일은 호스트가 드라이브를 다시 마운트할 때까지 표시되지 않습니다. OS와 카메라가 동시에 동일한 파일 시스템에 쓰면, OS가 우선하여 카메라가 변경한 내용을 덮어씁니다. 스크립트가 기록하는 모든 데이터에는 SD 카드를 사용하고, 호스트에서 해당 파일을 읽기 전에 다시 마운트하세요.
참고
호스트가 USB 대용량 저장 드라이브에서 읽거나 쓰는 동안 사용자 RGB LED의 빨강 채널이 잠깐 켜질 수 있습니다 — 이는 펌웨어가 구동하는 활동 표시기이며 결함이 아닙니다.
저장 용량¶
Portenta H7은 다음을 갖추고 출하됩니다:
/flash— 11 MB FAT 파일 시스템, 읽기/쓰기./rom— 4 MB 읽기 전용 메모리 매핑 ROMFS로, 제로 카피 mmap 액세스의 이점을 누리는 스크립트와 ML 모델을 출하하는 데 사용됩니다./sdcard— Vision Shield에 삽입된 microSD 카드(있는 경우)의 전체 용량, 읽기/쓰기.
하드 폴트 표시기¶
사용자 RGB LED가 모든 색상을 빠르게 순환하는 경우 — 뚜렷한 색조라기보다 반짝이는 흰색 LED처럼 보일 정도로 빠르다면 — 펌웨어가 복구 불가능한 하드 폴트에 도달한 것입니다. 복구하려면 펌웨어를 다시 플래시하세요. 다시 플래시해도 도움이 되지 않으면 보드가 물리적으로 손상되었을 수 있습니다.
소프트웨어 라이브러리¶
Portenta H7 빌드에 고유한 모듈을 포함한 전체 모듈 목록은 라이브러리 인덱스를 참조하세요.