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.

Arduino Nicla Vision

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 (D0D3), tres entradas analógicas de 1,8 V (A0A2), el par I²C SCL/SDA y el cuarteto SPI SCLK/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

Distribución de pines de la Arduino Nicla Vision

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

D0D3 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 VESLOV de 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 VIN mediante un diodo ideal LM66100

J5‑2

INT

entrada de interrupción externa en PD9

J5‑3

SCL_EXT

compartido con la almohadilla SCL de J2: el mismo bus I²C 1 que el conector de usuario

J5‑4

SDA_EXT

compartido con la almohadilla SDA de J2: el mismo bus I²C 1 que el conector de usuario

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 D1 y CS.

  • TIM1 CH3 está en D2 y CIPO; SCLK emite 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. Contiene main.py y README.txt de 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.py se ejecuta en cada reinicio en caliente (arranque en frío, Ctrl‑D desde el REPL, o cada vez que el script en ejecución retorna).

  • main.py se ejecuta solo en el arranque en frío, inmediatamente después de boot.py. Los reinicios en caliente posteriores vuelven a ejecutar boot.py pero pasan directamente al REPL; para volver a ejecutar main.py debe 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.