Arduino Nicla Vision

L’Arduino Nicla Vision è una scheda per visione artificiale di 22,86 × 22,86 mm costruita attorno allo STMicroelectronics STM32H747AII6 — un SoC dual‑core che combina un Cortex‑M7 a 400 MHz con un Cortex‑M4 a 200 MHz. Il firmware OpenMV gira interamente sul core M7. La scheda abbina al MCU il sensore CMOS a colori GC2145 da 2 MP, una IMU a 6 assi LSM6DSOX, un microfono MEMS MP34DT06, un telemetro time‑of‑flight VL53L1CB, Wi‑Fi + Bluetooth LE 5.1 e un caricabatterie / fuel gauge.

Arduino Nicla Vision

Per il datasheet completo, le foto e le dimensioni consulta la pagina prodotto dell’Arduino Nicla Vision.

Punti salienti

  • STMicroelectronics STM32H747AII6 dual Cortex‑M7 (400 MHz) + Cortex‑M4 (200 MHz). Il firmware OpenMV gira solo sul core M7.

  • 2 MB di flash interna più 16 MB di flash QSPI esterna (usata per l’applicazione + ROMFS).

  • 1 MB di SRAM interna.

  • Encoder/decoder JPEG hardware.

  • Sensore CMOS a colori GC2145 da 2 MP.

  • IMU integrata (accelerometro + giroscopio LSM6DSOX), microfono MEMS (MP34DT06JTR) e telemetro time‑of‑flight VL53L1CB (fino a ~4 m).

  • Wi‑Fi b/g/n (2,4 GHz) + Bluetooth LE 5.1 tramite il modulo Murata 1DX (CYW4343W) — si collega all’antenna fornita tramite un connettore U.FL integrato.

  • USB ad alta velocità (480 Mb/s) su Micro USB tramite un PHY ULPI esterno (USB3320C).

  • 13 pin di I/O utente sui connettori a pettine Arduino — quattro LPIO digitali (D0D3), tre ingressi analogici a 1,8 V (A0A2), la coppia I²C SCL/SDA e il quartetto SPI SCLK/CIPO/COPI/CS.

  • Supporto batteria — connettore Li‑Po sul retro, caricabatterie in stile BQ e fuel gauge MAX17262 sul bus PMIC interno.

  • Connettore ESLOV a 5 pin sul retro per l’espansione I²C senza saldatura.

Avvertimento

I pin digitali utente sono a 3,3 V per impostazione predefinita ma instradati attraverso level shifter programmabili via software (VDDIO_EXT) che possono essere riconfigurati a 1,8 V. I pin analogici (A0–A2) sono solo a 1,8 V — bypassano i level shifter e si collegano direttamente al MCU. Applicare 3,3 V su A0–A2 danneggerà il SoC.

Pinout

Pinout dell'Arduino Nicla Vision

Riferimento dei pin

Tredici pin utente sono esposti sui connettori a pettine Arduino (J1 e J2). Ulteriori segnali di debug, recovery e PMIC sono instradati a piazzole di test sul retro della scheda.

Nome del pin

Riferimento

Funzione

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 canale 4 (J1‑8)

A1

1,8 V

ADC2 canale 2 (J1‑7)

A2

1,8 V

ADC3 canale 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

collega a GND (o premi l’interruttore integrato) per resettare la scheda

LED_RED

3,3 V

canale rosso del LED RGB (attivo basso)

LED_GREEN

3,3 V

canale verde del LED RGB (attivo basso)

LED_BLUE

3,3 V

canale blu del LED RGB (attivo basso)

Nota

D0D3 e SCLK/CIPO/COPI/CS si trovano dietro il level shifter bidirezionale TXB0108 — quel componente supporta solo la pilotaggio GPIO push‑pull, quindi il traffico di bus open‑drain (ad esempio un 1‑Wire o un I²C bit‑banged su quei pin) non funzionerà.

SCL/SDA si trovano dietro un separato shifter NTS0304 che supporta sia il pilotaggio push‑pull che open‑drain, motivo per cui l’I²C 1 funziona lì.

Entrambi gli shifter sono riferiti a VDDIO_EXT (3,3 V per impostazione predefinita dal PMIC integrato) e la loro capacità di pilotaggio è limitata rispetto a un GPIO diretto — sono progettati per carichi di livello di segnale piuttosto che di potenza.

Pin di alimentazione

