Arduino Nicla Vision¶
Die Arduino Nicla Vision ist ein 22,86 × 22,86 mm großes Board für maschinelles Sehen, das um den STMicroelectronics STM32H747AII6 herum aufgebaut ist – ein Dual-Core-SoC, das einen Cortex-M7 mit 400 MHz mit einem Cortex-M4 mit 200 MHz kombiniert. Die OpenMV-Firmware läuft vollständig auf dem M7-Kern. Das Board kombiniert den MCU mit dem GC2145 2-MP-Farb-CMOS-Sensor, einer LSM6DSOX 6-Achsen-IMU, einem MP34DT06 MEMS-Mikrofon, einem VL53L1CB Time-of-Flight-Entfernungsmesser, Wi-Fi + Bluetooth LE 5.1 sowie einem Akkuladegerät / Fuel Gauge.
Vollständiges Datenblatt, Fotos und Abmessungen finden Sie auf der Arduino Nicla Vision Produktseite.
Höhepunkte¶
STMicroelectronics STM32H747AII6 Dual Cortex-M7 (400 MHz) + Cortex-M4 (200 MHz). Die OpenMV-Firmware läuft nur auf dem M7-Kern.
2 MB internes Flash plus 16 MB externes QSPI-Flash (verwendet für die Anwendung + ROMFS).
1 MB internes SRAM.
Hardware-JPEG-Encoder/Decoder.
GC2145 2-MP-Farb-CMOS-Sensor.
Onboard-IMU (LSM6DSOX Beschleunigungssensor + Gyroskop), MEMS-Mikrofon (MP34DT06JTR) und VL53L1CB Time-of-Flight-Entfernungsmesser (bis zu ~4 m).
Wi-Fi b/g/n (2,4 GHz) + Bluetooth LE 5.1 über das Murata 1DX (CYW4343W) Modul – verbindet sich über einen Onboard-U.FL-Anschluss mit der mitgelieferten Antenne.
High-Speed USB (480 Mb/s) über Micro USB durch eine externe ULPI-PHY (USB3320C).
13 Benutzer-I/O-Pins an den Arduino-Randsteckleisten – vier digitale LPIOs (
D0–D3), drei 1,8-V-Analogeingänge (A0–A2), dasSCL/SDAI²C-Paar und dasSCLK/CIPO/COPI/CSSPI-Quartett.Akku-Unterstützung – Li-Po-Anschluss auf der Rückseite, BQ-artiges Ladegerät und MAX17262 Fuel Gauge über den internen PMIC-Bus.
5-poliger ESLOV-Anschluss auf der Rückseite für lötfreie I²C-Erweiterung.
Warnung
Die digitalen Benutzer-Pins sind standardmäßig 3,3 V, werden jedoch über softwareprogrammierbare Pegelwandler (VDDIO_EXT) geführt, die auf 1,8 V umkonfiguriert werden können. Die Analogpins (A0–A2) sind ausschließlich 1,8 V – sie umgehen die Pegelwandler und sind direkt mit dem MCU verbunden. Das Anlegen von 3,3 V an A0–A2 beschädigt das SoC.
Pinbelegung¶
Pin-Referenz¶
Dreizehn Benutzerpins werden an den Arduino-Randsteckleisten (J1 und J2) bereitgestellt. Zusätzliche Debug-, Wiederherstellungs- und PMIC-Signale werden zu Testpads auf der Rückseite des Boards geführt.
Pin-Name |
Referenz |
Funktion |
|---|---|---|
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 Kanal 4 (J1-8) |
A1 |
1,8 V |
ADC2 Kanal 2 (J1-7) |
A2 |
1,8 V |
ADC3 Kanal 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 |
auf GND ziehen (oder den Onboard-Schalter drücken), um das Board zurückzusetzen |
LED_RED |
3,3 V |
RGB-LED Rotkanal (Low-aktiv) |
LED_GREEN |
3,3 V |
RGB-LED Grünkanal (Low-aktiv) |
LED_BLUE |
3,3 V |
RGB-LED Blaukanal (Low-aktiv) |
Bemerkung
D0–D3 und SCLK/CIPO/COPI/CS befinden sich hinter dem TXB0108 bidirektionalen Pegelwandler – dieser Baustein unterstützt nur Push-Pull-GPIO-Ansteuerung, sodass Open-Drain-Busverkehr (z. B. ein bit-banged 1-Wire oder I²C an diesen Pins) nicht funktioniert.
SCL/SDA befinden sich hinter einem separaten NTS0304-Wandler, der sowohl Push-Pull- als auch Open-Drain-Ansteuerung unterstützt, weshalb I²C 1 dort funktioniert.
Beide Wandler sind auf VDDIO_EXT referenziert (standardmäßig 3,3 V vom Onboard-PMIC), und ihre Treiberstärke ist im Vergleich zu einem direkten GPIO begrenzt – sie sind für Signalpegel und nicht für Leistungslasten ausgelegt.
Stromversorgungspins¶
Pins der Randsteckleiste:
VIN (J2-9) – Haupt-Systemschiene mit 3,6 – 5 V. Der PMIC bezieht hier seinen Eingang.
VDDIO_EXT (J2-7) – Ausgang der Pegelwandler-Schiene, 1,8 V oder 3,3 V (standardmäßig 3,3 V). Verwenden Sie diese, um externe 1,8-V- oder 3,3-V-Peripheriegeräte zu versorgen, die an die LPIO/SPI/I²C-Pins angeschlossen sind, damit sie denselben Logikpegel wie die Steckleisten sprechen.
VBAT (J3-2) – Li-Po-Akkueingang. Der Onboard-PMIC lädt die Zelle aus VIN und meldet den Ladezustand über das Fuel Gauge.
NTC (J3-1) – optionaler Li-Po-Thermistoreingang.
GND (J2-6) – gemeinsame Masse.
NC (J2-8) – nicht angeschlossen.
Testpads auf der Rückseite des Boards:
+3V3 – Haupt-3,3-V-Schiene.
D_P / D_N – USB-High-Speed-Datenpaar (nach PHY).
USB und der ESLOV-Anschluss speisen beide VIN über ein Paar LM66100 Ideal-Dioden (eine pro Quelle), sodass jede Versorgung das Board eigenständig betreiben kann und die beiden sich niemals gegenseitig rückspeisen. Wenn Sie VIN extern an J2-9 ansteuern, hat das Vorrang – die Dioden hören einfach auf, von USB / ESLOV zu leiten, sobald die externe Schiene höher ansteigt.
Das Board kann daher über jeden dieser Pfade mit Strom versorgt werden:
Micro USB – 5 V in VIN über die USB-seitige Ideal-Diode.
ESLOV-Anschluss – bis zu 5 V am
VESLOV-Pin von J5, über die ESLOV-seitige Ideal-Diode in VIN geführt (siehe ESLOV-Anschluss).VIN-Pin (J2-9) – eine geregelte 3,6 – 5 V Versorgung direkt anlegen.
Li-Po-Akku – an den J4-Akkuanschluss auf der Rückseite oder an die VBAT/GND/NTC-Pads an J3 / J2-6 anschließen. Schließen Sie nicht zwei Akkus gleichzeitig an.
ESLOV-Anschluss¶
J5 auf der Rückseite des Boards ist ein 5-poliger lötfreier ESLOV-Anschluss von Molex:
Pin |
Name |
Funktion |
|---|---|---|
J5-1 |
VESLOV |
Stromeingang (≤ 5 V) – über eine LM66100 Ideal-Diode mit |
J5-2 |
INT |
externer Interrupt-Eingang an |
J5-3 |
SCL_EXT |
gemeinsam mit dem J2- |
J5-4 |
SDA_EXT |
gemeinsam mit dem J2- |
J5-5 |
GND |
gemeinsame Masse |
ESLOVs SCL_EXT/SDA_EXT und J2s SCL/SDA sind dieselben Pins – ein I²C-1-Bus, der an zwei Anschlüssen bereitgestellt wird.
Tipp
Verwenden Sie den Akkulaufzeit-Schätzer, um zu modellieren, wie lange die Nicla Vision bei einem bestimmten Aktiv-/Deep-Sleep-Tastverhältnis mit einem Akku läuft.
Wiederherstellungs- und Debug-Pins¶
RESET – sowohl ein Taster auf der Oberseite des Boards als auch ein Pad (J3-4 / Testpad P5), das mit der NRST-Leitung des SoC verbunden ist. Auf GND ziehen, um zurückzusetzen.
Die Nicla Vision verwendet Arduinos Standard-Doppeltipp-Reset, um in Arduinos Bootloader zu gelangen – drücken Sie den Reset-Taster zweimal schnell hintereinander, und das Board meldet sich als DFU-Gerät an. OpenMV IDE nutzt diesen Modus, um die Firmware neu zu flashen.
Die STM32-SWD-Signale werden auf der Rückseite des Boards über eine Reihe von Testpads zwischen den beiden J2-Steckleisten bereitgestellt. Löten Sie eine 2,54 mm (100-mil) Steckleiste in diese ein, um einen ST-LINK- oder J-Link-Adapter anzuschließen:
P1 / P2 – interner PMIC I²C-Bus an PF0 (SDA) und PF1 (SCL). Dies ist
machine.I2C(2)auf der Nicla Vision und führt den PMIC-, Fuel-Gauge- und ToF-Verkehr.P3 – TMS / SWDIO (PA13)
P4 – TCK / SWCLK (PA14)
P5 – NRST
P6 – TDO / SWO (PB3)
P7 – +1V8-Schiene (die I/O-Versorgung des SoC – auch die richtige Referenz für den Debug-Adapter).
P8 –
VOTP_PMIC– nur für die Werksprogrammierung. Muss unverbunden bleiben.
Alle Debug-Signale sind auf 1,8 V referenziert – der I/O-Ring des STM32H747 auf diesem Board läuft von der +1V8-Schiene. Stellen Sie Ihren Debug-Adapter auf 1,8-V-Logik ein, bevor Sie ihn anschließen.
Onboard-Peripheriegeräte¶
LEDs¶
Die Nicla Vision hat eine einzelne RGB-Benutzer-LED, die softwaregesteuert über machine.LED ansteuerbar ist:
from machine import LED
LED("LED_RED").on()
LED("LED_GREEN").on()
LED("LED_BLUE").on()
Eine separate DL2 CHARGE-LED an der Seite des Boards ist direkt mit dem CHGB-Ausgang des PMIC verdrahtet – sie leuchtet, während ein Li-Po-Akku über USB / ESLOV / VIN geladen wird, und ist nicht benutzersteuerbar.
Kamerasensor¶
Der GC2145 wird über das csi — Kamerasensoren-Modul angesteuert:
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()
Wenn Sie eine kleine Framegröße anfordern, schneidet der GC2145-Treiber ein proportional kleines Auslesefenster aus dem Sensor aus – standardmäßig ist das Herunterskalierungsverhältnis von Auslesung zu Ausgabe auf 3x begrenzt, um die Bildrate hochzuhalten. csi.IOCTL_SET_FOV_WIDE erhöht diese Grenze auf 5x, was bedeutet, dass der Treiber bei kleinen Auflösungen aus einem breiteren Bereich des Sensors liest. Das Ergebnis ist ein merklich breiteres Sichtfeld bei kleinen Framegrößen, auf Kosten von etwas Durchsatz:
cam.ioctl(csi.IOCTL_SET_FOV_WIDE, True)
cam.ioctl(csi.IOCTL_GET_FOV_WIDE) # returns the current setting
M4-Kern¶
Der Cortex-M4-Kern wird über openamp für die Inter-Prozessor-Kommunikation bereitgestellt. Die OpenMV-Firmware läuft nur auf dem M7; der M4 hat keine eigene MicroPython-Laufzeit, sodass seine Nutzung bedeutet, ein separates C-Firmware-Image zu erstellen und es über openamp.RemoteProc aus dem Dateisystem zu laden. Vorgefertigte Beispiel-Firmware, die einen virtuellen UART-Endpunkt implementiert, ist im Repository openamp_vuart verfügbar – folgen Sie dessen README, um vuart.elf zu erstellen:
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 der Praxis sollte diese Unterstützung am besten als Demonstration der openamp-Schnittstelle betrachtet werden und nicht als funktionierende Dual-Core-Plattform – der M4 kann nicht unabhängig vom M7 zurückgesetzt werden, sodass das Stoppen des M4 einen vollständigen Systemneustart erzwingt.
Mikrofon¶
Das Onboard-MP34DT06JTR-PDM-Mikrofon wird über audio — Audio-Modul über das DFSDM-Peripheriegerät des STM32 erfasst. Jeder Puffer kommt als vorzeichenbehaftetes 16-Bit-PCM-bytearray an, bereit zur Einspeisung in ulab/numpy für DSP – zum Beispiel ein einfacher Lautstärkedetektor:
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¶
Der Onboard-LSM6DSOX-Beschleunigungssensor + Gyroskop wird über imu — IMU-Sensor bereitgestellt:
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)
Die IMU ist mit einem dedizierten internen SPI-Bus (SPI5) verdrahtet, sodass sie nicht mit dem an den Steckleisten herausgeführten Benutzer-SPI4 in Konflikt gerät.
Time-of-Flight-Entfernungsmesser¶
Der Onboard-ST-VL53L1CB-Time-of-Flight-Entfernungsmesser sitzt am internen PMIC-I²C-Bus (I²C 2). Verwenden Sie den eingefrorenen vl53l1x — VL53L1X ToF-Distanzsensor-Treiber-Treiber, um Abstandsmessungen bis zu ~4 m zu erhalten:
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)
Akku-Fuel-Gauge¶
Das Maxim MAX17262 ModelGauge m5 Fuel Gauge erfasst Spannung, Strom, Temperatur und Ladezustand des Li-Po-Akkus. Es sitzt an I²C 2 unter der Adresse 0x36.
Der MAX17262 verfügt über interne Strommessung, sodass das Stromregister direkt in Mikroampere ausgelesen wird, ohne einen externen Rsense-Faktor anwenden zu müssen. Das Auslesen des Fuel Gauge ist harmlos – es wird kein Treiber mitgeliefert, aber die im MAX17262-Datenblatt dokumentierten Register können direkt ausgelesen werden:
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 ist im vorzeichenbehafteten Zweierkomplement: positiv beim Laden, negativ beim Entladen. TTE ist nur aussagekräftig, wenn der Strom negativ ist; TTF nur, wenn der Strom positiv ist.
Power-Management-IC¶
Der NXP MC34PF1550A0EP PMIC verwaltet jeden Regler auf der Nicla Vision – die +3V3-Hauptschiene, die +1V8 SoC-Kern-/I/O-Schiene, VDDIO_EXT zu den Pegelwandlern und das Li-Po-Ladegerät. Er sitzt an I²C 2 unter der Adresse 0x08.
Warnung
Das Lesen von PMIC-Registern ist in Ordnung; das Schreiben in sie ist gefährlich. Eine fehlerhafte Konfiguration eines Abwärtsreglers oder einer Ladeeinstellung kann das Board, den Akku oder beides dauerhaft beschädigen. Behandeln Sie den PMIC als schreibgeschützt, es sei denn, Sie wissen genau, was Sie tun.
Das Nützlichste, was Ihnen der PMIC mitteilt und das Fuel Gauge nicht kann, ist die Lade-Zustandsmaschine – ob das Board derzeit über USB / ESLOV / VIN läuft, in welcher Phase des Ladezyklus sich der Li-Po befindet und ob das Ladegerät in einem thermischen oder Watchdog-Fehler ist. Die Ladegerät-Register liegen mit einem Offset von 0x80 im Haupt-I²C-Adressraum des PF1550 (siehe §22.2 des PF1550-Datenblatts), sodass beispielsweise CHG_INT_OK an der Ladegerät-Adresse 0x04 aus dem PMIC-Register 0x84 gelesen wird:
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)
Weitere schreibgeschützte Register, die im Datenblatt einen Blick wert sind (alle mit Ladegerät-Offset 0x80): 0x80 CHG_INT (gelatchte Ladegerät-Interrupts – Fehlerflags), 0x86 VBUS_SNS (der Multi-Bit-VBUS-Zustand einschließlich OVLO / UVLO / DPM) und 0x88 BATT_SNS (Akku-Vorhandensein und Überstromzustand).
Wi-Fi¶
Das Onboard-Murata 1DX (CYW4343W) wird über network — Netzwerkkonfiguration als Station-Schnittstelle bereitgestellt. Schließen Sie die mitgelieferte Antenne an den Onboard-U.FL-Anschluss an, bevor Sie das Funkmodul hochfahren:
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¶
Das gleiche Murata 1DX stellt auch Bluetooth LE 5.1 bereit. Verwenden Sie aioble — Async BLE für asyncio-freundliches BLE – zum Beispiel als Peripheriegerät werben und warten, bis sich ein Central verbindet:
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())
Bus-Referenz¶
GPIO¶
Verwenden Sie machine.Pin, um einen der bedruckten Pins zu lesen oder anzusteuern. Ausgänge sind 3,3 V CMOS (standardmäßig VDDIO_EXT), und die Pegelwandler begrenzen die Treiberstärke pro Pin auf wenige Milliampere – sie sind für Signalpegel und nicht für Leistungslasten ausgelegt.
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())
Jeder Eingangspin kann auch einen Interrupt bei Flankenwechseln auslösen:
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)
Bemerkung
UART4 teilt sich seine Pins mit I²C 1 – dieselben SDA/SCL-Pads führen beide Busse. Wählen Sie an diesen Pins UART oder I²C, nicht beides.
Der D1/D2-Aufdruck liest sich auch als UART_TX/UART_RX, aber in dieser Firmware sind diese Pins zu LPUART1 geführt, nicht zu machine.UART. machine.UART(1) selbst ist für den On-Chip-Bluetooth-Controller reserviert und an den Steckleisten nicht zugänglich.
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")
Die SCL/SDA-Pads an J2 und die SCL_EXT/SDA_EXT-Pins des ESLOV-Anschlusses landen auf demselben I²C-1-Bus – siehe ESLOV-Anschluss oben für die ESLOV-Pinbelegung.
Dieselbe Hardware kann auch im Target-(Slave-)Modus über machine.I2CTarget verwendet werden, um einer anderen I²C-Steuerung einen Speicherbereich bereitzustellen:
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¶
Die Nicla Vision stellt drei 12-Bit-ADC-Kanäle an A0, A1 und A2 bereit. Alle drei sind auf 1,8 V referenziert – read_u16 gibt 0–65535 über 0–1,8 V am Pin zurück:
from machine import ADC
import time
adc = ADC("A0")
while True:
voltage = adc.read_u16() * 1.8 / 65535
print(voltage)
time.sleep_ms(100)
Warnung
Die ADC-Eingänge der Nicla Vision sind auf 1,8 V referenziert (und haben keinen Pegelwandler vor dem SoC). Das Anlegen eines 3,3-V-Signals sättigt den Wandler und kann den Pin beschädigen – teilen Sie höhere Spannungen extern herunter.
PWM¶
Pin |
Timer / Kanal |
|---|---|
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 |
Steuern Sie einen davon über machine.PWM an:
from machine import Pin, PWM
pwm = PWM(Pin("D1"), freq=1_000, duty_u16=32768)
Bemerkung
Mehrere Pins teilen sich TIM1-Kanäle:
TIM1 CH2 ist an
D1undCS.TIM1 CH3 ist an
D2undCIPO;SCLKgibt das invertierte Komplement (TIM1 CH3N) desselben Kanals aus.TIM1 CH4 ist allein an
COPI.
Wählen Sie einen Verbraucher pro Timer-Kanal. Die SPI-Quartett-Pins (SCLK/CIPO/COPI/CS) können außerdem nicht PWM-angesteuert werden, während machine.SPI(4) sie verwendet.
Software-bit-banged Busse¶
machine.SoftI2C und machine.SoftSPI funktionieren an jedem GPIO, falls Sie einen zusätzlichen Bus benötigen.
Thermalsensor (extern)¶
Die Firmware enthält den fir — Wärmesensortreiber (fir == far infrared)-Treiber für extern verdrahtete Wärmebildkameras:
MLX90621 – 16 × 4 IR-Array
MLX90640 – 32 × 24 IR-Array
MLX90641 – 16 × 12 IR-Array
AMG8833 – 8 × 8 IR-Array
Verdrahten Sie das Modul mit dem I²C-Bus des Boards und lesen Sie Einzelbilder mit 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())
Der fir-Treiber kommuniziert mit dem Sensor nur über I²C 1 – verdrahten Sie das Modul mit den bedruckten SCL / SDA-Pads.
Timing¶
time¶
Das time-Modul deckt blockierende Verzögerungen, monotone Ticks und die Messung verstrichener Zeit ab:
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)
Virtuelle Timer¶
machine.Timer plant periodische oder einmalige Callbacks, ohne einen Hardware-Timer-Slot zu belegen. Übergeben Sie -1 als id, um einen virtuellen (Software-)Timer zu verwenden:
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"))
Periodenwerte sind in Millisekunden. Rufen Sie deinit() auf, um den Slot zu stoppen und freizugeben.
Echtzeituhr¶
machine.RTC hält die Wanduhrzeit über Resets hinweg:
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 setzt das Board zurück, wenn die Anwendung hängt. Einmal gestartet, kann er nicht gestoppt oder umkonfiguriert werden – füttern Sie ihn periodisch innerhalb Ihrer Hauptschleife:
from machine import WDT
wdt = WDT(timeout=5_000) # 5 second window
while True:
# ...do work...
wdt.feed()
Boot- und Laufzeitinformationen¶
Firmware-Update (DFU)¶
Die Nicla Vision verwendet Arduinos Standard-Doppeltipp-Reset, um in Arduinos Bootloader zu gelangen. Drücken Sie den Reset-Taster zweimal schnell hintereinander – das Board meldet sich über USB als DFU-Gerät neu an, und OpenMV IDE kann ein neues Firmware-Image flashen.
Ein laufendes Skript kann den Bootloader bei Bedarf erneut aufrufen, indem es machine.bootloader() aufruft:
import machine
machine.bootloader()
Dateisystem und Boot-Reihenfolge¶
Die Nicla-Vision-Firmware mountet beim Booten bis zu zwei Dateisysteme:
Internes Flash – immer unter
/flashgemountet. Enthält standardmäßigmain.pyundREADME.txt; wird beim allerersten Boot erstellt.ROMFS – schreibgeschütztes, speicherabgebildetes Dateisystem unter
/rom, das von MicroPython beim Start automatisch gemountet wird.
Nach dem Mounten wird das Arbeitsverzeichnis auf /flash gesetzt. Der Interpreter führt dann Skripte aus diesem Verzeichnis aus:
boot.pywird bei jedem Soft-Reset ausgeführt (Kaltstart,Ctrl‑Daus der REPL oder immer dann, wenn das laufende Skript zurückkehrt).main.pywird nur beim Kaltstart ausgeführt, unmittelbar nachboot.py. Nachfolgende Soft-Resets führenboot.pyerneut aus, fallen aber direkt zur REPL durch – ummain.pyerneut auszuführen, müssen Sie das Board vollständig zurücksetzen.
Die standardmäßige main.py, die auf einem frisch geflashten Board ausgeliefert wird, lässt einfach den blauen Kanal der RGB-Benutzer-LED als Heartbeat blinken (zwei kurze Impulse, kurze Pause), sodass Sie erkennen können, dass die Firmware sauber gebootet ist, ohne dass ein Host angeschlossen ist.
sys.path wird erweitert, um beide Dateisysteme und ihre lib/-Unterverzeichnisse einzuschließen, sodass importierbare Module in /flash/lib oder /rom/lib liegen können.
Wenn über USB verbunden, meldet sich /flash auch als USB-Massenspeicherlaufwerk auf dem Host an, sodass Sie boot.py, main.py und alle anderen Dateien direkt bearbeiten können. Werfen Sie das Laufwerk aus, bevor Sie die Kamera zurücksetzen, damit der Host seine zwischengespeicherten Schreibvorgänge leert.
Bemerkung
Da das Betriebssystem das Laufwerk als passives Blockgerät behandelt, werden Dateien, die von auf der Kamera laufendem Code erstellt oder geändert werden, erst angezeigt, wenn der Host das Laufwerk neu mountet. Wenn sowohl das Betriebssystem als auch die Kamera gleichzeitig dasselbe Dateisystem beschreiben, gewinnt das Betriebssystem und überschreibt die von der Kamera vorgenommenen Änderungen. Verwenden Sie die SD-Karte für alle Daten, die das Skript zurückschreibt, und mounten Sie neu, bevor Sie diese Dateien vom Host lesen.
Bemerkung
Der rote Kanal der RGB-Benutzer-LED leuchtet möglicherweise kurz auf, während der Host vom USB-Massenspeicherlaufwerk liest oder darauf schreibt – dies ist eine firmwaregesteuerte Aktivitätsanzeige, kein Fehler.
Speichergrößen¶
Die Nicla Vision wird ausgeliefert mit:
/flash– 11 MB FAT-Dateisystem, lesen/schreiben./rom– 4 MB schreibgeschütztes, speicherabgebildetes ROMFS, verwendet zum Ausliefern von Skripten und ML-Modellen, die vom Zero-Copy-mmap-Zugriff profitieren.
Hard-Fault-Anzeige¶
Wenn die RGB-Benutzer-LED schnell alle Farben durchläuft – schnell genug, dass sie eher wie eine funkelnde weiße LED als wie einzelne Farbtöne aussieht – hat die Firmware einen nicht behebbaren Hard-Fault erlitten. Flashen Sie die Firmware neu, um sie wiederherzustellen; wenn das Neuflashen nicht hilft, ist das Board möglicherweise physisch beschädigt.
Software-Bibliotheken¶
Im Bibliotheksindex finden Sie die vollständige Liste der Module – einschließlich derjenigen, die einzigartig für den Nicla-Vision-Build sind.