Arduino Portenta H7¶
La Arduino Portenta H7 es una placa de desarrollo industrial de 66 × 25 mm construida en torno al STMicroelectronics STM32H747XI — un SoC de doble núcleo que combina un Cortex‑M7 a 400 MHz con un Cortex‑M4 a 200 MHz. El firmware de OpenMV se ejecuta enteramente en el núcleo M7 y está diseñado para usarse con el Portenta Vision Shield (edición Ethernet o LoRa), que añade una cámara Himax HM01B0 / HM0360, micrófonos PDM duales y una ranura microSD a la Portenta H7 base.
Para ver la hoja de datos completa, fotos y dimensiones, consulta la página del producto Arduino Portenta H7.
Aspectos destacados¶
STMicroelectronics STM32H747XI doble Cortex‑M7 (400 MHz) + Cortex‑M4 (200 MHz). El firmware de OpenMV se ejecuta únicamente en el núcleo M7; el núcleo M4 se expone a través de openamp para la comunicación entre procesadores.
8 MB de SDRAM externa más 2 MB de memoria flash interna y 16 MB de memoria flash QSPI externa.
Codificador/decodificador JPEG por hardware.
Wi‑Fi b/g/n (2,4 GHz) + Bluetooth LE 5.1 a través del módulo Murata 1DX (CYW4343W) — se conecta a la antena suministrada mediante un conector U.FL integrado en la placa.
USB‑C de alta velocidad (480 Mb/s).
22 pines de E/S de usuario en los conectores superiores de tipo Arduino MKR — D0–D14 (digitales) más A0–A6 (analógicos).
Dos conectores de alta densidad de 80 pines en la parte inferior exponen toda la estructura del STM32H747 — DCMI, DSI, Ethernet RMII, FDCAN, SDIO, SAI/I²S, UARTs, SPI/I²C/temporizadores adicionales, etc. Shields como el Vision Shield se acoplan a estos conectores.
JTAG / SWD disponibles en los conectores de alta densidad inferiores para depuración avanzada.
Soporte para batería — conector JST para Li‑Po de 3,7 V más cargador y monitor de batería integrados.
Distribución de pines¶
Referencia de pines¶
Se exponen 22 pines de usuario en los conectores superiores de tipo Arduino MKR — 15 digitales (D0-D14) más 7 analógicos (A0-A6). Hay muchos más pines del SoC disponibles a través de los conectores de alta densidad de 80 pines inferiores para trabajar con shields; consulta el PDF de distribución de pines completa de Arduino para ese mapeo.
Nombre de pin |
Referencia |
Función |
|---|---|---|
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 (compartido con A3 / A5) |
D9 |
3.3 V |
SPI2 SCK |
D10 |
3.3 V |
SPI2 MISO (compartido con 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 (solo analógico) |
A1 |
3.3 V |
ADC12 IN1 (solo analógico) |
A2 |
3.3 V |
ADC123 IN12 (solo analógico; compartido con D10) |
A3 |
3.3 V |
ADC12 IN13 (solo analógico; compartido con D8) |
A4 |
3.3 V |
ADC123 IN12 (compartido con D10) |
A5 |
3.3 V |
ADC12 IN13 (compartido con D8) |
A6 |
3.3 V |
DAC1 OUT1 / ADC12 IN18 |
A7 |
3.3 V |
TIM3 CH1 / ADC12 IN3 (no expuesto en los conectores) |
D20 |
3.3 V |
alias de |
D21 |
3.3 V |
alias de |
RESET |
3.3 V |
pulsa el interruptor integrado en la placa o conéctalo a GND para reiniciar |
LED_RED |
3.3 V |
canal rojo del LED RGB (activo en bajo) |
LED_GREEN |
3.3 V |
canal verde del LED RGB (activo en bajo) |
LED_BLUE |
3.3 V |
canal azul del LED RGB (activo en bajo) |
Nota
A0-A3 son pads solo analógicos en el STM32H747 sin función GPIO — trátalos únicamente como entradas ADC. A2/A4 y A3/A5 comparten sus pines físicos con D10 y D8 respectivamente, así que no puedes generar PWM ni usar SPI en ellos mientras los lees como analógicos. A7 se encuentra en los conectores de alta densidad inferiores.
Pines de alimentación¶
Pines del conector MKR:
VIN — riel principal del sistema hacia el PMIC integrado. Alimentado a través de un diodo desde el riel
+5V, el pinVINdel MKR o los conectores de alta densidad de 80 pines inferiores.+5V — riel de 5 V alimentado desde USB, el conector ESLOV o el propio pin
+5Vdel MKR.+3V3 — riel principal de 3,3 V (salida del regulador conmutado del PMIC).
AREF — referencia de tensión analógica para los pines ADC. Por defecto es 3,3 V; aplícale una tensión externa para usar una referencia diferente.
GND — tierra común.
Entrada de batería:
JST Li‑Po en la parte frontal de la placa acepta una celda Li‑Po de 3,7 V. El PMIC la carga siempre que
+5VoVINesté presente.
La Portenta H7 puede alimentarse a través de cualquiera de estas vías:
USB‑C — suministra 5 V al PMIC integrado.
Conector ESLOV — hasta 5 V en
VESLOV(consulta Conector ESLOV).Pin VIN — aplica directamente una fuente regulada de 5 V.
Batería Li‑Po — conéctala al JST de la parte frontal.
Conector ESLOV¶
En el lateral de la placa hay un conector ESLOV de 5 pines sin soldadura:
Pin |
Nombre |
Función |
|---|---|---|
1 |
VESLOV |
salida de alimentación de 5 V (mismo riel que el |
2 |
INT |
entrada de interrupción externa en |
3 |
SCL_EXT |
compartido con el pad |
4 |
SDA_EXT |
compartido con el pad |
5 |
GND |
tierra común |
Los SCL_EXT/SDA_EXT de ESLOV y los D12/D11 del conector MKR son los mismos pines — un único bus I²C 3 expuesto en dos conectores.
Truco
Usa el estimador de duración de batería para modelar cuánto tiempo funcionará la Portenta H7 con una batería para un ciclo de trabajo activo / de sueño profundo determinado.
Pines de recuperación y depuración¶
RESET — es tanto un pin expuesto en el conector superior como un interruptor momentáneo en el lateral de la placa, conectado a la línea NRST del SoC. Conéctalo a GND o pulsa el botón para reiniciar.
La Portenta H7 usa el reinicio por doble pulsación estándar de Arduino para entrar en el gestor de arranque (bootloader) de Arduino. Pulsa rápidamente el botón de reinicio dos veces — la placa se vuelve a enumerar por USB como un dispositivo DFU y OpenMV IDE puede grabar una nueva imagen de firmware.
Las señales SWD del STM32 están expuestas en el conector de alta densidad J1 inferior:
J1‑73— NRSTJ1‑75— SWDIO (PA13)J1‑77— SWCLK (PA14)J1‑79— SWO (PB3)
Conéctalas mediante una Portenta Breakout, el adaptador de depuración oficial de Arduino o una placa portadora personalizada con un conector de 1,27 mm. Todas las señales de depuración están referenciadas a 3,3 V.
Nota
Cuando el Portenta Vision Shield está acoplado, las mismas señales SWD/JTAG se enrutan hacia el conector JTAG de depuración ARM Cortex de 20 pines estándar del shield (paso de 1,27 mm / 0,05″).
Periféricos integrados¶
LEDs¶
La Portenta H7 tiene un único LED RGB de usuario, controlable por software a través de machine.LED:
from machine import LED
LED("LED_RED").on()
LED("LED_GREEN").on()
LED("LED_BLUE").on()
Un LED naranja de carga independiente, junto al JST de la batería, se ilumina cuando el cargador integrado está suministrando corriente a una Li‑Po conectada; no es controlable por el usuario.
Sensor de cámara (Vision Shield)¶
Con el Portenta Vision Shield (edición Ethernet o LoRa) acoplado, el sensor Himax se controla a través del módulo csi — sensores de cámara:
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()
Se admiten dos revisiones del Vision Shield:
HM01B0 — 320 × 320 monocromo.
HM0360 — 640 × 480 monocromo.
Advertencia
Mientras la cámara del Vision Shield está inicializada, el firmware reclama los siguientes pines del conector MKR y no pueden usarse:
Pin MKR |
Motivo |
|---|---|
|
TIM1 CH1 — reloj maestro de la cámara |
|
TIM1 CH1 (alt) — reloj maestro de la cámara |
|
I²C 3 SDA — compartido con la cámara; el bus es utilizable pero evita la dirección I²C del sensor ( |
|
I²C 3 SCL — compartido con la cámara; el bus es utilizable pero evita la dirección I²C del sensor ( |
|
DCMI HSYNC — también deshabilita el DAC |
|
DCMI PXCLK |
Aprendizaje automático¶
ml — Aprendizaje automático ejecuta modelos TFLite cuantizados en el Cortex‑M7 con kernels CMSIS‑NN — lo bastante rápido para detectores compactos a unos pocos fotogramas por segundo. Los modelos del sistema de archivos de solo lectura /rom se cargan directamente desde la memoria flash sin copiarlos a la RAM. Aquí tienes un detector BlazeFace de 128×128 que superpone el rostro detectado y sus seis puntos de referencia en cada fotograma de la cámara del 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")
Núcleo M4¶
El núcleo Cortex‑M4 se expone a través de openamp para la comunicación entre procesadores. El firmware de OpenMV se ejecuta únicamente en el M7; el M4 no tiene un entorno de ejecución MicroPython propio, así que usarlo implica compilar una imagen de firmware en C separada y cargarla desde el sistema de archivos mediante openamp.RemoteProc. Hay un firmware de ejemplo precompilado que implementa un endpoint UART virtual disponible en el repositorio openamp_vuart — sigue su README para compilar 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)
En la práctica, conviene tratar este soporte como una demostración de la interfaz openamp más que como una plataforma de doble núcleo funcional — el M4 no puede reiniciarse independientemente del M7, así que detener el M4 fuerza un reinicio completo del sistema.
Micrófono (Vision Shield)¶
El Vision Shield lleva micrófonos PDM duales capturados a través de audio — Módulo de audio mediante el periférico SAI4 del STM32. Cada búfer llega como PCM de 16 bits con signo en un bytearray, listo para alimentar a ulab/numpy para DSP — por ejemplo, un sencillo detector de volumen:
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
Pasa channels=2 a audio.init para recibir muestras intercaladas de ambos micrófonos.
Medidor de carga de batería¶
El medidor de carga ModelGauge m5 MAX17262 de Maxim realiza un seguimiento de la tensión, corriente, temperatura y estado de carga de la batería Li‑Po. Se ubica en el I²C 1 en la dirección 0x36.
El MAX17262 tiene detección de corriente interna, así que el registro de corriente se lee directamente en microamperios sin un factor Rsense externo que aplicar. Leer el medidor de carga es inofensivo — no se incluye ningún controlador, pero los registros documentados en la hoja de datos del MAX17262 pueden leerse directamente:
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 es complemento a dos con signo: positivo durante la carga, negativo durante la descarga. TTE solo tiene sentido cuando la corriente es negativa; TTF solo cuando la corriente es positiva.
Circuito integrado de gestión de energía¶
El PMIC PF1550 de NXP gestiona todos los reguladores de la Portenta H7 — el riel principal +3V3, el riel +1V8 del núcleo / E/S del SoC, y el cargador de la Li‑Po. Se ubica en el I²C 1 en la dirección 0x08.
Advertencia
Leer los registros del PMIC es seguro; escribir en ellos es peligroso. Configurar incorrectamente un regulador reductor o un ajuste del cargador puede dañar de forma permanente la placa, la batería, o ambas. Trata el PMIC como de solo lectura a menos que sepas exactamente lo que haces.
Lo más útil que el PMIC te indica y que el medidor de carga no puede es la máquina de estados del cargador — si la placa está funcionando actualmente con USB / ESLOV / VIN, en qué etapa del ciclo de carga se encuentra la Li‑Po, y si el cargador está en un fallo térmico o de watchdog. Los registros del cargador se ubican en un desplazamiento de 0x80 dentro del espacio de direcciones I²C principal del PF1550 (consulta la §22.2 de la hoja de datos del PF1550), así que, por ejemplo, CHG_INT_OK en la dirección de cargador 0x04 se lee del registro 0x84 del PMIC:
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)
Otros registros de solo lectura que vale la pena consultar en la hoja de datos (todos con desplazamiento de cargador 0x80): 0x80 CHG_INT (interrupciones del cargador retenidas — banderas de fallo), 0x86 VBUS_SNS (el estado VBUS multibit incluyendo OVLO / UVLO / DPM), y 0x88 BATT_SNS (presencia de la batería y estado de sobrecorriente).
Wi‑Fi¶
El Murata 1DX (CYW4343W) integrado se expone mediante network — configuración de red como una interfaz de estación. Conecta la antena suministrada al conector U.FL integrado en la placa antes de activar la radio:
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¶
El mismo Murata 1DX también expone Bluetooth LE 5.1. Usa aioble — BLE asíncrono para BLE compatible con asyncio — por ejemplo, anúnciate como periférico y espera a que un central se conecte:
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)¶
La edición LoRa del Vision Shield añade un módulo LoRaWAN Murata CMWX1ZZABZ conectado a la Portenta H7 por UART. El módulo lora envuelve el firmware de comandos AT y admite unión OTAA o ABP, enlace ascendente y enlace descendente:
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()
Usa BAND_US915 / BAND_AS923 / BAND_AU915, etc. para regiones fuera de la UE, y cambia a lora.Lora.join_ABP() si tu servidor de red usa la activación ABP.
Advertencia
Mientras el módulo LoRa está en uso, el controlador reclama los siguientes pines del conector MKR como líneas de control para el Murata CMWX1ZZABZ — no pueden usarse:
Pin MKR |
Motivo |
|---|---|
|
pin BOOT del módulo LoRa |
|
pin RST del módulo LoRa |
Ethernet (Vision Shield)¶
La edición Ethernet del Vision Shield añade un conector RJ45 con magnéticos conectado al MAC Ethernet 10/100 del STM32H747 por RMII. Conecta un cable Ethernet y el PHY aparece como una interfaz LAN; DHCP se ejecuta automáticamente una vez que el enlace se activa:
import network
import time
lan = network.LAN()
lan.active(True)
while not lan.isconnected():
time.sleep(1)
print("Ethernet IP:", lan.ipconfig("addr4")[0])
Tarjeta microSD (Vision Shield)¶
Cuando se inserta una tarjeta, se monta automáticamente en /sdcard y es utilizable a través del sistema de archivos habitual:
import os
for entry in os.listdir("/sdcard"):
print(entry)
Referencia de buses¶
GPIO¶
Usa machine.Pin para leer o controlar cualquiera de los pines serigrafiados. Las salidas son CMOS de 3,3 V y pueden absorber/suministrar hasta 20 mA por pin (140 mA en total a través de todo el conector).
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())
Cualquier pin de entrada también puede disparar una interrupción en las transiciones de borde:
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")
Los pads D11/D12 del conector MKR y los pines SDA_EXT/SCL_EXT del conector ESLOV están en el mismo bus I²C 3 — consulta Conector ESLOV más arriba para la distribución de pines de ESLOV.
El mismo hardware también puede usarse en modo de destino (esclavo) a través de machine.I2CTarget para exponer una región de memoria a otro controlador I²C:
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¶
La Portenta H7 expone ocho canales ADC de 12 bits en A0–A7. Todos están referenciados a 3,3 V — read_u16 devuelve 0–65535 en el rango de 0–3,3 V en el 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¶
Se expone un único canal DAC de 12 bits en DAC1 (A6 / D21) a través de pyb.DAC:
from pyb import DAC
dac = DAC("DAC1")
dac.write(int(0.5 * 255)) # 8‑bit output, ~1.65 V
PWM¶
Pin |
Temporizador / canal |
|---|---|
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 |
Controla cualquiera de ellos mediante machine.PWM:
from machine import Pin, PWM
pwm = PWM(Pin("D4"), freq=1_000, duty_u16=32768)
Nota
Varios pines comparten canales de temporizador:
TIM1 CH1 está en
D1yD6.TIM1 CH2 está en
D2yD14.TIM8 CH3N está en
D0yD1.
Elige un único consumidor por canal de temporizador.
Advertencia
TIM1 está reservado para el reloj maestro de la cámara cuando el Vision Shield se inicializa a través de csi — sensores de cámara — D1, D2, D6, D13 y D14 no pueden controlarse por PWM mientras la cámara está activa.
Buses bit‑banged por software¶
machine.SoftI2C y machine.SoftSPI funcionan en cualquier GPIO si necesitas un bus adicional.
Sensor térmico (externo)¶
El firmware incluye el controlador fir — controlador de sensor térmico (fir == infrarrojo lejano) para cámaras térmicas cableadas externamente:
MLX90621 — matriz IR de 16 × 4
MLX90640 — matriz IR de 32 × 24
MLX90641 — matriz IR de 16 × 12
AMG8833 — matriz IR de 8 × 8
Conecta el módulo al bus I²C de la placa y lee fotogramas con 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())
El controlador fir solo se comunica con el sensor por I²C 3 — conecta el módulo a D12 (SCL) y D11 (SDA).
Temporización¶
time¶
El módulo time cubre retardos bloqueantes, tics monótonos y la medición de tiempo transcurrido:
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)
Temporizadores virtuales¶
machine.Timer programa funciones de retorno (callbacks) periódicas o de un solo disparo sin consumir una ranura de temporizador por hardware. Pasa -1 como id para usar un temporizador virtual (por 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"))
Los valores de periodo están en milisegundos. Llama a deinit() para detener y liberar la ranura.
Reloj de tiempo real¶
machine.RTC mantiene la hora del reloj de pared entre reinicios. El conector de alta densidad también expone un pad COINCELL que puede respaldar el RTC con una CR2032 ante una pérdida de alimentación:
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 reinicia la placa si la aplicación se cuelga. Una vez iniciado, no puede detenerse ni reconfigurarse — aliméntalo periódicamente dentro de tu bucle principal:
from machine import WDT
wdt = WDT(timeout=5_000) # 5 second window
while True:
# ...do work...
wdt.feed()
Información de arranque y de tiempo de ejecución¶
Actualización de firmware (DFU)¶
La Portenta H7 usa el reinicio por doble pulsación estándar de Arduino para entrar en el gestor de arranque (bootloader) de Arduino. Pulsa rápidamente el botón de reinicio dos veces — la placa se vuelve a enumerar por USB como un dispositivo DFU y OpenMV IDE puede grabar una nueva imagen de firmware.
Un script en ejecución puede volver a entrar en el gestor de arranque (bootloader) bajo demanda llamando a machine.bootloader():
import machine
machine.bootloader()
Sistema de archivos y orden de arranque¶
El firmware de la Portenta H7 monta hasta tres sistemas de archivos en el arranque:
Memoria flash interna — siempre montada en
/flash. Contienemain.pyyREADME.txtpor defecto; se crea en el primer arranque.Tarjeta microSD — si hay un Vision Shield acoplado y una tarjeta insertada, se monta en
/sdcard.ROMFS — sistema de archivos de solo lectura, mapeado en memoria, en
/rom, montado automáticamente por MicroPython al inicio.
Tras el montaje, el directorio de trabajo se establece en /sdcard cuando la tarjeta está presente, de lo contrario en /flash. El intérprete ejecuta entonces los scripts desde ese directorio:
boot.pyse ejecuta en cada reinicio suave (arranque en frío,Ctrl‑Ddesde el REPL, o cada vez que el script en ejecución retorna).main.pyse ejecuta solo en el arranque en frío, inmediatamente después deboot.py. Los reinicios suaves posteriores vuelven a ejecutarboot.pypero pasan directamente al REPL — para volver a ejecutarmain.pytienes que reiniciar la placa por completo.
Colocar un boot.py o main.py en la tarjeta SD anula la copia de la memoria flash sin tocarla — ambos archivos se buscan en el directorio de arranque (/sdcard cuando la tarjeta está montada, de lo contrario /flash).
El main.py por defecto que viene en una placa recién grabada simplemente parpadea el canal azul del LED RGB de usuario como latido (dos pulsos cortos, breve pausa), para que puedas saber que el firmware arrancó correctamente sin ningún host conectado.
sys.path se extiende para incluir los tres sistemas de archivos y sus subdirectorios lib/, de modo que los módulos importables pueden residir en /flash/lib, /sdcard/lib o /rom/lib.
Para forzar al sistema a ignorar una tarjeta SD insertada (por ejemplo, para ejecutar el main.py de la flash incluso con una tarjeta presente), crea un archivo vacío llamado SKIPSD en la raíz de /flash.
Cuando está conectada por USB, el sistema de archivos de arranque (/sdcard si hay una tarjeta presente, de lo contrario /flash) también se enumera como una unidad de almacenamiento masivo USB en el host, lo que te permite editar boot.py, main.py y cualquier otro archivo directamente. Expulsa la unidad antes de reiniciar la placa para que el host vuelque sus escrituras en caché.
Nota
Como el sistema operativo trata la unidad como un dispositivo de bloques pasivo, los archivos creados o modificados por el código que se ejecuta en la cámara no aparecerán hasta que el host vuelva a montar la unidad. Si tanto el sistema operativo como la cámara escriben en el mismo sistema de archivos al mismo tiempo, el sistema operativo ganará y sobrescribirá los cambios hechos por la cámara. Usa la tarjeta SD para cualquier dato que el script escriba de vuelta, y vuelve a montar antes de leer esos archivos desde el host.
Nota
El canal rojo del LED RGB de usuario puede iluminarse brevemente mientras el host lee de la unidad de almacenamiento masivo USB o escribe en ella — esto es un indicador de actividad gestionado por el firmware, no un fallo.
Tamaños de almacenamiento¶
La Portenta H7 viene con:
/flash— sistema de archivos FAT de 11 MB, lectura/escritura./rom— ROMFS de solo lectura mapeado en memoria de 4 MB, usado para distribuir scripts y modelos de ML que se benefician del acceso mmap sin copia./sdcard— tamaño completo de la tarjeta microSD que esté insertada en un Vision Shield (cuando esté presente), lectura/escritura.
Indicador de fallo grave (hard fault)¶
Si el LED RGB de usuario está recorriendo rápidamente todos los colores — lo bastante rápido como para que tienda a parecer un LED blanco titilante en lugar de tonos distintos — el firmware ha sufrido un fallo grave irrecuperable. Vuelve a grabar el firmware para recuperarlo; si volver a grabarlo no ayuda, la placa puede estar dañada físicamente.
Bibliotecas de software¶
Consulta el índice de bibliotecas para ver la lista completa de módulos — incluyendo cuáles son exclusivos de la compilación para la Portenta H7.