OpenMV Pure Thermal¶
Das OpenMV Pure Thermal ist eine Komplettsystem-Wärmebildplatine, die um den STMicroelectronics STM32H743 (Cortex‑M7 @ 480 MHz) herum aufgebaut ist, mit 64 MB externem SDRAM, 32 MB QSPI-Flash, einem Hardware-JPEG-Codec, einem 4,3“-IPS-Touchscreen mit 800×480 und kapazitiver Bedienung, einem HDMI-Ausgang, einem FLIR® Lepton®-Wärmebildsockel und einer 5-MP-OV5640-Kamera für sichtbares Licht. Außerdem bietet es Wi‑Fi, einen microSD-Sockel, einen Laser-Entfernungsmesser, einen Summer und einen leistungsstarken weißen Beleuchter.
Das vollständige Datenblatt sowie Fotos und Abmessungen finden Sie auf der Produktseite des OpenMV Pure Thermal.
Höhepunkte¶
STMicroelectronics STM32H743XI Cortex‑M7 mit 480 MHz.
Hardware-JPEG-Encoder/-Decoder.
64 MB externes SDRAM (~400 MB/s) plus 1 MB internes SRAM.
2 MB internes Flash + 32 MB externes QSPI-Flash (~50 MB/s Lesegeschwindigkeit).
OV5640 5-MP-Rolling-Shutter-Sensor für sichtbares Licht.
FLIR® Lepton®-Sockel — nimmt jedes Lepton-1/2/2.5/3/3.5-Modul auf, radiometrisch oder nicht-radiometrisch, mit Temperatur pro Pixel in Grad Celsius.
4,3“-IPS-Touchscreen mit 800×480 und kapazitiver Bedienung (24‑Bit-Farbe @ 60 Hz) mit Unterstützung für bis zu 5 Gestenpunkte.
HDMI-Ausgang über TFP410-DVI-Serializer — bis zu 1280×720 @ 60 Hz.
Wi‑Fi über WINC1500; MJPEG über RTSP wird ab Werk unterstützt.
Full-Speed-USB‑C (12 Mb/s, strombegrenzt auf 900 mA) — erscheint gegenüber dem Host als VCP + USB-Massenspeicher und übernimmt zudem das Laden.
microSD-Sockel — SD bis 2 GB, SDHC bis 32 GB, SDXC bis 2 TB.
VL53L1CX-Laser-Entfernungsmesser (bis zu ~4 m).
Summer mit softwaregesteuerter Lautstärke / Frequenz.
Leistungsstarker weißer LED-Beleuchter zusätzlich zur RGB-Status-LED für den Benutzer.
LiPo-Akku-Anschluss mit USB-Laden bei 500 mA.
10 I/O-Pins, 5-V-tolerant mit 3,3-V-Ausgang, 25 mA pro Pin (120 mA insgesamt), interrupt-fähig. P6 ist im ADC- oder DAC-Modus nicht 5-V-tolerant.
ARM-10-Pin-SWD-Anschluss für ST‑LINK-/J‑Link-Debugging.
Qwiic-Anschluss für I²C-Peripheriegeräte.
Bemerkung
Die Platine hat an ihrer unteren linken Kante eine Aussparung für eine optionale ¼“–20-Stativmutter. Sie ist ab Werk nicht eingebaut — löten Sie eine in die Aussparung ein, wenn Sie die Platine auf einem Standard-Kamerastativ montieren möchten.
Pinbelegung¶
Pin-Referenz¶
Pin-Name |
Funktion |
|---|---|
P0 |
UART1 RX / SPI2 MOSI |
P1 |
UART1 TX / SPI2 MISO |
P2 |
SPI2 SCK / FDCAN2 TX |
P3 |
SPI2 NSS (CS) / FDCAN2 RX |
P4 |
I2C2 SCL / UART3 TX / TIM2 CH3 |
P5 |
I2C2 SDA / UART3 RX / TIM2 CH4 |
P6 |
ADC / DAC / TIM2 CH1 |
P7 |
I2C4 SCL / TIM4 CH1 |
P8 |
I2C4 SDA / TIM4 CH2 |
P9 |
digitaler I/O |
RESET |
auf GND ziehen, um die Platine zurückzusetzen |
SYN |
Frame-Sync-Pad — nicht angeschlossen |
VIN |
Shield-VIN-Pad — nicht angeschlossen |
BOOT0 |
beim Einschalten auf 3,3 V ziehen für DFU / ROM-Bootloader |
BUZZER |
On-Board-Piezo-Summer (TIM2/PWM-gesteuert) |
LED_RED |
Rotkanal der RGB-Status-LED (active low) |
LED_GREEN |
Grünkanal der RGB-Status-LED (active low) |
LED_BLUE |
Blaukanal der RGB-Status-LED (active low) |
LED_WHITE |
leistungsstarke weiße Beleuchtungs-LED |
Bemerkung
Die Pads SYN und VIN am Shield/Header haben beim Pure Thermal keine elektrische Verbindung — sie sind nur aus Gründen der Header-Kompatibilität vorhanden. Versorgen Sie die Platine stattdessen über USB‑C oder den On-Board-LiPo-Akku-Anschluss (siehe Power-Pins weiter unten). Beachten Sie außerdem, dass das VIN-Pad auf der Platine mit VBAT bedruckt ist (ein Beschriftungsfehler) — die Position entspricht dem Standard-VIN-Pin des OpenMV-Headers und ist ohnehin nicht angeschlossen.
Power-Pins¶
3.3V — geregelte 3,3-V-Schiene. Bis zu 250 mA für Shields verfügbar.
GND — gemeinsame Masse.
Das Pure Thermal wird über USB‑C oder den On-Board-LiPo-Akku-Anschluss mit Strom versorgt. Der USB‑C-Port ist insgesamt auf 900 mA strombegrenzt und übernimmt zudem das LiPo-Laden bei 500 mA, sodass das gleichzeitige Anschließen eines Akkus neben USB unterstützt wird.
Der On-Board-Einschaltknopf schaltet die Systemschienen ein und aus und funktioniert unabhängig davon, ob die Platine über USB oder über den LiPo versorgt wird. Halten Sie den Knopf einige Sekunden lang gedrückt, um den Zustand umzuschalten — ein kurzes Antippen wird ignoriert, um ein versehentliches Abschalten zu verhindern.
Die Quellenauswahl folgt zwei einfachen Regeln:
Der Akku versorgt die Platine nur, wenn seine Spannung über 3 V liegt. Unterhalb dieses Schwellenwerts trennt der On-Board-PMIC den Akku, um ihn vor Tiefentladung zu schützen.
Wenn USB vorhanden ist, versorgt USB die Platine und ein angeschlossener LiPo wird im Hintergrund geladen.
Der LiPo-Anschluss verfügt außerdem über einen Verpolungsschutz, sodass ein verkehrt herum eingestecktes Akku der Platine nicht schadet.
Bemerkung
Die Platine leitet außerdem die Akkuspannung und ein Akkustrom-Messsignal zurück an ADC-Kanäle des MCU, allerdings wurde für beides noch keine Firmware-Unterstützung hinzugefügt.
Recovery- und Debug-Pins¶
RESET — auf GND ziehen, um die Platine zurückzusetzen. Das Pure Thermal hat zudem einen dedizierten RESET-Knopf auf der Platine, der dasselbe bewirkt.
BOOT0 — beim Einschalten der Platine auf 3,3 V ziehen, um den STM32-ROM-Bootloader (DFU-Modus) aufzurufen. OpenMV IDE nutzt diesen Modus, um den On-Board-Bootloader neu zu flashen. Ein dedizierter BOOT0-Knopf auf der Platine bewirkt dasselbe — halten Sie ihn gedrückt, während Sie die Stromversorgung anlegen.
Die Platine stellt einen SWD-Debug-Header (RST / SWCLK / SWDIO / SWO) neben dem GPIO-Header bereit, kompatibel mit ST‑LINK- und SEGGER-J‑Link-Adaptern. Ein separater ARM-10-Pin-SWD-Anschluss ist ebenfalls verbaut — er führt dieselben SWD-Signale (kein vollständiges JTAG), jedoch im Standard-Formfaktor mit 0,05“ und 10 Pins.
Bemerkung
Der SWO-Trace-Pin wird mit dem SPI-Takt des On-Board-FLIR® Lepton® geteilt. SWO kann nicht gleichzeitig mit dem Lepton verwendet werden — entscheiden Sie sich für eines von beiden.
Ein dritter PURE Modules Debug-Anschluss ist auf der Platine verbaut. Er führt eine Handvoll debug-orientierter Signale heraus (SWCLK, SWDIO, RST, SPI2_MISO, SPI2_MOSI, VBUS, 3,3 V, GND sowie zwei GPIO-Pins) zum Anschluss von Begleitmodulen. Die beiden GPIO-Pins an diesem Anschluss werden von einem internen, per Bit-Banging realisierten I²C-Bus angesteuert und nicht von einem Hardware-Peripheriegerät.
Alle drei Debug-Anschlüsse (der Inline-SWD-Header, der ARM-10-Pin-SWD-Anschluss und der PURE Modules Debug-Anschluss) sind auf 3,3 V bezogen — stellen Sie sicher, dass Ihr Debug-Adapter vor dem Anschließen auf 3,3-V-Logik konfiguriert ist.
On-Board-Peripheriegeräte¶
LEDs¶
Das Pure Thermal hat drei LEDs auf der Platine:
Benutzer-RGB-LED — softwaresteuerbar, bereitgestellt als
LED_RED,LED_GREENundLED_BLUE:from machine import LED LED("LED_RED").on() LED("LED_GREEN").on() LED("LED_BLUE").on()
Weißer Beleuchter — angesteuert über
LED_WHITE.LED_WHITEist in der Hardware active high verdrahtet, während die Firmware jede andere On-Board-LED als active low behandelt; verwenden Sie daherlow()/high()statton()/off()(was die Logik invertieren würde):from machine import LED light = LED("LED_WHITE") light.low() # turn the white LED ON light.high() # turn the white LED OFF
Lade-LED — direkt von der On-Board-Energieverwaltungshardware angesteuert, keine Softwaresteuerung. Sie funktioniert unabhängig davon, ob die Systemschienen ein- oder ausgeschaltet sind (d. h. mit dem Einschaltknopf in beiden Stellungen).
Farbe
Bedeutung
Blau
lädt — siehe Errata: schaltet möglicherweise nicht ab, wenn der Ladevorgang abgeschlossen ist
Grün
Ladevorgang abgeschlossen — siehe Errata: wird möglicherweise nicht zuverlässig ausgelöst
Rot
niedriger Akkustand (≤ 3,2 V, nur wenn nicht aktiv geladen wird)
Summer¶
Der On-Board-Piezo-Summer ist mit einem Timer-Kanal verdrahtet — steuern Sie ihn mit machine.PWM an, um Töne mit softwaregesteuerter Frequenz (Tonhöhe) und Tastverhältnis (Lautstärke) zu erzeugen:
import time
from machine import Pin, PWM
beep = PWM(Pin("BUZZER"), freq=2_000, duty_u16=32768) # ~50% duty
time.sleep_ms(500) # sound for 0.5 s
beep.deinit()
Kamerasensor¶
Der OV5640 ist die primäre CSI am Pure Thermal — übergeben Sie cid=csi.OV5640, um ihn explizit anzusprechen:
import csi
cam = csi.CSI(cid=csi.OV5640)
cam.reset(hard=True)
cam.pixformat(csi.RGB565)
cam.framesize(csi.WVGA)
cam.snapshot(time=2000) # let auto‑exposure settle
while True:
img = cam.snapshot()
Der OV5640 verfügt über einen On-Board-JPEG-Kompressor. Setzen Sie csi.CSI.pixformat auf csi.JPEG, und der Sensor liefert komprimierte Einzelbilder direkt über den Kamerabus an die Kamera, was hochauflösende Aufnahmen praktikabel macht: csi.HD (1280×720), csi.FHD (1920×1080) und das volle 5-MP-csi.WQXGA2 (2592×1944) werden alle als JPEG gestreamt. Stellen Sie die Kompression mit csi.CSI.quality ein (0-100, höher = größere Einzelbilder, mehr Details):
cam.pixformat(csi.JPEG)
cam.framesize(csi.WQXGA2)
cam.quality(90)
Der OV5640 verfügt über ein Autofokus-Objektiv mit Voice-Coil-Aktuator. Lösen Sie über csi.CSI.ioctl mit csi.IOCTL_TRIGGER_AUTO_FOCUS einen einzelnen Autofokus-Durchlauf aus — der Sensor fährt den Fokusmotor einmal durch und stellt scharf auf das, was sich vor ihm befindet:
cam.ioctl(csi.IOCTL_TRIGGER_AUTO_FOCUS)
Setzen Sie den ioctl erneut ab, sobald sich die Szene ändert — der Autofokus arbeitet einmalig, nicht kontinuierlich.
Bemerkung
Der STROBE-Ausgang des OV5640 (verwendet für synchronisierten Blitz / IR-Beleuchtung) ist beim Pure Thermal mit dem MCU verdrahtet, doch eine Firmware-Unterstützung dafür wurde noch nicht hinzugefügt.
Wärmebild-Kamerasensor¶
Der FLIR® Lepton®-Sockel erscheint als zweite CSI über dieselbe csi — Kamerasensoren-API. Übergeben Sie cid=csi.LEPTON, um ihn anzusprechen, und überspringen Sie den Hardware-Reset:
import csi
lepton = csi.CSI(cid=csi.LEPTON)
lepton.reset(hard=False)
lepton.pixformat(csi.GRAYSCALE)
lepton.framesize(csi.QVGA)
while True:
img = lepton.snapshot()
Bemerkung
Der VSYNC-Ausgang des Lepton (ein Impuls pro Wärmebild-Einzelbild) ist beim Pure Thermal mit dem MCU verdrahtet, doch eine Firmware-Unterstützung dafür wurde noch nicht hinzugefügt.
Beide CSIs können nebeneinander laufen. Das folgende Beispiel holt ein Farbbild vom OV5640 und ein Wärmebild vom Lepton und legt dann das Lepton-Bild mithilfe einer Ironbow-Palette und einer Alphamaske, die bei niedriger Intensität in Transparenz übergeht, über das Farbbild:
import csi
import image
import math
alpha_pal = image.Image(256, 1, image.GRAYSCALE)
for i in range(256):
alpha_pal[i] = int(math.pow((i / 255), 2) * 255)
csi0 = csi.CSI()
csi0.reset(hard=True)
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.WVGA)
csi1 = csi.CSI(cid=csi.LEPTON)
csi1.reset(hard=False)
csi1.pixformat(csi.GRAYSCALE)
csi1.framesize(csi.QVGA)
img1 = image.Image(csi1.width(), csi1.height(), csi1.pixformat())
while True:
img0 = csi0.snapshot()
csi1.snapshot(blocking=False, image=img1)
img0.draw_image(
img1, 0, 0,
color_palette=image.PALETTE_IRONBOW,
alpha_palette=alpha_pal,
hint=image.BILINEAR,
)
Maschinelles Lernen¶
ml — Maschinelles Lernen führt quantisierte TFLite-Modelle auf dem Cortex‑M7 mit CMSIS‑NN-Kerneln aus — schnell genug für kompakte Detektoren mit einigen Einzelbildern pro Sekunde. Modelle auf dem schreibgeschützten /rom-Dateisystem werden direkt aus dem Flash geladen, ohne in den RAM kopiert zu werden. Hier ist ein 128×128-BlazeFace-Detektor, der das erkannte Gesicht und seine sechs Landmarken über jedes Einzelbild der Kamera für sichtbares Licht legt:
import csi
import time
import ml
from ml.postprocessing.mediapipe import BlazeFace
# Initialize the sensor.
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)
csi0.window((400, 400))
# Load built-in face detection model
model = ml.Model("/rom/blazeface_front_128.tflite", postprocess=BlazeFace(threshold=0.4))
print(model)
clock = time.clock()
while True:
clock.tick()
img = csi0.snapshot()
# faces is a list of ((x, y, w, h), score, keypoints) tuples
for r, score, keypoints in model.predict([img]):
ml.utils.draw_predictions(img, [r], ("face",), ((0, 0, 255),), format=None)
# keypoints is a ndarray of shape (6, 2)
# 0 - right eye (x, y)
# 1 - left eye (x, y)
# 2 - nose (x, y)
# 3 - mouth (x, y)
# 4 - right ear (x, y)
# 5 - left ear (x, y)
ml.utils.draw_keypoints(img, keypoints, color=(255, 0, 0))
print(clock.fps(), "fps")
Laser-Entfernungsmesser¶
Der On-Board-ST-VL53L1CX-Time-of-Flight-Entfernungsmesser ist mit I²C-Bus 2 verdrahtet. Verwenden Sie den eingefrorenen vl53l1x — VL53L1X ToF-Distanzsensor-Treiber-Treiber, um Entfernungsmessungen bis zu ~4 m zu erhalten:
import time
from machine import I2C
import vl53l1x
bus = I2C(2)
tof = vl53l1x.VL53L1X(bus)
while True:
print("Distance:", tof.read(), "mm")
time.sleep_ms(100)
LCD-Ausgang¶
Das 4,3“-On-Board-LCD hat eine Auflösung von 800 × 480 (WVGA) und wird über die RGB-Display-Schnittstelle des display — Display-Treiber-Moduls angesteuert — übergeben Sie framesize=display.FWVGA, um seiner nativen Auflösung zu entsprechen:
import display
lcd = display.RGBDisplay(framesize=display.FWVGA, refresh=60)
lcd.backlight(True) # turn the LCD backlight on
lcd.write(img)
Die Hintergrundbeleuchtung ist mit einem GPIO verdrahtet, daher akzeptiert backlight() True / False (oder einen beliebigen Wert von 0–100, wobei 0 aus bedeutet und jeder Wert ungleich null an):
lcd.backlight(False) # turn the backlight off
lcd.backlight(True) # back on
Touchscreen¶
Der kapazitive Touch-Controller ist der FT5X06; Multi-Touch-Positionen und Gesten-Ereignisse werden über ft5x06 — Touchscreen-Treiber bereitgestellt. Registrieren Sie einen Callback, um auf Berührungen zu reagieren, und lesen Sie darin die aktiven Punkte aus:
import ft5x06
touch = ft5x06.FT5X06()
def on_touch(n):
for i in range(n):
x = touch.get_point_x(i)
y = touch.get_point_y(i)
print("touch", i, "at", x, y)
gesture = touch.get_gesture()
if gesture != ft5x06.GESTURE_NONE:
print("gesture:", gesture)
touch.touch_callback(on_touch)
HDMI-Ausgang¶
Die Firmware spiegelt den LCD-Framebuffer zudem auf den On-Board-tfp410 — DVI/HDMI-Controller-HDMI-Serializer, sodass ein externer Monitor das anzeigt, was auf dem LCD zu sehen ist. Instanziieren Sie tfp410.TFP410, um den HDMI-Ausgang zu aktivieren:
import tfp410
hdmi = tfp410.TFP410()
Wenn Sie nur den HDMI-Ausgang nutzen möchten und das On-Board-LCD nicht benötigen, schalten Sie die Hintergrundbeleuchtung aus und erhöhen Sie die Framebuffer-Auflösung über WVGA hinaus. Der TFP410 unterstützt bis zu 1280×720 @ 60 Hz, also zum Beispiel:
lcd = display.RGBDisplay(framesize=display.HD, refresh=60)
lcd.backlight(False) # the on‑board LCD can't render HD
hdmi = tfp410.TFP410()
Das On-Board-Panel ist fest auf 800×480 eingestellt, sodass alles oberhalb von WVGA nur auf dem externen HDMI-Monitor von Bedeutung ist.
Um zu erfahren, wann ein HDMI-Monitor angeschlossen oder getrennt wurde, registrieren Sie einen Hot-Plug-Callback am TFP410. Der Callback wird mit True beim Anschließen und False beim Trennen ausgelöst:
def on_hotplug(connected):
print("HDMI", "connected" if connected else "disconnected")
hdmi.hotplug_callback(on_hotplug)
Sie können den Verbindungsstatus auch jederzeit mit isconnected() abfragen (nur wenn kein Callback registriert ist).
Der HDMI-Port führt zudem die Kanäle DDC (Display-Daten) und CEC (Consumer Electronics Control), die über die Klasse class DisplayData – Display-Daten bereitgestellt werden. Verwenden Sie sie, um den EDID-Block des angeschlossenen Monitors auszulesen (sodass Sie sich an dessen native Auflösung / Bildwiederholrate anpassen können) oder um CEC-Frames zur Steuerung anderer HDMI-Geräte auf derselben Leitung zu senden/empfangen:
from display import DisplayData
dd = DisplayData(cec=True, ddc=True)
edid = dd.display_id() # EDID bytes from the monitor
print(len(edid), "byte EDID")
# Send a CEC "image view on" command (opcode 0x04) from address 1 to address 0
dd.send_frame(0, 1, b"\x04")
# ...or wait for an incoming CEC frame addressed to us (logical address 1)
src, data = dd.receive_frame(1, timeout=5_000)
print("CEC from", src, ":", data)
Wi‑Fi¶
Wi‑Fi läuft über ein Microchip-WINC1500-Modul, das über die class WINC – WiFi-Shield-Treiber-Schnittstelle bereitgestellt wird:
import network, time
wlan = network.WINC()
wlan.connect("ssid", "password")
while not wlan.isconnected():
time.sleep(1)
print("Wi‑Fi IP:", wlan.ipconfig("addr4")[0])
Bemerkung
Aufgrund von Bauteilknappheit wurden einige Pure-Thermal-Geräte ohne bestücktes WINC1500-Modul ausgeliefert. Wenn network.WINC einen Fehler auslöst oder nie verbindet, prüfen Sie die Platine auf ein fehlendes Wi‑Fi-Modul — der Rest der Kamera funktioniert auch ohne genau gleich.
microSD-Karte¶
Wenn eine Karte eingelegt wird, wird sie automatisch unter /sdcard eingebunden und ist über das reguläre Dateisystem nutzbar:
import os
for entry in os.listdir("/sdcard"):
print(entry)
Bus-Referenz¶
GPIO¶
Verwenden Sie machine.Pin, um beliebige der bedruckten Pins zu lesen oder anzusteuern. Ausgänge sind 3,3-V-CMOS, 5-V-tolerant auf der Eingangsseite und können bis zu 25 mA pro Pin liefern/aufnehmen (120 mA insgesamt über den gesamten Header).
from machine import Pin
out = Pin("P0", Pin.OUT)
out.on()
out.off()
out.value(1)
inp = Pin("P1", Pin.IN, Pin.PULL_UP)
print(inp.value())
Jeder Eingangs-Pin kann zudem bei Flankenwechseln einen Interrupt auslösen:
def handler(pin):
print("triggered:", pin)
Pin("P1", Pin.IN, Pin.PULL_UP).irq(
handler, Pin.IRQ_FALLING | Pin.IRQ_RISING,
)
UART¶
Bus |
TX |
RX |
|---|---|---|
UART1 |
P1 |
P0 |
UART3 |
P4 |
P5 |
from machine import UART
uart = UART(3, baudrate=115200)
uart.write("hello")
uart.read(5)
I²C¶
Bus |
SCL |
SDA |
|---|---|---|
I2C2 |
P4 |
P5 |
I2C4 |
P7 |
P8 |
from machine import I2C
i2c = I2C(2, freq=400_000)
i2c.scan()
i2c.writeto(0x76, b"hi")
Dieselbe Hardware kann über machine.I2CTarget auch im Target-Modus (Slave) verwendet werden, um einem anderen I²C-Controller einen Speicherbereich bereitzustellen:
from machine import I2CTarget
buf = bytearray(32)
target = I2CTarget(2, addr=0x42, mem=buf)
Der On-Board-Qwiic-Anschluss führt einen dieser I²C-Busse für Plug-and-Play-Module heraus. Die Qwiic-Leitung wird über Open-Drain-Transistoren auf 5 V pegelgewandelt, sodass der Bus nur auf Standard-Modus (100 kHz) und Fast-Modus (400 kHz) beschränkt ist — versuchen Sie nicht, Fast-Modus-Plus oder höhere Raten über den Qwiic-Header zu betreiben.
Der Qwiic-Anschluss gibt 5 V aus, um angeschlossene Module zu versorgen; er kann nicht zur Versorgung des Pure Thermal selbst verwendet werden — versorgen Sie die Platine stattdessen über USB‑C oder den LiPo-Akku-Anschluss.
SPI¶
Bus |
MOSI |
MISO |
SCK |
CS |
|---|---|---|---|---|
SPI2 |
P0 |
P1 |
P2 |
P3 |
from machine import SPI
from machine import Pin
spi = SPI(2, baudrate=10_000_000)
cs = Pin("P3", Pin.OUT, value=1) # CS is not driven by the SPI peripheral
cs.value(0)
spi.write(b"hello")
cs.value(1)
CAN (FDCAN)¶
Bus |
TX |
RX |
|---|---|---|
FDCAN2 |
P2 |
P3 |
from machine import CAN
can = CAN(2, 500_000)
can.set_filters(None)
can.send(0x123, b"\xDE\xAD\xBE\xEF")
print(can.recv())
ADC und DAC¶
P6 ist der einzige analoge Benutzer-Pin. Er kann entweder als 12‑Bit-ADC-Eingang oder als DAC-Ausgang verwendet werden.
ADC — Vollausschlag bei 3,3 V am Pin:
from machine import ADC import time adc = ADC("P6") while True: voltage = adc.read_u16() * 3.3 / 65535 print(voltage) time.sleep_ms(100)
DAC — über
pyb.DAC. Der 8‑Bit-Wert deckt 0–3,3 V ab:from pyb import DAC dac = DAC("P6") voltage = 1.65 dac.write(int(voltage / 3.3 * 255))
Im ADC- oder DAC-Modus ist P6 nur 3,3-V-tolerant — speisen Sie keine 5 V ein.
PWM¶
Pin |
Timer / Kanal |
|---|---|
P4 |
TIM2 CH3 |
P5 |
TIM2 CH4 |
P6 |
TIM2 CH1 |
P7 |
TIM4 CH1 |
P8 |
TIM4 CH2 |
Bemerkung
TIM1 ist von der Firmware reserviert, um den Pixeltakt des Kamerasensors zu erzeugen, daher können die TIM1-Kanäle, die physisch an P0/P1/P2 liegen, nicht für Benutzer-PWM verwendet werden, ohne die Kamera zu beeinträchtigen.
TIM4 wird mit pyb.Servo geteilt — das Instanziieren eines Servos konfiguriert den gesamten Timer für den 50-Hz-Betrieb um, mischen Sie daher nicht machine.PWM an P7/P8 mit pyb.Servo im selben Skript.
Steuern Sie beliebige davon über machine.PWM an:
from machine import Pin, PWM
pwm = PWM(Pin("P7"), freq=1_000, duty_u16=32768)
Software-Busse per Bit-Banging¶
machine.SoftI2C und machine.SoftSPI funktionieren an jedem GPIO, falls Sie einen zusätzlichen Bus benötigen.
Wärmebildsensor (extern)¶
Zusätzlich zum On-Board-FLIR-Lepton enthält die Firmware auch den fir — Wärmesensortreiber (fir == far infrared)-Treiber für extern verdrahtete I²C-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 der Platine 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 2 — verdrahten Sie das Modul mit P4 (SCL) und P5 (SDA).
Timing¶
time¶
import time
time.sleep(1)
time.sleep_ms(500)
time.sleep_us(10)
start = time.ticks_ms()
elapsed = time.ticks_diff(time.ticks_ms(), start)
Virtuelle Timer¶
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 angegeben. Rufen Sie deinit() auf, um zu stoppen und den Slot freizugeben.
Echtzeituhr¶
from machine import RTC
rtc = RTC()
rtc.datetime((2026, 4, 30, 4, 12, 0, 0, 0))
print(rtc.datetime())
Wenn ein LiPo-Akku angeschlossen ist, hält die RTC die Zeit auch dann aufrecht, wenn die Systemschienen ausgeschaltet sind (über den On-Board-Einschaltknopf heruntergefahren). Ist nur USB eingesteckt, trennt das Drücken des Einschaltknopfs auch die RTC von der Stromversorgung — die Echtzeit übersteht ohne angeschlossenen Akku also keinen Stromzyklus.
Watchdog¶
from machine import WDT
wdt = WDT(timeout=5_000)
while True:
# ...do work...
wdt.feed()
Boot- und Laufzeitinformationen¶
USB-Bootloader-Fenster¶
Bei jedem Einschalten führt die Kamera einen kurzen Bootloader aus (einige Sekunden), der es OpenMV IDE ermöglicht, die Firmware zu aktualisieren, ohne dass der Benutzer in den DFU-Modus wechseln muss. Nach Ablauf des Fensters übergibt der Bootloader an boot.py und dann an main.py.
Ein laufendes Skript kann den Bootloader bei Bedarf erneut aufrufen, indem es machine.bootloader() aufruft.
Dateisystem und Boot-Reihenfolge¶
Die Pure-Thermal-Firmware bindet beim Booten bis zu drei Dateisysteme ein:
Internes Flash — immer unter
/flasheingebunden. Enthält standardmäßigmain.pyundREADME.txt; wird beim allerersten Booten erstellt.microSD-Karte — wenn eine Karte eingelegt ist, wird sie unter
/sdcardeingebunden.ROMFS — schreibgeschütztes, speicherabgebildetes Dateisystem unter
/rom, das verwendet wird, um große Datenbestände (z. B. KI-Modelle) auszuliefern, die von Zero-Copy-Zugriff profitieren. Wird von MicroPython beim Start automatisch eingebunden, bevor irgendein Benutzer-Python läuft.
Nach dem Einbinden wird das Arbeitsverzeichnis auf /sdcard gesetzt, wenn die Karte vorhanden ist, andernfalls auf /flash. Der Interpreter führt dann Skripte aus diesem Verzeichnis aus:
boot.pywird bei jedem Soft-Reset ausgeführt.main.pywird nur beim Kaltstart ausgeführt, unmittelbar nachboot.py.
Wenn Sie eine boot.py oder main.py auf die SD-Karte legen, überschreibt dies die Kopie im Flash, ohne sie anzutasten.
Bei Verbindung über USB wird das Boot-Dateisystem (/sdcard, falls eine Karte vorhanden ist, andernfalls /flash) auf dem Host zudem als USB-Massenspeicherlaufwerk angemeldet. Werfen Sie das Laufwerk aus, bevor Sie die Kamera zurücksetzen, damit der Host seine zwischengespeicherten Schreibvorgänge schreibt.
Bemerkung
Dateien, die von Code erstellt oder verändert werden, der auf der OpenMV Cam läuft, erscheinen erst dann auf dem Host, wenn das Laufwerk erneut eingebunden wird. Verwenden Sie die SD-Karte für alle Daten, die das Skript zurückschreibt, und binden Sie sie erneut ein, bevor Sie diese Dateien vom Host aus lesen.
Speichergrößen¶
Das Pure Thermal wird ausgeliefert mit:
/flash— 24 MB FAT-Dateisystem, lesen/schreiben./rom— 8 MB schreibgeschütztes, speicherabgebildetes ROMFS, das verwendet wird, um Skripte und ML-Modelle auszuliefern, die von Zero-Copy-mmap-Zugriff profitieren./sdcard— volle Größe der jeweils eingelegten microSD-Karte (sofern vorhanden), lesen/schreiben.
Hard-Fault-Anzeige¶
Wenn die Benutzer-RGB-LED schnell alle Farben durchläuft — so schnell, dass sie eher wie eine flackernde weiße LED als wie einzelne Farbtöne aussieht — ist die Firmware auf einen nicht behebbaren Hard Fault gestoßen. Flashen Sie die Firmware neu, um den Zustand wiederherzustellen.
Hardware-Errata¶
Eine Handvoll Eigenheiten auf Platinenebene sind in den Hardware-Errata des Pure Thermal dokumentiert. Wichtige Punkte, die zu beachten sind:
Interferenz des Akku-Anschlusses — Bauteile auf der Platine sitzen direkt unter dem LiPo-Akku-Anschluss, und der vorstehende Keil am Stecker des Akkukabels kann sich beim Abziehen des Kabels an ihnen verhaken und manchmal Bauteile von der Platine reißen. Schneiden Sie den Keil mit einem bündigen Seitenschneider vom Kabelstecker ab, bevor Sie das Gerät zum ersten Mal verwenden.
Die RTC stoppt, während die Platine ausgeschaltet ist — die Lastkapazität am 32-kHz-Quarz (Y2) ist zu hoch. Das Entfernen von C96 und C97 (dem Paar, das den Quarz neben dem STM32 flankiert) lässt die RTC im Backup-Betrieb weiterlaufen. Die meisten Platinen werden bereits mit entfernten Kondensatoren ausgeliefert; wenn Ihre RTC im ausgesteckten Zustand die Zeit verliert, prüfen Sie diese Positionen. Den vollständigen Thread finden Sie in den GitHub-Issues #1536 und #1600.
Lade-Anzeige-LED bleibt blau — das Ladegerät kann seinen Ladezyklus irgendwo zwischen 4,15 V und 4,19 V beenden, ohne die Anzeige von Blau (lädt) auf Grün (geladen) umzuschalten. Der Akku ist in diesem Fall trotzdem vollständig geladen; vertrauen Sie einer Spannungsmessung, nicht der LED.
Bedruckung beschriftet VIN fälschlich als VBAT — das Pad in der Standard-VIN-Position des OpenMV-Headers ist beim Pure Thermal mit
VBATbedruckt. Die Beschriftung ist falsch, spielt aber in der Praxis keine Rolle, da das Pad ohnehin keine elektrische Verbindung hat.
Softwarebibliotheken¶
Im Bibliotheksindex finden Sie die vollständige Liste der Module — einschließlich derjenigen, die exklusiv für den Pure-Thermal-Build sind.