Arduino Nicla Vision¶
La Arduino Nicla Vision es una placa de visión artificial de 22,86 × 22,86 mm construida en torno al STMicroelectronics STM32H747AII6, 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 íntegramente en el núcleo M7. La placa empareja el MCU con el sensor CMOS a color GC2145 de 2 MP, una IMU de 6 ejes LSM6DSOX, un micrófono MEMS MP34DT06, un medidor de distancia por tiempo de vuelo VL53L1CB, Wi‑Fi + Bluetooth LE 5.1 y un cargador de batería / medidor de carga.
Para la hoja de datos completa, fotos y dimensiones consulte la página del producto Arduino Nicla Vision.
Aspectos destacados¶
STMicroelectronics STM32H747AII6 doble Cortex‑M7 (400 MHz) + Cortex‑M4 (200 MHz). El firmware de OpenMV se ejecuta únicamente en el núcleo M7.
2 MB de memoria flash interna más 16 MB de memoria flash QSPI externa (utilizada para la aplicación + ROMFS).
1 MB de SRAM interna.
Codificador/decodificador JPEG por hardware.
Sensor CMOS a color GC2145 de 2 MP.
IMU integrada (acelerómetro + giroscopio LSM6DSOX), micrófono MEMS (MP34DT06JTR) y medidor de distancia por tiempo de vuelo VL53L1CB (hasta ~4 m).
Wi‑Fi b/g/n (2,4 GHz) + Bluetooth LE 5.1 mediante el módulo Murata 1DX (CYW4343W), que se conecta a la antena suministrada a través de un conector U.FL integrado.
USB de alta velocidad (480 Mb/s) sobre Micro USB a través de un PHY ULPI externo (USB3320C).
13 pines de E/S de usuario en los conectores de borde Arduino: cuatro LPIO digitales (
D0–D3), tres entradas analógicas de 1,8 V (A0–A2), el par I²CSCL/SDAy el cuarteto SPISCLK/CIPO/COPI/CS.Soporte de batería: conector Li‑Po en la parte trasera, cargador de tipo BQ y medidor de carga MAX17262 sobre el bus PMIC interno.
Conector ESLOV de 5 pines en la parte trasera para expansión I²C sin soldadura.
Advertencia
Los pines digitales de usuario son de 3,3 V de forma predeterminada, pero están enrutados a través de conversores de nivel programables por software (VDDIO_EXT) que pueden reconfigurarse a 1,8 V. Los pines analógicos (A0–A2) son únicamente de 1,8 V: omiten los conversores de nivel y se conectan directamente al MCU. Aplicar 3,3 V a A0–A2 dañará el SoC.
Distribución de pines¶
Referencia de pines¶
Trece pines de usuario están expuestos en los conectores de borde Arduino (J1 y J2). Otras señales de depuración, recuperación y PMIC están enrutadas a almohadillas de prueba en la parte trasera de la placa.
Nombre del pin |
Referencia |
Función |
|---|---|---|
D0 |
3,3 V |
GPIO / LPIO0 (J1‑1) |
D1 |
3,3 V |
LPUART1 TX / TIM1 CH2 / LPIO1 (J2‑3) |
D2 |
3,3 V |
LPUART1 RX / TIM1 CH3 / LPIO2 (J2‑4) |
D3 |
3,3 V |
GPIO / LPIO3 (J2‑5) |
A0 |
1,8 V |
ADC1 canal 4 (J1‑8) |
A1 |
1,8 V |
ADC2 canal 2 (J1‑7) |
A2 |
1,8 V |
ADC3 canal 5 (J1‑2) |
SCL |
3,3 V |
I2C1 SCL / UART4 RX / TIM4 CH3 (J2‑2) |
SDA |
3,3 V |
I2C1 SDA / UART4 TX / TIM4 CH4 (J2‑1) |
SCLK |
3,3 V |
SPI4 SCK / TIM1 CH3N (J1‑6) |
CIPO |
3,3 V |
SPI4 MISO / TIM1 CH3 (J1‑5) |
COPI |
3,3 V |
SPI4 MOSI / TIM1 CH4 (J1‑4) |
CS |
3,3 V |
SPI4 NSS / TIM1 CH2 (J1‑3) |
RESET |
3,3 V |
tire a GND (o pulse el interruptor integrado) para reiniciar la placa |
LED_RED |
3,3 V |
canal rojo del LED RGB (activo a nivel bajo) |
LED_GREEN |
3,3 V |
canal verde del LED RGB (activo a nivel bajo) |
LED_BLUE |
3,3 V |
canal azul del LED RGB (activo a nivel bajo) |
Nota
D0–D3 y SCLK/CIPO/COPI/CS están detrás del conversor de nivel bidireccional TXB0108, una pieza que solo admite excitación GPIO push‑pull, por lo que el tráfico de bus en colector abierto (p. ej. un 1‑Wire o un I²C emulado por software en esos pines) no funcionará.
SCL/SDA están detrás de un conversor NTS0304 independiente que admite excitación tanto push‑pull como en colector abierto, razón por la cual el I²C 1 funciona ahí.
Ambos conversores están referenciados a VDDIO_EXT (3,3 V de forma predeterminada desde el PMIC integrado), y su capacidad de excitación es limitada en comparación con un GPIO directo: están diseñados para cargas a nivel de señal en lugar de cargas de potencia.
Pines de alimentación¶
Pines del conector de borde:
VIN (J2‑9): raíl principal del sistema de 3,6 – 5 V. El PMIC toma su entrada aquí.
VDDIO_EXT (J2‑7): salida del raíl del conversor de nivel, 1,8 V o 3,3 V (3,3 V de forma predeterminada). Úselo para alimentar periféricos externos de 1,8 V o 3,3 V conectados a los pines LPIO/SPI/I²C, de modo que utilicen el mismo nivel lógico que los conectores.
VBAT (J3‑2): entrada de batería Li‑Po. El PMIC integrado carga la celda desde VIN e informa del estado de carga a través del medidor de carga.
NTC (J3‑1): entrada opcional para termistor de Li‑Po.
GND (J2‑6): tierra común.
NC (J2‑8): sin conexión.
Almohadillas de prueba en la parte trasera de la placa:
+3V3: raíl principal de 3,3 V.
D_P / D_N: par de datos USB de alta velocidad (posterior al PHY).
Tanto el USB como el conector ESLOV alimentan VIN a través de un par de diodos ideales LM66100 (uno por fuente), de modo que cualquiera de las dos fuentes puede alimentar la placa por sí sola y nunca se retroalimentan entre sí. Si excita VIN externamente en J2‑9, esa fuente tiene prioridad: los diodos simplemente dejan de conducir desde USB / ESLOV en cuanto el raíl externo sube por encima.
Por lo tanto, la placa puede alimentarse a través de cualquiera de estas vías:
Micro USB: 5 V hacia VIN a través del diodo ideal del lado USB.
Conector ESLOV: hasta 5 V en el pin
VESLOVde J5, enrutados hacia VIN a través del diodo ideal del lado ESLOV (véase Conector ESLOV).Pin VIN (J2‑9): aplique directamente una fuente regulada de 3,6 – 5 V.
Batería Li‑Po: conéctela al conector de batería J4 de la parte trasera o a las almohadillas VBAT/GND/NTC de J3 / J2‑6. No conecte dos baterías simultáneamente.
Conector ESLOV¶
J5 en la parte trasera de la placa es un conector ESLOV Molex de 5 pines sin soldadura:
Pin |
Nombre |
Función |
|---|---|---|
J5‑1 |
VESLOV |
entrada de alimentación (≤ 5 V): combinada en OR con |
J5‑2 |
INT |
entrada de interrupción externa en |
J5‑3 |
SCL_EXT |
compartido con la almohadilla |
J5‑4 |
SDA_EXT |
compartido con la almohadilla |
J5‑5 |
GND |
tierra común |
Los pines SCL_EXT/SDA_EXT del ESLOV y los pines SCL/SDA de J2 son los mismos: un único bus I²C 1 expuesto en dos conectores.
Truco
Utilice el estimador de vida de la batería para modelar cuánto tiempo funcionará la Nicla Vision con una batería para un ciclo de trabajo activo / de sueño profundo determinado.
Pines de recuperación y depuración¶
RESET: tanto un interruptor momentáneo en la parte superior de la placa como una almohadilla (J3‑4 / almohadilla de prueba P5) conectada a la línea NRST del SoC. Tire a GND para reiniciar.
La Nicla Vision utiliza el doble toque de reinicio estándar de Arduino para entrar en el gestor de arranque (bootloader) de Arduino: pulse rápidamente el botón de reinicio dos veces y la placa se enumerará como un dispositivo DFU. OpenMV IDE usa este modo para reescribir el firmware.
Las señales SWD del STM32 están expuestas en la parte trasera de la placa a través de una fila de almohadillas de prueba situadas entre los dos conectores J2. Suelde en ellas un conector de 2,54 mm (100 mil) para conectar un adaptador ST‑LINK o J‑Link:
P1 / P2: bus I²C del PMIC interno en PF0 (SDA) y PF1 (SCL). Este es
machine.I2C(2)en la Nicla Vision y transporta el tráfico del PMIC, el medidor de carga y el ToF.P3: TMS / SWDIO (PA13)
P4: TCK / SWCLK (PA14)
P5: NRST
P6: TDO / SWO (PB3)
P7: raíl +1V8 (la alimentación de E/S del SoC, también la referencia correcta para el adaptador de depuración).
P8:
VOTP_PMIC: solo para programación de fábrica. Debe dejarse sin conectar.
Todas las señales de depuración están referenciadas a 1,8 V: el anillo de E/S del STM32H747 en esta placa funciona desde el raíl +1V8. Configure su adaptador de depuración para lógica de 1,8 V antes de conectarlo.
Periféricos integrados¶
LEDs¶
La Nicla Vision 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 DL2 CHARGE independiente situado en el lateral de la placa está cableado directamente a la salida CHGB del PMIC: se enciende mientras se carga una batería Li‑Po desde USB / ESLOV / VIN y no es controlable por el usuario.
Sensor de cámara¶
El GC2145 se controla a través del módulo csi — sensores de cámara:
import csi
cam = csi.CSI()
cam.reset()
cam.pixformat(csi.RGB565)
cam.framesize(csi.QVGA)
cam.snapshot(time=2000) # let auto‑exposure settle
while True:
img = cam.snapshot()
Cuando solicitas un framesize pequeño, el controlador del GC2145 recorta una ventana de lectura proporcionalmente pequeña del sensor; de forma predeterminada, la relación de reducción de escala entre lectura y salida está limitada a 3x para mantener alta la velocidad de fotogramas. csi.IOCTL_SET_FOV_WIDE eleva ese límite a 5x, lo que significa que el controlador toma de un área más amplia del sensor al transmitir resoluciones pequeñas. El resultado es un campo de visión notablemente más amplio en framesizes pequeños, a costa de cierto rendimiento:
cam.ioctl(csi.IOCTL_SET_FOV_WIDE, True)
cam.ioctl(csi.IOCTL_GET_FOV_WIDE) # returns the current setting
Núcleo M4¶
El núcleo Cortex‑M4 está expuesto 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 C separada y cargarla desde el sistema de archivos mediante openamp.RemoteProc. En el repositorio openamp_vuart hay disponible un firmware de ejemplo precompilado que implementa un punto final de UART virtual; siga 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 en lugar de como una plataforma de doble núcleo funcional: el M4 no puede reiniciarse de forma independiente del M7, por lo que detener el M4 fuerza un reinicio completo del sistema.
Micrófono¶
El micrófono PDM MP34DT06JTR integrado se captura a través de audio — Módulo de audio sobre el periférico DFSDM del STM32. Cada búfer llega como un bytearray PCM de 16 bits con signo, listo para alimentarlo 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
IMU¶
El acelerómetro + giroscopio LSM6DSOX integrado está expuesto a través de imu — sensor imu:
import imu
import time
while True:
print(imu.acceleration_mg()) # (x, y, z) in milli‑g
print(imu.angular_rate_mdps()) # (x, y, z) in milli‑deg/s
time.sleep_ms(100)
La IMU está cableada a un bus SPI interno dedicado (SPI5), de modo que no compite con el SPI4 de usuario expuesto en los conectores.
Medidor de distancia por tiempo de vuelo¶
El medidor de distancia por tiempo de vuelo ST VL53L1CB integrado se encuentra en el bus I²C interno del PMIC (I²C 2). Utilice el controlador integrado vl53l1x — Controlador del sensor de distancia ToF VL53L1X para obtener lecturas de distancia de hasta ~4 m:
import time
from machine import I2C
import vl53l1x
bus = I2C(2) # internal bus (PMIC / fuel gauge / ToF)
tof = vl53l1x.VL53L1X(bus)
while True:
print("Distance:", tof.read(), "mm")
time.sleep_ms(100)
Medidor de carga de batería¶
El medidor de carga Maxim MAX17262 ModelGauge m5 realiza un seguimiento de la tensión, la corriente, la temperatura y el estado de carga de la batería Li‑Po. Se encuentra en el I²C 2 en la dirección 0x36.
El MAX17262 tiene detección de corriente interna, por lo que el registro de corriente se lee directamente en microamperios sin ningún 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(2)
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 está en 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 NXP MC34PF1550A0EP gestiona todos los reguladores de la Nicla Vision: el raíl principal +3V3, el raíl +1V8 del núcleo / E/S del SoC, VDDIO_EXT hacia los conversores de nivel y el cargador Li‑Po. Se encuentra en el I²C 2 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 permanentemente la placa, la batería o ambas. Trate el PMIC como de solo lectura a menos que sepa exactamente lo que está haciendo.
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 residen en un desplazamiento de 0x80 dentro del espacio de direcciones I²C principal del PF1550 (véase el §22.2 de la hoja de datos del PF1550), de modo que, por ejemplo, CHG_INT_OK en la dirección del cargador 0x04 se lee desde el 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(2)
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/ESLOV/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: indicadores de fallo), 0x86 VBUS_SNS (el estado multibit de VBUS, incluidos OVLO / UVLO / DPM) y 0x88 BATT_SNS (presencia de batería y estado de sobrecorriente).
Wi‑Fi¶
El módulo Murata 1DX (CYW4343W) integrado está expuesto a través de network — configuración de red como interfaz de estación. Conecte la antena suministrada al conector U.FL integrado 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. Utilice aioble — BLE asíncrono para BLE compatible con asyncio; por ejemplo, anunciarse como periférico y esperar a que un central se conecte:
import asyncio
import aioble
async def run():
while True:
conn = await aioble.advertise(250_000, name="Nicla-Vision")
print("Connected:", conn.device)
await conn.disconnected()
asyncio.run(run())
Referencia de buses¶
GPIO¶
Utilice machine.Pin para leer o excitar cualquiera de los pines serigrafiados. Las salidas son CMOS de 3,3 V (VDDIO_EXT de forma predeterminada) y los conversores de nivel limitan la capacidad de excitación por pin a unos pocos miliamperios: están diseñados para cargas a nivel de señal en lugar de cargas de potencia.
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 |
|---|---|---|
UART4 |
SDA |
SCL |
from machine import UART
uart = UART(4, baudrate=115200)
uart.write("hello")
uart.read(5)
Nota
UART4 comparte sus pines con el I²C 1: las mismas almohadillas SDA/SCL transportan ambos buses. Elija UART o I²C, pero no ambos, en esos pines.
La serigrafía D1/D2 también indica UART_TX/UART_RX, pero en este firmware esos pines están enrutados a LPUART1, no a machine.UART. El propio machine.UART(1) está reservado para el controlador Bluetooth integrado en el chip y no es accesible en los conectores.
I²C¶
Bus |
SCL |
SDA |
|---|---|---|
I2C1 |
SCL |
SDA |
from machine import I2C
i2c = I2C(1, freq=400_000)
i2c.scan()
i2c.writeto(0x76, b"hi")
Las almohadillas SCL/SDA de J2 y los pines SCL_EXT/SDA_EXT del conector ESLOV llegan al mismo bus I²C 1; véase Conector ESLOV más arriba para la distribución de pines del ESLOV.
El mismo hardware también puede usarse en modo 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(1, addr=0x42, mem=buf)
SPI¶
Bus |
MOSI |
MISO |
SCK |
CS |
|---|---|---|---|---|
SPI4 |
COPI |
CIPO |
SCLK |
CS |
from machine import SPI
from machine import Pin
spi = SPI(4, baudrate=10_000_000)
cs = Pin("CS", Pin.OUT, value=1) # CS is not driven by the SPI peripheral
cs.value(0)
spi.write(b"hello")
cs.value(1)
ADC¶
La Nicla Vision expone tres canales ADC de 12 bits en A0, A1 y A2. Los tres están referenciados a 1,8 V: read_u16 devuelve 0–65535 a lo largo de 0–1,8 V en el pin:
from machine import ADC
import time
adc = ADC("A0")
while True:
voltage = adc.read_u16() * 1.8 / 65535
print(voltage)
time.sleep_ms(100)
Advertencia
Las entradas ADC de la Nicla Vision están referenciadas a 1,8 V (y no tienen ningún conversor de nivel delante del SoC). Aplicar una señal de 3,3 V saturará el convertidor y puede dañar el pin: divida externamente las tensiones más altas.
PWM¶
Pin |
Temporizador / canal |
|---|---|
D1 |
TIM1 CH2 |
D2 |
TIM1 CH3 |
SCL |
TIM4 CH3, TIM16 CH1 |
SDA |
TIM4 CH4, TIM17 CH1 |
SCLK |
TIM1 CH3N |
CIPO |
TIM1 CH3 |
COPI |
TIM1 CH4 |
CS |
TIM1 CH2 |
Excite cualquiera de ellos mediante machine.PWM:
from machine import Pin, PWM
pwm = PWM(Pin("D1"), freq=1_000, duty_u16=32768)
Nota
Varios pines comparten canales de TIM1:
TIM1 CH2 está en
D1yCS.TIM1 CH3 está en
D2yCIPO;SCLKemite el complemento invertido (TIM1 CH3N) del mismo canal.TIM1 CH4 está únicamente en
COPI.
Elija un solo consumidor por canal de temporizador. Los pines del cuarteto SPI (SCLK/CIPO/COPI/CS) tampoco pueden excitarse por PWM mientras machine.SPI(4) los esté usando.
Buses emulados por software (bit‑banged)¶
machine.SoftI2C y machine.SoftSPI funcionan en cualquier GPIO si necesita 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
Cablee el módulo al bus I²C de la placa y lea 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 a través del I²C 1: cablee el módulo a las almohadillas serigrafiadas SCL / SDA.
Temporización¶
time¶
El módulo time cubre retardos bloqueantes, ticks monótonos y 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. Pase -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. Llame a deinit() para detener y liberar la ranura.
Reloj de tiempo real¶
machine.RTC mantiene la hora del reloj de pared a través de los reinicios:
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éntelo periódicamente dentro de su 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 ejecución¶
Actualización del firmware (DFU)¶
La Nicla Vision utiliza el doble toque de reinicio estándar de Arduino para entrar en el gestor de arranque (bootloader) de Arduino. Pulse 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 bootloader bajo demanda llamando a machine.bootloader():
import machine
machine.bootloader()
Sistema de archivos y orden de arranque¶
El firmware de la Nicla Vision monta hasta dos sistemas de archivos al arrancar:
Memoria flash interna: siempre montada en
/flash. Contienemain.pyyREADME.txtde forma predeterminada; se crea en el primer arranque.ROMFS: sistema de archivos de solo lectura y mapeado en memoria en
/rom, montado automáticamente por MicroPython al inicio.
Tras el montaje, el directorio de trabajo se establece en /flash. A continuación, el intérprete ejecuta los scripts de ese directorio:
boot.pyse ejecuta en cada reinicio en caliente (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 en caliente posteriores vuelven a ejecutarboot.pypero pasan directamente al REPL; para volver a ejecutarmain.pydebe reiniciar completamente la placa.
El main.py predeterminado que viene en una placa recién grabada simplemente hace parpadear el canal azul del LED RGB de usuario a modo de latido (dos pulsos cortos, una breve pausa), de modo que puede saber que el firmware arrancó correctamente sin ningún host conectado.
sys.path se amplía para incluir ambos sistemas de archivos y sus subdirectorios lib/, de modo que los módulos importables pueden residir en /flash/lib o /rom/lib.
Cuando está conectado por USB, /flash también se enumera como una unidad de almacenamiento masivo USB en el host, lo que le permite editar boot.py, main.py y cualquier otro archivo directamente. Expulse la unidad antes de reiniciar la cámara para que el host vacíe sus escrituras en caché.
Nota
Dado que 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. Utilice la tarjeta SD para cualquier dato que el script escriba, y vuelva a montar antes de leer esos archivos desde el host.
Nota
El canal rojo del LED RGB de usuario puede encenderse brevemente mientras el host lee o escribe en la unidad de almacenamiento masivo USB; se trata de un indicador de actividad gestionado por el firmware, no de un fallo.
Tamaños de almacenamiento¶
La Nicla Vision viene con:
/flash: sistema de archivos FAT de 11 MB, lectura/escritura./rom: ROMFS de 4 MB de solo lectura y mapeado en memoria, utilizado para incluir scripts y modelos de ML que se benefician del acceso mmap sin copias.
Indicador de fallo grave (hard‑fault)¶
Si el LED RGB de usuario está recorriendo rápidamente todos los colores, tan rápido que tiende a parecer un LED blanco parpadeante en lugar de tonos distintos, el firmware ha sufrido un fallo grave irrecuperable. Vuelva a grabar el firmware para recuperarse; si volver a grabarlo no ayuda, la placa puede estar dañada físicamente.
Bibliotecas de software¶
Consulte el índice de la biblioteca para ver la lista completa de módulos, incluidos los que son exclusivos de la versión para la Nicla Vision.