Pin dei connettori a pettine:

  • VIN (J2‑9) — linea di sistema principale 3,6 – 5 V. Il PMIC prende qui il suo ingresso.

  • VDDIO_EXT (J2‑7) — uscita della linea dei level shifter, 1,8 V o 3,3 V (3,3 V per impostazione predefinita). Usala per alimentare periferiche esterne a 1,8 V o 3,3 V collegate ai pin LPIO/SPI/I²C così che parlino lo stesso livello logico dei connettori.

  • VBAT (J3‑2) — ingresso batteria Li‑Po. Il PMIC integrato carica la cella da VIN e riporta lo stato di carica tramite il fuel gauge.

  • NTC (J3‑1) — ingresso opzionale per termistore Li‑Po.

  • GND (J2‑6) — massa comune.

  • NC (J2‑8) — non collegato.

Piazzole di test sul retro della scheda:

  • +3V3 — linea principale a 3,3 V.

  • D_P / D_N — coppia di dati USB ad alta velocità (post‑PHY).

L’USB e il connettore ESLOV alimentano entrambi VIN attraverso una coppia di diodi ideali LM66100 (uno per sorgente), così che ciascuna alimentazione possa alimentare la scheda da sola e le due non si pilotino mai a vicenda all’indietro. Se piloti VIN esternamente su J2‑9, quello ha la precedenza — i diodi smettono semplicemente di condurre da USB / ESLOV una volta che la linea esterna sale più in alto.

La scheda può quindi essere alimentata attraverso una qualsiasi di queste vie:

  • Micro USB — 5 V su VIN attraverso il diodo ideale lato USB.

  • Connettore ESLOV — fino a 5 V sul pin VESLOV di J5, instradato in VIN attraverso il diodo ideale lato ESLOV (vedi Connettore ESLOV).

  • Pin VIN (J2‑9) — piloti direttamente un’alimentazione regolata a 3,6 – 5 V.

  • Batteria Li‑Po — collega al connettore batteria J4 sul retro oppure alle piazzole VBAT/GND/NTC su J3 / J2‑6. Non collegare due batterie contemporaneamente.

Connettore ESLOV

J5 sul retro della scheda è un connettore ESLOV Molex a 5 pin senza saldatura:

Pin

Nome

Funzione

J5‑1

VESLOV

ingresso di alimentazione (≤ 5 V) — combinato in OR su VIN tramite un diodo ideale LM66100

J5‑2

INT

ingresso di interrupt esterno su PD9

J5‑3

SCL_EXT

condiviso con la piazzola SCL di J2 — stesso bus I²C 1 del connettore utente

J5‑4

SDA_EXT

condiviso con la piazzola SDA di J2 — stesso bus I²C 1 del connettore utente

J5‑5

GND

massa comune

Gli SCL_EXT/SDA_EXT dell’ESLOV e gli SCL/SDA di J2 sono gli stessi pin — un unico bus I²C 1 esposto su due connettori.

Suggerimento

Usa lo stimatore di durata della batteria per modellare per quanto tempo la Nicla Vision funzionerà a batteria per un dato ciclo di lavoro attivo / deep‑sleep.

Pin di recovery e debug

  • RESET — sia un interruttore momentaneo sulla parte superiore della scheda sia una piazzola (J3‑4 / piazzola di test P5) collegata alla linea NRST del SoC. Collega a GND per resettare.

La Nicla Vision usa il double‑tap reset standard di Arduino per entrare nel bootloader di Arduino — premi rapidamente il pulsante di reset due volte e la scheda si enumera come dispositivo DFU. OpenMV IDE usa questa modalità per riflashare il firmware.

I segnali SWD dell’STM32 sono esposti sul retro della scheda attraverso una fila di piazzole di test tra i due connettori J2. Salda un pettine da 2,54 mm (100 mil) in esse per collegare un adattatore ST‑LINK o J‑Link:

  • P1 / P2 — bus I²C del PMIC interno su PF0 (SDA) e PF1 (SCL). Questo è machine.I2C(2) sulla Nicla Vision e trasporta il traffico del PMIC, del fuel gauge e del ToF.

  • P3 — TMS / SWDIO (PA13)

  • P4 — TCK / SWCLK (PA14)

  • P5 — NRST

  • P6 — TDO / SWO (PB3)

  • P7 — linea +1V8 (l’alimentazione di I/O del SoC — anche il riferimento corretto per l’adattatore di debug).

  • P8VOTP_PMICsolo programmazione di fabbrica. Deve essere lasciato non collegato.

