Arduino Nicla Vision¶
Arduino Nicla Vision 是一块 22.86 × 22.86 mm 的机器视觉开发板,围绕 STMicroelectronics STM32H747AII6 构建——这是一款双核 SoC,将 400 MHz 的 Cortex‑M7 与 200 MHz 的 Cortex‑M4 结合在一起。OpenMV 固件完全运行在 M7 核心上。该板将 MCU 与 GC2145 200 万像素彩色 CMOS 传感器、LSM6DSOX 六轴 IMU、MP34DT06 MEMS 麦克风、VL53L1CB 飞行时间测距仪、Wi‑Fi + Bluetooth LE 5.1 以及电池充电器/电量计配对在一起。
完整的数据手册、照片和尺寸请参见 Arduino Nicla Vision 产品页面。
亮点¶
STMicroelectronics STM32H747AII6 双核 Cortex‑M7(400 MHz)+ Cortex‑M4(200 MHz)。OpenMV 固件仅运行在 M7 核心上。
2 MB 内部闪存 外加 16 MB 外部 QSPI 闪存(用于应用程序 + ROMFS)。
1 MB 内部 SRAM。
硬件 JPEG 编码器/解码器。
GC2145 200 万像素彩色 CMOS 传感器。
板载 IMU(LSM6DSOX 加速度计 + 陀螺仪)、MEMS 麦克风(MP34DT06JTR)以及 VL53L1CB 飞行时间测距仪(最远约 4 m)。
Wi‑Fi b/g/n(2.4 GHz)+ Bluetooth LE 5.1,通过 Murata 1DX(CYW4343W)模块实现——经由板载 U.FL 连接器 连接到随附的天线。
高速 USB(480 Mb/s),通过外部 ULPI PHY(USB3320C)经由 Micro USB 提供。
Arduino 边缘排针上的 13 个用户 I/O 引脚——四个数字 LPIO(
D0–D3)、三个 1.8 V 模拟输入(A0–A2)、SCL/SDAI²C 引脚对,以及SCLK/CIPO/COPI/CSSPI 四元组。电池支持——背面的 Li‑Po 连接器、BQ 系列充电器,以及通过内部 PMIC 总线连接的 MAX17262 电量计。
背面的 5 针 ESLOV 连接器,用于免焊 I²C 扩展。
警告
用户 数字引脚默认为 3.3 V,但通过软件可编程的电平转换器(VDDIO_EXT)路由,可重新配置为 1.8 V。模拟引脚(A0–A2)仅为 1.8 V——它们绕过电平转换器,直接连接到 MCU。向 A0–A2 施加 3.3 V 会损坏 SoC。
引脚分布¶
引脚参考¶
Arduino 边缘排针(J1 和 J2)上暴露了十三个用户引脚。额外的调试、恢复和 PMIC 信号被路由到板背面的测试焊盘。
引脚名称 |
参考电平 |
功能 |
|---|---|---|
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 channel 4 (J1‑8) |
A1 |
1.8 V |
ADC2 channel 2 (J1‑7) |
A2 |
1.8 V |
ADC3 channel 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 |
拉至 GND(或按下板载开关)以复位开发板 |
LED_RED |
3.3 V |
RGB LED 红色通道(低电平有效) |
LED_GREEN |
3.3 V |
RGB LED 绿色通道(低电平有效) |
LED_BLUE |
3.3 V |
RGB LED 蓝色通道(低电平有效) |
备注
D0–D3 和 SCLK/CIPO/COPI/CS 位于 TXB0108 双向电平转换器之后——该器件仅支持 推挽式 GPIO 驱动,因此开漏总线流量(例如这些引脚上的位翻转 1‑Wire 或 I²C)将无法工作。
SCL/SDA 位于另一个 NTS0304 转换器之后,它同时支持 推挽和开漏 驱动,这就是 I²C 1 在那里能正常工作的原因。
两个转换器都以 VDDIO_EXT(板载 PMIC 默认提供 3.3 V)为参考,与直接 GPIO 相比,它们的驱动强度受到限制——它们是为信号电平而非功率负载设计的。
电源引脚¶
边缘排针引脚:
VIN(J2‑9)——主 3.6 – 5 V 系统电源轨。PMIC 在此处获取输入。
VDDIO_EXT(J2‑7)——电平转换器电源轨的 输出,为 1.8 V 或 3.3 V(默认 3.3 V)。使用它为连接到 LPIO/SPI/I²C 引脚的外部 1.8 V 或 3.3 V 外设供电,使它们与排针使用相同的逻辑电平。
VBAT(J3‑2)——Li‑Po 电池输入。板载 PMIC 从 VIN 为电芯充电,并通过电量计报告充电状态。
NTC(J3‑1)——可选的 Li‑Po 热敏电阻输入。
GND(J2‑6)——公共地。
NC(J2‑8)——无连接。
板背面的测试焊盘:
+3V3——主 3.3 V 电源轨。
D_P / D_N——USB 高速数据对(PHY 之后)。
USB 和 ESLOV 连接器都通过一对 LM66100 理想二极管(每个电源一个)馈入 VIN,因此任一电源都可以单独为开发板供电,且两者绝不会相互倒灌。如果你在 J2‑9 上从外部驱动 VIN,那将优先生效——一旦外部电源轨升得更高,二极管便不再从 USB / ESLOV 导通。
因此,开发板可以通过以下任意路径供电:
Micro USB——5 V 通过 USB 侧理想二极管进入 VIN。
ESLOV 连接器——J5 的
VESLOV引脚上最高 5 V,通过 ESLOV 侧理想二极管路由进 VIN(参见 ESLOV 连接器)。VIN 引脚(J2‑9)——直接驱动一个稳压的 3.6 – 5 V 电源。
Li‑Po 电池——连接到背面的 J4 电池连接器,或 连接到 J3 / J2‑6 上的 VBAT/GND/NTC 焊盘。请勿同时连接两块电池。
ESLOV 连接器¶
板背面的 J5 是一个 5 针 Molex 免焊 ESLOV 连接器:
引脚 |
名称 |
功能 |
|---|---|---|
J5‑1 |
VESLOV |
电源输入(≤ 5 V)——通过 LM66100 理想二极管与 |
J5‑2 |
INT |
|
J5‑3 |
SCL_EXT |
与 J2 的 |
J5‑4 |
SDA_EXT |
与 J2 的 |
J5‑5 |
GND |
公共地 |
ESLOV 的 SCL_EXT/SDA_EXT 与 J2 的 SCL/SDA 是同一组引脚——同一条 I²C 1 总线暴露在两个连接器上。
小技巧
使用 电池续航估算器 来推算 Nicla Vision 在给定的活跃/深度睡眠占空比下,靠电池能运行多久。
恢复和调试引脚¶
RESET——既有板顶部的瞬时开关,也有一个连接到 SoC NRST 线的焊盘(J3‑4 / 测试焊盘 P5)。拉至 GND 以复位。
Nicla Vision 使用 Arduino 标准的 双击复位 来进入 Arduino 的引导加载程序——快速按两次复位按钮,开发板便会枚举为 DFU 设备。OpenMV IDE 使用此模式来重新刷写固件。
STM32 SWD 信号通过两个 J2 排针之间的一排测试焊盘暴露在板背面。将一个 2.54 mm(100 mil) 排针焊接到这些焊盘上,即可连接 ST‑LINK 或 J‑Link 适配器:
P1 / P2——PF0(SDA)和 PF1(SCL)上的内部 PMIC I²C 总线。这在 Nicla Vision 上是
machine.I2C(2),承载 PMIC、电量计和 ToF 的流量。P3——TMS / SWDIO (PA13)
P4——TCK / SWCLK (PA14)
P5——NRST
P6——TDO / SWO (PB3)
P7——+1V8 电源轨(SoC 的 I/O 供电——也是调试适配器的正确参考电平)。
P8——
VOTP_PMIC——仅用于出厂编程。必须保持悬空。
所有调试信号均以 1.8 V 为参考——本板上 STM32H747 的 I/O 环路由 +1V8 电源轨供电。连接前请将调试适配器设置为 1.8 V 逻辑电平。
板载外设¶
LED¶
Nicla Vision 有一个用户 RGB LED,可通过 machine.LED 用软件控制:
from machine import LED
LED("LED_RED").on()
LED("LED_GREEN").on()
LED("LED_BLUE").on()
板侧另有一个 DL2 CHARGE LED,直接连接到 PMIC 的 CHGB 输出——当从 USB / ESLOV / VIN 为 Li‑Po 电池充电时它会亮起,且不可由用户控制。
摄像头传感器¶
GC2145 通过 csi --- 摄像头传感器 模块驱动:
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()
当你请求较小的帧尺寸时,GC2145 驱动会从传感器裁剪出一个成比例缩小的读出窗口——默认情况下,读出到输出的降采样比上限为 3 倍,以保持帧率。csi.IOCTL_SET_FOV_WIDE 将该上限提升到 5 倍,这意味着在以小分辨率流式传输时,驱动会从传感器更宽的区域读取。其结果是在小帧尺寸下获得明显更宽的视场,但代价是损失一些吞吐量:
cam.ioctl(csi.IOCTL_SET_FOV_WIDE, True)
cam.ioctl(csi.IOCTL_GET_FOV_WIDE) # returns the current setting
M4 核心¶
Cortex‑M4 核心通过 openamp 暴露出来用于处理器间通信。OpenMV 固件仅运行在 M7 上;M4 没有自己的 MicroPython 运行时,因此使用它意味着要构建一个单独的 C 固件镜像,并通过 openamp.RemoteProc 从文件系统加载它。一个实现了虚拟 UART 端点的预编译示例固件可在 openamp_vuart 仓库中获取——按照其 README 构建 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)
实际上,最好将这一支持视为 openamp 接口的演示,而非一个可用的双核平台——M4 无法独立于 M7 复位,因此停止 M4 会强制整个系统重启。
麦克风¶
板载 MP34DT06JTR PDM 麦克风通过 audio --- 音频模块 经由 STM32 的 DFSDM 外设捕获。每个缓冲区以有符号 16 位 PCM bytearray 的形式到达,可直接送入 ulab/numpy 进行 DSP——例如,一个简单的响度检测器:
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¶
板载 LSM6DSOX 加速度计 + 陀螺仪通过 imu --- 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)
IMU 连接到一条专用的内部 SPI 总线(SPI5),因此它不会与引出到排针上的用户 SPI4 争用。
飞行时间测距仪¶
板载的 ST VL53L1CB 飞行时间测距仪位于内部 PMIC I²C 总线(I²C 2)上。使用冻结的 vl53l1x --- VL53L1X ToF 距离传感器驱动 驱动来获取最远约 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)
电池电量计¶
Maxim MAX17262 ModelGauge m5 电量计跟踪 Li‑Po 电池的电压、电流、温度和充电状态。它位于 I²C 2 上,地址为 0x36。
MAX17262 具有 内部 电流检测功能,因此电流寄存器直接以微安为单位读出,无需应用任何外部 Rsense 系数。读取电量计是无害的——虽然没有随附驱动,但可以直接读取 MAX17262 数据手册 中记录的寄存器:
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 为有符号二进制补码:充电时为正,放电时为负。TTE 仅在电流为负时有意义;TTF 仅在电流为正时有意义。
电源管理 IC¶
NXP MC34PF1550A0EP PMIC 处理 Nicla Vision 上的每一个稳压器——+3V3 主电源轨、+1V8 SoC 核心/I/O 电源轨、连接电平转换器的 VDDIO_EXT,以及 Li‑Po 充电器。它位于 I²C 2 上,地址为 0x08。
警告
读取 PMIC 寄存器没有问题;写入它们则很危险。 错误配置降压稳压器或充电器设置可能会永久损坏开发板、电池,或两者。除非你完全清楚自己在做什么,否则请将 PMIC 视为只读。
PMIC 能告诉你而电量计无法提供的最有用信息是 充电器状态机——开发板当前是依靠 USB / ESLOV / VIN 运行、Li‑Po 处于充电周期的哪个阶段,以及充电器是否处于热保护或看门狗故障状态。充电器寄存器位于 PF1550 主 I²C 地址空间中偏移 0x80 处(参见 PF1550 数据手册 的 §22.2),因此例如位于充电器地址 0x04 的 CHG_INT_OK 应从 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)
数据手册中其他值得一看的只读寄存器(均位于充电器偏移 0x80 处):0x80 CHG_INT(锁存的充电器中断——故障标志)、0x86 VBUS_SNS(包含 OVLO / UVLO / DPM 的多位 VBUS 状态),以及 0x88 BATT_SNS(电池存在与过流状态)。
Wi‑Fi¶
板载 Murata 1DX(CYW4343W)通过 network --- 网络配置 暴露为一个 station 接口。在启用射频之前,请将随附的天线连接到板载 U.FL 连接器:
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¶
同一颗 Murata 1DX 还暴露了 Bluetooth LE 5.1。使用 aioble --- 异步 BLE 实现 asyncio 友好的 BLE——例如,作为外设进行广播并等待中心设备连接:
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())
总线参考¶
GPIO¶
使用 machine.Pin 来读取或驱动任何丝印引脚。输出为 3.3 V CMOS(默认 VDDIO_EXT),且电平转换器将每个引脚的驱动强度限制在几毫安——它们是为信号电平而非功率负载设计的。
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())
任何输入引脚也可以在边沿跳变时触发中断:
def handler(pin):
print("triggered:", pin)
Pin("D1", Pin.IN, Pin.PULL_UP).irq(
handler, Pin.IRQ_FALLING | Pin.IRQ_RISING,
)
UART¶
总线 |
TX |
RX |
|---|---|---|
UART4 |
SDA |
SCL |
from machine import UART
uart = UART(4, baudrate=115200)
uart.write("hello")
uart.read(5)
备注
UART4 与 I²C 1 共享引脚——同样的 SDA/SCL 焊盘承载这两条总线。在这些引脚上请二选一:UART 或 I²C,不能同时使用。
D1/D2 的丝印也标为 UART_TX/UART_RX,但在本固件中,这些引脚被路由到 LPUART1,而非 machine.UART。machine.UART(1) 本身保留给片上 Bluetooth 控制器,无法在排针上访问。
I²C¶
总线 |
SCL |
SDA |
|---|---|---|
I2C1 |
SCL |
SDA |
from machine import I2C
i2c = I2C(1, freq=400_000)
i2c.scan()
i2c.writeto(0x76, b"hi")
J2 上的 SCL/SDA 焊盘和 ESLOV 连接器的 SCL_EXT/SDA_EXT 引脚落在同一条 I²C 1 总线上——ESLOV 引脚分布参见上文的 ESLOV 连接器。
同样的硬件也可以通过 machine.I2CTarget 用于目标(从机)模式,从而向另一个 I²C 控制器暴露一块内存区域:
from machine import I2CTarget
buf = bytearray(32)
target = I2CTarget(1, addr=0x42, mem=buf)
SPI¶
总线 |
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¶
Nicla Vision 在 A0、A1 和 A2 上暴露了三个 12 位 ADC 通道。三者均以 1.8 V 为参考——read_u16 在引脚上 0–1.8 V 范围内返回 0–65535:
from machine import ADC
import time
adc = ADC("A0")
while True:
voltage = adc.read_u16() * 1.8 / 65535
print(voltage)
time.sleep_ms(100)
警告
Nicla Vision 的 ADC 输入以 1.8 V 为参考(并且 SoC 前没有电平转换器)。施加 3.3 V 信号会使转换器饱和,并可能损坏引脚——请在外部将较高电压分压降低。
PWM¶
引脚 |
定时器 / 通道 |
|---|---|
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 |
通过 machine.PWM 来驱动它们中的任意一个:
from machine import Pin, PWM
pwm = PWM(Pin("D1"), freq=1_000, duty_u16=32768)
备注
若干引脚共享 TIM1 通道:
TIM1 CH2 位于
D1和CS上。TIM1 CH3 位于
D2和CIPO上;SCLK输出同一通道的反相互补信号(TIM1 CH3N)。TIM1 CH4 仅位于
COPI上。
每个定时器通道只挑选一个使用者。当 machine.SPI(4) 正在使用 SPI 四元组引脚(SCLK/CIPO/COPI/CS)时,它们也无法被 PWM 驱动。
软件位翻转总线¶
如果你需要额外的总线,machine.SoftI2C 和 machine.SoftSPI 可在任何 GPIO 上工作。
热成像传感器(板外)¶
固件包含 fir --- 热成像传感器驱动(fir == 远红外) 驱动,用于外部接线的热成像仪:
MLX90621——16 × 4 红外阵列
MLX90640——32 × 24 红外阵列
MLX90641——16 × 12 红外阵列
AMG8833——8 × 8 红外阵列
将模块接到开发板的 I²C 总线,并用 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())
fir 驱动只通过 I²C 1 与传感器通信——请将模块接到丝印 SCL / SDA 焊盘上。
计时¶
time¶
time 模块涵盖阻塞延时、单调滴答计数和经过时间测量:
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)
虚拟定时器¶
machine.Timer 可在不占用硬件定时器槽位的情况下调度周期性或单次回调。将 -1 作为 id 传入即可使用虚拟(软件)定时器:
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"))
周期值以毫秒为单位。调用 deinit() 以停止并释放该槽位。
实时时钟¶
machine.RTC 可在多次复位之间保持挂钟时间:
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())
看门狗¶
machine.WDT 在应用程序挂起时复位开发板。一旦启动便无法停止或重新配置——请在主循环中定期喂狗:
from machine import WDT
wdt = WDT(timeout=5_000) # 5 second window
while True:
# ...do work...
wdt.feed()
启动与运行时信息¶
固件更新(DFU)¶
Nicla Vision 使用 Arduino 标准的 双击复位 来进入 Arduino 的引导加载程序。快速按两次复位按钮——开发板便会通过 USB 重新枚举为 DFU 设备,OpenMV IDE 即可刷写新的固件镜像。
正在运行的脚本可以通过调用 machine.bootloader() 按需重新进入引导加载程序:
import machine
machine.bootloader()
文件系统与启动顺序¶
Nicla Vision 固件在启动时最多挂载两个文件系统:
内部闪存——始终挂载在
/flash。默认保存main.py和README.txt;在首次启动时创建。ROMFS——只读的内存映射文件系统,位于
/rom,由 MicroPython 在启动时自动挂载。
挂载完成后,工作目录被设为 /flash。随后解释器从该目录运行脚本:
boot.py在 每次 软复位时执行(冷启动、从 REPL 按Ctrl‑D,或正在运行的脚本返回时)。main.py仅在冷启动时 执行,紧接在boot.py之后。后续的软复位会重新运行boot.py,但会直接进入 REPL——要重新运行main.py,你必须完全复位开发板。
刚刷写的开发板上随附的默认 main.py 只是闪烁用户 RGB LED 的 蓝色 通道作为心跳信号(两次短脉冲,短间隔),这样你无需连接任何主机就能判断固件是否干净地启动了。
sys.path 被扩展为包含两个文件系统及其 lib/ 子目录,因此可导入的模块可以放在 /flash/lib 或 /rom/lib 中。
当通过 USB 连接时,/flash 还会在主机上枚举为一个 USB 大容量存储驱动器,让你可以直接编辑 boot.py、main.py 及任何其他文件。在复位摄像头前请弹出该驱动器,以便主机刷新其缓存的写入。
备注
由于操作系统将该驱动器视为被动块设备,由摄像头上运行的代码创建或修改的文件在主机重新挂载该驱动器之前不会显示出来。如果操作系统和摄像头同时写入同一个文件系统,操作系统将取胜并覆盖摄像头所做的更改。脚本要写回的任何数据请使用 SD 卡,并在从主机读取这些文件之前重新挂载。
备注
当主机正在从 USB 大容量存储驱动器读取或写入时,用户 RGB LED 的 红色 通道可能会短暂亮起——这是固件驱动的活动指示,并非故障。
存储容量¶
Nicla Vision 出厂时配有:
/flash——11 MB FAT 文件系统,可读写。/rom——4 MB 只读的内存映射 ROMFS,用于存放那些受益于零拷贝 mmap 访问的脚本和 ML 模型。
硬故障指示¶
如果用户 RGB LED 正在快速循环遍历所有颜色——快到看上去更像是一个 闪烁的白色 LED 而非分明的色调——则说明固件遇到了无法恢复的硬故障。重新刷写固件以恢复;如果重新刷写也无济于事,则开发板可能已物理损坏。
软件库¶
完整的模块列表请参见 库索引——包括哪些模块是 Nicla Vision 构建版本所独有的。