Arduino Nicla Vision¶
A Arduino Nicla Vision é uma placa de visão de máquina de 22,86 × 22,86 mm construída em torno do STMicroelectronics STM32H747AII6 — um SoC dual-core que combina um Cortex-M7 a 400 MHz com um Cortex-M4 a 200 MHz. O firmware da OpenMV roda inteiramente no núcleo M7. A placa combina o MCU com o sensor CMOS colorido GC2145 de 2 MP, uma IMU de 6 eixos LSM6DSOX, um microfone MEMS MP34DT06, um medidor de distância por tempo de voo VL53L1CB, Wi-Fi + Bluetooth LE 5.1 e um carregador de bateria / medidor de carga (fuel gauge).
Para datasheet completo, fotos e dimensões, consulte a página do produto Arduino Nicla Vision.
Destaques¶
STMicroelectronics STM32H747AII6 dual Cortex-M7 (400 MHz) + Cortex-M4 (200 MHz). O firmware da OpenMV roda apenas no núcleo M7.
2 MB de flash interna mais 16 MB de flash QSPI externa (usada para a aplicação + ROMFS).
1 MB de SRAM interna.
Codificador/decodificador JPEG em hardware.
Sensor CMOS colorido GC2145 de 2 MP.
IMU integrada (acelerômetro + giroscópio LSM6DSOX), microfone MEMS (MP34DT06JTR) e medidor de distância por tempo de voo VL53L1CB (até ~4 m).
Wi-Fi b/g/n (2,4 GHz) + Bluetooth LE 5.1 através do módulo Murata 1DX (CYW4343W) — conecta-se à antena fornecida por meio de um conector U.FL na placa.
USB de alta velocidade (480 Mb/s) sobre Micro USB através de um PHY ULPI externo (USB3320C).
13 pinos de I/O do usuário nos conectores de borda Arduino — quatro LPIOs digitais (
D0–D3), três entradas analógicas de 1,8 V (A0–A2), o par I²CSCL/SDAe o quarteto SPISCLK/CIPO/COPI/CS.Suporte a bateria — conector Li-Po na parte de trás, carregador no estilo BQ e medidor de carga (fuel gauge) MAX17262 sobre o barramento PMIC interno.
Conector ESLOV de 5 pinos na parte de trás para expansão I²C sem solda.
Aviso
Os pinos digitais do usuário são 3,3 V por padrão, mas roteados através de conversores de nível programáveis por software (VDDIO_EXT) que podem ser reconfigurados para 1,8 V. Os pinos analógicos (A0–A2) são apenas 1,8 V — eles contornam os conversores de nível e se conectam diretamente ao MCU. Aplicar 3,3 V em A0–A2 danificará o SoC.
Pinagem¶
Referência de pinos¶
Treze pinos do usuário são expostos nos conectores de borda Arduino (J1 e J2). Sinais adicionais de depuração, recuperação e PMIC são roteados para pads de teste na parte de trás da placa.
Nome do pino |
Referência |
Função |
|---|---|---|
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 |
puxe para GND (ou pressione o interruptor da placa) para reiniciar a placa |
LED_RED |
3,3 V |
canal vermelho do LED RGB (ativo em nível baixo) |
LED_GREEN |
3,3 V |
canal verde do LED RGB (ativo em nível baixo) |
LED_BLUE |
3,3 V |
canal azul do LED RGB (ativo em nível baixo) |
Nota
D0–D3 e SCLK/CIPO/COPI/CS ficam atrás do conversor de nível bidirecional TXB0108 — essa peça só suporta acionamento GPIO push-pull, então o tráfego de barramento em dreno aberto (open-drain) (por exemplo, um 1-Wire ou I²C feito por bit-banging nesses pinos) não funcionará.
SCL/SDA ficam atrás de um conversor NTS0304 separado que suporta tanto acionamento push-pull quanto dreno aberto (open-drain), e é por isso que o I²C 1 funciona ali.
Ambos os conversores são referenciados a VDDIO_EXT (3,3 V por padrão a partir do PMIC da placa), e sua capacidade de acionamento é limitada em comparação com um GPIO direto — eles são projetados para cargas de nível de sinal e não de potência.
Pinos de alimentação¶
Pinos do conector de borda:
VIN (J2‑9) — barramento principal do sistema de 3,6 – 5 V. O PMIC recebe sua entrada aqui.
VDDIO_EXT (J2‑7) — saída do barramento do conversor de nível, 1,8 V ou 3,3 V (3,3 V por padrão). Use isto para alimentar periféricos externos de 1,8 V ou 3,3 V conectados aos pinos LPIO/SPI/I²C de modo que falem o mesmo nível lógico dos conectores.
VBAT (J3‑2) — entrada de bateria Li-Po. O PMIC da placa carrega a célula a partir de VIN e relata o estado de carga através do medidor de carga (fuel gauge).
NTC (J3‑1) — entrada opcional para termistor da Li-Po.
GND (J2‑6) — terra comum.
NC (J2‑8) — sem conexão.
Pads de teste na parte de trás da placa:
+3V3 — barramento principal de 3,3 V.
D_P / D_N — par de dados USB de alta velocidade (pós-PHY).
Tanto o USB quanto o conector ESLOV alimentam o VIN através de um par de diodos ideais LM66100 (um por fonte), de modo que qualquer das fontes pode alimentar a placa por conta própria e as duas nunca se realimentam mutuamente. Se você acionar VIN externamente em J2‑9, isso tem precedência — os diodos simplesmente param de conduzir a partir do USB / ESLOV assim que o barramento externo sobe mais alto.
Portanto, a placa pode ser alimentada por qualquer um destes caminhos:
Micro USB — 5 V em VIN através do diodo ideal do lado USB.
Conector ESLOV — até 5 V no pino
VESLOVde J5, roteado para VIN através do diodo ideal do lado ESLOV (consulte Conector ESLOV).Pino VIN (J2‑9) — acione uma fonte regulada de 3,6 – 5 V diretamente.
Bateria Li-Po — conecte ao conector de bateria J4 na parte de trás ou aos pads VBAT/GND/NTC em J3 / J2‑6. Não conecte duas baterias simultaneamente.
Conector ESLOV¶
J5 na parte de trás da placa é um conector ESLOV Molex sem solda de 5 pinos:
Pino |
Nome |
Função |
|---|---|---|
J5‑1 |
VESLOV |
entrada de alimentação (≤ 5 V) — combinada (OR) com |
J5‑2 |
INT |
entrada de interrupção externa em |
J5‑3 |
SCL_EXT |
compartilhado com o pad |
J5‑4 |
SDA_EXT |
compartilhado com o pad |
J5‑5 |
GND |
terra comum |
Os pinos SCL_EXT/SDA_EXT do ESLOV e os SCL/SDA de J2 são os mesmos pinos — um único barramento I²C 1 exposto em dois conectores.
Dica
Use o estimador de vida útil da bateria para modelar por quanto tempo a Nicla Vision funcionará com bateria para um determinado ciclo de trabalho ativo / sono profundo (deep-sleep).
Pinos de recuperação e depuração¶
RESET — tanto um interruptor momentâneo na parte de cima da placa quanto um pad (J3‑4 / pad de teste P5) ligado à linha NRST do SoC. Puxe para GND para reiniciar.
A Nicla Vision usa o reset por duplo toque padrão da Arduino para entrar no bootloader da Arduino — pressione rapidamente o botão de reset duas vezes e a placa enumera como um dispositivo DFU. A OpenMV IDE usa esse modo para regravar o firmware.
Os sinais SWD do STM32 são expostos na parte de trás da placa através de uma fileira de pads de teste entre os dois conectores J2. Solde um conector de 2,54 mm (100 mil) neles para conectar um adaptador ST-LINK ou J-Link:
P1 / P2 — barramento I²C interno do PMIC em PF0 (SDA) e PF1 (SCL). Este é o
machine.I2C(2)na Nicla Vision e transporta o tráfego do PMIC, do medidor de carga (fuel gauge) e do ToF.P3 — TMS / SWDIO (PA13)
P4 — TCK / SWCLK (PA14)
P5 — NRST
P6 — TDO / SWO (PB3)
P7 — barramento +1V8 (a alimentação de I/O do SoC — também a referência correta para o adaptador de depuração).
P8 —
VOTP_PMIC— apenas programação de fábrica. Deve ser deixado desconectado.
Todos os sinais de depuração são referenciados a 1,8 V — o anel de I/O do STM32H747 nesta placa funciona a partir do barramento +1V8. Configure seu adaptador de depuração para lógica de 1,8 V antes de conectar.
Periféricos integrados¶
LEDs¶
A Nicla Vision tem um único LED RGB de usuário, controlável por software através de machine.LED
from machine import LED
LED("LED_RED").on()
LED("LED_GREEN").on()
LED("LED_BLUE").on()
Um LED DL2 CHARGE separado na lateral da placa é ligado diretamente à saída CHGB do PMIC — ele acende enquanto uma bateria Li-Po está sendo carregada a partir de USB / ESLOV / VIN e não é controlável pelo usuário.
Sensor da câmera¶
O GC2145 é acionado através do módulo csi — sensores de câmera
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 você solicita um tamanho de quadro pequeno, o driver do GC2145 recorta uma janela de leitura proporcionalmente pequena do sensor — por padrão, a razão de redução de escala entre leitura e saída é limitada a 3x para manter a taxa de quadros alta. csi.IOCTL_SET_FOV_WIDE aumenta esse limite para 5x, o que significa que o driver puxa de uma área mais ampla do sensor ao transmitir resoluções pequenas. O resultado é um campo de visão visivelmente mais amplo em tamanhos de quadro pequenos, ao custo de algum throughput:
cam.ioctl(csi.IOCTL_SET_FOV_WIDE, True)
cam.ioctl(csi.IOCTL_GET_FOV_WIDE) # returns the current setting
Núcleo M4¶
O núcleo Cortex-M4 é exposto através do openamp para comunicação entre processadores. O firmware da OpenMV roda apenas no M7; o M4 não tem um runtime MicroPython próprio, então usá-lo significa compilar uma imagem de firmware C separada e carregá-la a partir do sistema de arquivos via openamp.RemoteProc. Um firmware de exemplo pré-compilado que implementa um endpoint de UART virtual está disponível no repositório openamp_vuart — siga o 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)
Na prática, esse suporte é melhor tratado como uma demonstração da interface openamp do que como uma plataforma dual-core funcional — o M4 não pode ser reiniciado independentemente do M7, então parar o M4 força uma reinicialização completa do sistema.
Microfone¶
O microfone PDM MP34DT06JTR integrado é capturado através de audio — Módulo de Áudio sobre o periférico DFSDM do STM32. Cada buffer chega como um bytearray PCM de 16 bits com sinal, pronto para ser alimentado em ulab/numpy para DSP — por exemplo, um detector de intensidade sonora simples:
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¶
O acelerômetro + giroscópio LSM6DSOX integrado é exposto atravé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)
A IMU é ligada a um barramento SPI interno dedicado (SPI5), de modo que não disputa com o SPI4 do usuário exposto nos conectores.
Medidor de distância por tempo de voo¶
O medidor de distância por tempo de voo ST VL53L1CB integrado fica no barramento I²C interno do PMIC (I²C 2). Use o driver congelado vl53l1x — Driver do sensor de distância ToF VL53L1X para obter leituras de distância de até ~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 da bateria (fuel gauge)¶
O medidor de carga (fuel gauge) Maxim MAX17262 ModelGauge m5 acompanha a tensão, a corrente, a temperatura e o estado de carga da bateria Li-Po. Ele fica no I²C 2 no endereço 0x36.
O MAX17262 possui medição de corrente interna, então o registrador de corrente é lido diretamente em microampères, sem fator Rsense externo a aplicar. Ler o medidor de carga (fuel gauge) é inofensivo — não há driver fornecido, mas os registradores documentados no datasheet do MAX17262 podem ser lidos diretamente:
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 é um valor com sinal em complemento de dois: positivo durante o carregamento, negativo durante a descarga. TTE só faz sentido quando a corrente é negativa; TTF apenas quando a corrente é positiva.
Circuito integrado de gerenciamento de energia (PMIC)¶
O PMIC NXP MC34PF1550A0EP gerencia cada regulador da Nicla Vision — o barramento principal +3V3, o barramento +1V8 do núcleo / I/O do SoC, o VDDIO_EXT para os conversores de nível e o carregador Li-Po. Ele fica no I²C 2 no endereço 0x08.
Aviso
Ler registradores do PMIC é seguro; escrever neles é perigoso. Configurar incorretamente um regulador buck ou uma configuração do carregador pode danificar permanentemente a placa, a bateria, ou ambos. Trate o PMIC como somente leitura, a menos que você saiba exatamente o que está fazendo.
A coisa mais útil que o PMIC informa e que o medidor de carga (fuel gauge) não consegue é a máquina de estados do carregador — se a placa está atualmente funcionando a partir de USB / ESLOV / VIN, em que estágio do ciclo de carga a Li-Po está, e se o carregador está em falha térmica ou de watchdog. Os registradores do carregador ficam em um deslocamento de 0x80 no espaço de endereços I²C principal do PF1550 (consulte §22.2 do datasheet do PF1550), então, por exemplo, CHG_INT_OK no endereço de carregador 0x04 é lido a partir do registrador 0x84 do 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)
Outros registradores somente leitura que vale a pena conferir no datasheet (todos no deslocamento de carregador 0x80): 0x80 CHG_INT (interrupções do carregador travadas (latched) — sinalizadores de falha), 0x86 VBUS_SNS (o estado VBUS de múltiplos bits, incluindo OVLO / UVLO / DPM) e 0x88 BATT_SNS (presença da bateria e estado de sobrecorrente).
Wi-Fi¶
O Murata 1DX (CYW4343W) integrado é exposto via network — configuração de rede como uma interface de estação. Conecte a antena fornecida ao conector U.FL integrado antes de ativar o rádio:
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¶
O mesmo Murata 1DX também expõe Bluetooth LE 5.1. Use aioble — BLE Assíncrono para BLE compatível com asyncio — por exemplo, anuncie-se como periférico e aguarde a conexão de um central:
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())
Referência de barramentos¶
GPIO¶
Use machine.Pin para ler ou acionar qualquer um dos pinos serigrafados. As saídas são CMOS de 3,3 V (VDDIO_EXT por padrão) e os conversores de nível limitam a capacidade de acionamento por pino a alguns miliampères — eles são projetados para cargas de nível de sinal e não de potência.
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())
Qualquer pino de entrada também pode disparar uma interrupção em transições de borda:
def handler(pin):
print("triggered:", pin)
Pin("D1", Pin.IN, Pin.PULL_UP).irq(
handler, Pin.IRQ_FALLING | Pin.IRQ_RISING,
)
UART¶
Barramento |
TX |
RX |
|---|---|---|
UART4 |
SDA |
SCL |
from machine import UART
uart = UART(4, baudrate=115200)
uart.write("hello")
uart.read(5)
Nota
O UART4 compartilha seus pinos com o I²C 1 — os mesmos pads SDA/SCL transportam ambos os barramentos. Escolha UART ou I²C nesses pinos, não os dois.
A serigrafia D1/D2 também indica UART_TX/UART_RX, mas neste firmware esses pinos são roteados para o LPUART1, e não para machine.UART. O próprio machine.UART(1) é reservado para o controlador Bluetooth no chip e não é acessível nos conectores.
I²C¶
Barramento |
SCL |
SDA |
|---|---|---|
I2C1 |
SCL |
SDA |
from machine import I2C
i2c = I2C(1, freq=400_000)
i2c.scan()
i2c.writeto(0x76, b"hi")
Os pads SCL/SDA em J2 e os pinos SCL_EXT/SDA_EXT do conector ESLOV chegam ao mesmo barramento I²C 1 — consulte Conector ESLOV acima para a pinagem do ESLOV.
O mesmo hardware também pode ser usado em modo alvo (escravo) através de machine.I2CTarget para expor uma região de memória a outro controlador I²C:
from machine import I2CTarget
buf = bytearray(32)
target = I2CTarget(1, addr=0x42, mem=buf)
SPI¶
Barramento |
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¶
A Nicla Vision expõe três canais de ADC de 12 bits em A0, A1 e A2. Todos os três são referenciados a 1,8 V — read_u16 retorna 0–65535 ao longo de 0–1,8 V no pino:
from machine import ADC
import time
adc = ADC("A0")
while True:
voltage = adc.read_u16() * 1.8 / 65535
print(voltage)
time.sleep_ms(100)
Aviso
As entradas do ADC da Nicla Vision são referenciadas a 1,8 V (e não têm conversor de nível à frente do SoC). Aplicar um sinal de 3,3 V satura o conversor e pode danificar o pino — divida tensões mais altas externamente.
PWM¶
Pino |
Timer / 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 |
Acione qualquer um deles via machine.PWM
from machine import Pin, PWM
pwm = PWM(Pin("D1"), freq=1_000, duty_u16=32768)
Nota
Vários pinos compartilham canais do TIM1:
TIM1 CH2 está em
D1eCS.TIM1 CH3 está em
D2eCIPO;SCLKproduz o complemento invertido (TIM1 CH3N) do mesmo canal.TIM1 CH4 está apenas em
COPI.
Escolha um único consumidor por canal de timer. Os pinos do quarteto SPI (SCLK/CIPO/COPI/CS) também não podem ser acionados por PWM enquanto machine.SPI(4) estiver os usando.
Barramentos por software (bit-banging)¶
machine.SoftI2C e machine.SoftSPI funcionam em qualquer GPIO caso você precise de um barramento extra.
Sensor térmico (externo)¶
O firmware inclui o driver fir — driver de sensor térmico (fir == far infrared) para imageadores térmicos conectados externamente:
MLX90621 — array IR de 16 × 4
MLX90640 — array IR de 32 × 24
MLX90641 — array IR de 16 × 12
AMG8833 — array IR de 8 × 8
Conecte o módulo ao barramento I²C da placa e leia quadros com 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())
O driver fir só se comunica com o sensor sobre o I²C 1 — conecte o módulo aos pads serigrafados SCL / SDA.
Temporização¶
time¶
O módulo time cobre atrasos bloqueantes, ticks monotônicos e medição de tempo decorrido:
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)
Timers virtuais¶
machine.Timer agenda callbacks periódicos ou de disparo único sem consumir um slot de timer de hardware. Passe -1 como id para usar um timer 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"))
Os valores de período são em milissegundos. Chame deinit() para parar e liberar o slot.
Relógio de tempo real¶
machine.RTC mantém a hora do relógio de parede entre reinicializações:
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 a placa se a aplicação travar. Uma vez iniciado, não pode ser parado nem reconfigurado — alimente-o periodicamente dentro do seu loop principal:
from machine import WDT
wdt = WDT(timeout=5_000) # 5 second window
while True:
# ...do work...
wdt.feed()
Informações de boot e tempo de execução¶
Atualização de firmware (DFU)¶
A Nicla Vision usa o reset por duplo toque padrão da Arduino para entrar no bootloader da Arduino. Pressione rapidamente o botão de reset duas vezes — a placa reenumera sobre USB como um dispositivo DFU e a OpenMV IDE pode gravar uma nova imagem de firmware.
Um script em execução pode reentrar no bootloader sob demanda chamando machine.bootloader()
import machine
machine.bootloader()
Sistema de arquivos e ordem de boot¶
O firmware da Nicla Vision monta até dois sistemas de arquivos durante o boot:
Flash interna — sempre montada em
/flash. Contémmain.pyeREADME.txtpor padrão; criada no primeiro boot.ROMFS — sistema de arquivos somente leitura, mapeado em memória, em
/rom, montado automaticamente pelo MicroPython na inicialização.
Após a montagem, o diretório de trabalho é definido como /flash. O interpretador então executa scripts a partir desse diretório:
boot.pyé executado em todo soft reset (boot a frio,Ctrl‑Da partir do REPL, ou sempre que o script em execução retorna).main.pyé executado apenas no boot a frio, imediatamente apósboot.py. Soft resets subsequentes reexecutamboot.py, mas caem diretamente no REPL — para reexecutarmain.pyvocê precisa reiniciar totalmente a placa.
O main.py padrão fornecido em uma placa recém-gravada apenas pisca o canal azul do LED RGB do usuário como um batimento cardíaco (dois pulsos curtos, intervalo curto), para que você possa saber que o firmware inicializou corretamente sem nenhum host conectado.
sys.path é estendido para incluir ambos os sistemas de arquivos e seus subdiretórios lib/, de modo que módulos importáveis podem residir em /flash/lib ou /rom/lib.
Quando conectada por USB, /flash também se enumera como uma unidade de armazenamento em massa USB no host, permitindo que você edite boot.py, main.py e quaisquer outros arquivos diretamente. Ejete a unidade antes de reiniciar a câmera para que o host descarregue suas escritas em cache.
Nota
Como o SO trata a unidade como um dispositivo de bloco passivo, arquivos criados ou modificados por código em execução na câmera não aparecerão até que o host remonte a unidade. Se tanto o SO quanto a câmera escreverem no mesmo sistema de arquivos ao mesmo tempo, o SO vencerá e sobrescreverá as alterações feitas pela câmera. Use o cartão SD para quaisquer dados que o script grave de volta, e remonte antes de ler esses arquivos a partir do host.
Nota
O canal vermelho do LED RGB do usuário pode acender brevemente enquanto o host está lendo ou gravando na unidade de armazenamento em massa USB — isso é um indicador de atividade controlado pelo firmware, não uma falha.
Tamanhos de armazenamento¶
A Nicla Vision vem com:
/flash— sistema de arquivos FAT de 11 MB, leitura/escrita./rom— ROMFS de 4 MB somente leitura, mapeado em memória, usado para fornecer scripts e modelos de ML que se beneficiam do acesso mmap sem cópia (zero-copy).
Indicador de hard fault¶
Se o LED RGB do usuário estiver ciclando rapidamente por todas as cores — rápido o suficiente para que tenda a parecer um LED branco cintilante em vez de tons distintos — o firmware encontrou um hard fault irrecuperável. Regrave o firmware para recuperar; se a regravação não ajudar, a placa pode estar fisicamente danificada.
Bibliotecas de software¶
Consulte o índice da biblioteca para a lista completa de módulos — incluindo quais são exclusivos da build da Nicla Vision.