Tutti i segnali di debug sono riferiti a 1,8 V — l’anello di I/O dell’STM32H747 su questa scheda funziona dalla linea +1V8. Imposta il tuo adattatore di debug per logica a 1,8 V prima di collegarlo.

Periferiche integrate

LED

La Nicla Vision ha un singolo LED RGB utente, controllabile via software tramite machine.LED

from machine import LED

LED("LED_RED").on()
LED("LED_GREEN").on()
LED("LED_BLUE").on()

Un LED separato DL2 CHARGE sul lato della scheda è cablato direttamente all’uscita CHGB del PMIC — si accende mentre una batteria Li‑Po viene caricata da USB / ESLOV / VIN e non è controllabile dall’utente.

Sensore camera

Il GC2145 è pilotato attraverso il modulo csi — sensori camera

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()

Quando richiedi un framesize piccolo, il driver del GC2145 ritaglia una finestra di lettura proporzionalmente piccola dal sensore — per impostazione predefinita il rapporto di downscale dalla lettura all’uscita è limitato a 3x per mantenere alto il frame rate. csi.IOCTL_SET_FOV_WIDE alza tale limite a 5x, il che significa che il driver preleva da un’area più ampia del sensore quando trasmette in streaming risoluzioni piccole. Il risultato è un campo visivo notevolmente più ampio ai framesize piccoli, a costo di un po” di throughput:

cam.ioctl(csi.IOCTL_SET_FOV_WIDE, True)
cam.ioctl(csi.IOCTL_GET_FOV_WIDE)  # returns the current setting

Core M4

Il core Cortex‑M4 è esposto attraverso openamp per la comunicazione tra processori. Il firmware OpenMV gira solo sull’M7; l’M4 non ha un proprio runtime MicroPython, quindi usarlo significa compilare una immagine firmware C separata e caricarla dal filesystem tramite openamp.RemoteProc. Un firmware di esempio precompilato che implementa un endpoint UART virtuale è disponibile nel repository openamp_vuart — segui il suo README per compilare 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)

In pratica è meglio considerare questo supporto come una dimostrazione dell’interfaccia openamp piuttosto che come una piattaforma dual‑core funzionante — l’M4 non può essere resettato indipendentemente dall’M7, quindi fermare l’M4 forza un riavvio completo del sistema.

Microfono

Il microfono PDM MP34DT06JTR integrato è catturato tramite audio — Modulo Audio sulla periferica DFSDM dell’STM32. Ogni buffer arriva come un bytearray PCM a 16 bit con segno, pronto per essere passato a ulab/numpy per il DSP — per esempio, un semplice rilevatore di volume:

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

L’accelerometro + giroscopio LSM6DSOX integrato è esposto attraverso imu — sensore 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)

L’IMU è cablata a un bus SPI interno dedicato (SPI5) così da non entrare in conflitto con l’SPI4 utente esposto sui connettori.

Telemetro time‑of‑flight

Il telemetro time‑of‑flight ST VL53L1CB integrato si trova sul bus I²C del PMIC interno (I²C 2). Usa il driver congelato vl53l1x — Driver del sensore di distanza ToF VL53L1X per ottenere letture di distanza fino a ~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)

Fuel gauge della batteria

Il fuel gauge Maxim MAX17262 ModelGauge m5 traccia la tensione, la corrente, la temperatura e lo stato di carica della batteria Li‑Po. Si trova sull”I²C 2 all’indirizzo 0x36.

Il MAX17262 ha il rilevamento di corrente interno, quindi il registro della corrente fornisce direttamente la lettura in microampere senza alcun fattore Rsense esterno da applicare. Leggere il fuel gauge è innocuo — non viene fornito alcun driver, ma i registri documentati nel datasheet del MAX17262 possono essere letti direttamente:

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 è in complemento a due con segno: positivo durante la carica, negativo durante la scarica. TTE è significativo solo quando la corrente è negativa; TTF solo quando la corrente è positiva.

IC di gestione dell’alimentazione

Il PMIC NXP MC34PF1550A0EP gestisce ogni regolatore sulla Nicla Vision — la linea principale +3V3, la linea +1V8 del core / I/O del SoC, VDDIO_EXT ai level shifter e il caricabatterie Li‑Po. Si trova sull”I²C 2 all’indirizzo 0x08.

Avvertimento

Leggere i registri del PMIC va bene; scriverci è pericoloso. Configurare male un regolatore buck o un’impostazione del caricabatterie può danneggiare permanentemente la scheda, la batteria o entrambe. Tratta il PMIC come di sola lettura a meno che tu non sappia esattamente cosa stai facendo.

La cosa più utile che il PMIC ti dice e che il fuel gauge non può è la macchina a stati del caricabatterie — se la scheda sta attualmente funzionando da USB / ESLOV / VIN, in quale fase del ciclo di carica si trova la Li‑Po e se il caricabatterie è in un guasto termico o di watchdog. I registri del caricabatterie risiedono a un offset di 0x80 nello spazio di indirizzi I²C principale del PF1550 (vedi §22.2 del datasheet del PF1550), quindi per esempio CHG_INT_OK all’indirizzo del caricabatterie 0x04 viene letto dal registro 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(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)

Altri registri di sola lettura che vale la pena consultare nel datasheet (tutti all’offset del caricabatterie 0x80): 0x80 CHG_INT (interrupt del caricabatterie latched — flag di guasto), 0x86 VBUS_SNS (lo stato VBUS multi‑bit incluso OVLO / UVLO / DPM) e 0x88 BATT_SNS (presenza della batteria e stato di sovracorrente).

Wi‑Fi

Il Murata 1DX (CYW4343W) integrato è esposto tramite network — configurazione di rete come interfaccia station. Collega l’antenna fornita al connettore U.FL integrato prima di attivare 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

Lo stesso Murata 1DX espone anche il Bluetooth LE 5.1. Usa aioble — BLE asincrono per BLE adatto ad asyncio — per esempio, annunciarsi come periferica e attendere che un central si connetta:

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())

Riferimento dei bus

GPIO

Usa machine.Pin per leggere o pilotare uno qualsiasi dei pin serigrafati. Le uscite sono CMOS a 3,3 V (VDDIO_EXT predefinito) e i level shifter limitano la capacità di pilotaggio per pin a pochi milliampere — sono progettati per carichi di livello di segnale piuttosto che di potenza.

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())

Qualsiasi pin di ingresso può anche far scattare un interrupt sulle transizioni di fronte:

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 condivide i suoi pin con l”I²C 1 — le stesse piazzole SDA/SCL trasportano entrambi i bus. Scegli UART o I²C, non entrambi, su quei pin.

La serigrafia D1/D2 riporta anche UART_TX/UART_RX, ma su questo firmware quei pin sono instradati a LPUART1, non a machine.UART. machine.UART(1) stesso è riservato al controller Bluetooth on‑chip e non è accessibile sui connettori.

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")

Le piazzole SCL/SDA su J2 e i pin SCL_EXT/SDA_EXT del connettore ESLOV terminano sullo stesso bus I²C 1 — vedi Connettore ESLOV sopra per il pinout dell’ESLOV.

Lo stesso hardware può anche essere usato in modalità target (slave) tramite machine.I2CTarget per esporre una regione di memoria a un altro controller 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 espone tre canali ADC a 12 bit su A0, A1 e A2. Tutti e tre sono riferiti a 1,8 Vread_u16 restituisce 0–65535 su 0–1,8 V al 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)

Avvertimento

Gli ingressi ADC della Nicla Vision sono riferiti a 1,8 V (e non hanno alcun level shifter davanti al SoC). Pilotare un segnale a 3,3 V saturerà il convertitore e potrebbe danneggiare il pin — riduci esternamente le tensioni più alte tramite un partitore.

PWM

Pin

Timer / canale

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

Pilota uno qualsiasi di essi tramite machine.PWM

from machine import Pin, PWM

pwm = PWM(Pin("D1"), freq=1_000, duty_u16=32768)

Nota

Diversi pin condividono canali TIM1:

  • TIM1 CH2 è su D1 e CS.

  • TIM1 CH3 è su D2 e CIPO; SCLK emette il complemento invertito (TIM1 CH3N) dello stesso canale.

  • TIM1 CH4 è su COPI da solo.

Scegli un solo consumatore per canale timer. Anche i pin del quartetto SPI (SCLK/CIPO/COPI/CS) non possono essere pilotati in PWM mentre machine.SPI(4) li sta usando.

Bus bit‑banged via software

machine.SoftI2C e machine.SoftSPI funzionano su qualsiasi GPIO se ti serve un bus aggiuntivo.

Sensore termico (esterno)

Il firmware include il driver fir — driver del sensore termico (fir == far infrared) per imager termici cablati esternamente:

  • MLX90621 — array IR 16 × 4

  • MLX90640 — array IR 32 × 24

  • MLX90641 — array IR 16 × 12

  • AMG8833 — array IR 8 × 8

Collega il modulo al bus I²C della scheda e leggi i frame 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())

Il driver fir parla con il sensore solo sull”I²C 1 — collega il modulo alle piazzole serigrafate SCL / SDA.

Timing

time

Il modulo time copre i ritardi bloccanti, i tick monotoni e la misurazione del tempo trascorso:

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)

Timer virtuali

machine.Timer pianifica callback periodici o one‑shot senza consumare uno slot di timer hardware. Passa -1 come id per usare un timer virtuale (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"))

I valori del periodo sono in millisecondi. Chiama deinit() per fermare e rilasciare lo slot.

Real‑time clock

machine.RTC mantiene l’ora reale attraverso i reset:

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 resetta la scheda se l’applicazione si blocca. Una volta avviato non può essere fermato né riconfigurato — alimentalo periodicamente all’interno del tuo loop principale:

from machine import WDT

wdt = WDT(timeout=5_000)   # 5 second window
while True:
    # ...do work...
    wdt.feed()

Informazioni di boot e runtime

Aggiornamento del firmware (DFU)

La Nicla Vision usa il double‑tap reset standard di Arduino per entrare nel bootloader di Arduino. Premi rapidamente il pulsante di reset due volte — la scheda si rienumera su USB come dispositivo DFU e OpenMV IDE può flashare una nuova immagine firmware.

Uno script in esecuzione può rientrare nel bootloader su richiesta chiamando machine.bootloader()

import machine

machine.bootloader()

Filesystem e ordine di boot

Il firmware della Nicla Vision monta fino a due filesystem all’avvio:

  • Flash interna — sempre montata su /flash. Contiene main.py e README.txt per impostazione predefinita; creata al primissimo avvio.

  • ROMFS — filesystem di sola lettura, mappato in memoria, su /rom montato automaticamente da MicroPython all’avvio.

Dopo il montaggio, la directory di lavoro è impostata su /flash. L’interprete esegue quindi gli script da quella directory:

  • boot.py viene eseguito a ogni soft reset (avvio a freddo, Ctrl‑D dal REPL o ogni volta che lo script in esecuzione termina).

  • main.py viene eseguito solo all’avvio a freddo, subito dopo boot.py. I soft reset successivi rieseguono boot.py ma scendono direttamente al REPL — per rieseguire main.py devi resettare completamente la scheda.

Il main.py predefinito fornito su una scheda appena flashata fa semplicemente lampeggiare il canale blu del LED RGB utente come battito cardiaco (due brevi impulsi, breve pausa), così puoi capire che il firmware si è avviato correttamente senza alcun host collegato.

sys.path viene esteso per includere entrambi i filesystem e le loro sottodirectory lib/, così i moduli importabili possono risiedere in /flash/lib o /rom/lib.

Quando collegata via USB, /flash si enumera anche come unità di archiviazione di massa USB sull’host, permettendoti di modificare boot.py, main.py e qualsiasi altro file direttamente. Espelli l’unità prima di resettare la camera così che l’host scarichi le sue scritture in cache.

Nota

Poiché il sistema operativo tratta l’unità come un dispositivo a blocchi passivo, i file creati o modificati dal codice in esecuzione sulla camera non compariranno finché l’host non rimonta l’unità. Se sia il sistema operativo che la camera scrivono sullo stesso filesystem contemporaneamente, vincerà il sistema operativo e sovrascriverà le modifiche fatte dalla camera. Usa la scheda SD per qualsiasi dato che lo script riscrive e rimonta prima di leggere quei file dall’host.

Nota

Il canale rosso del LED RGB utente può accendersi brevemente mentre l’host sta leggendo dall’unità di archiviazione di massa USB o scrivendo su di essa — è un indicatore di attività gestito dal firmware, non un guasto.

Dimensioni di archiviazione

La Nicla Vision viene fornita con:

  • /flash — filesystem FAT da 11 MB, lettura/scrittura.

  • /rom — ROMFS di sola lettura mappato in memoria da 4 MB, usato per fornire script e modelli ML che beneficiano dell’accesso mmap zero‑copy.

Indicatore di hard‑fault

Se il LED RGB utente sta ciclando rapidamente attraverso tutti i colori — abbastanza rapidamente da sembrare un LED bianco scintillante piuttosto che tinte distinte — il firmware ha incontrato un hard fault irrecuperabile. Riflasha il firmware per ripristinare; se il riflash non aiuta, la scheda potrebbe essere fisicamente danneggiata.

Librerie software

Consulta l”indice della libreria per l’elenco completo dei moduli — incluso quali sono esclusivi della build della Nicla Vision.