OpenMV Pure Thermal

De OpenMV Pure Thermal is een complete thermische beeldverwerkingsprint, opgebouwd rond de STMicroelectronics STM32H743 (Cortex‑M7 @ 480 MHz) met 64 MB extern SDRAM, 32 MB QSPI‑flashgeheugen, een hardware‑JPEG‑codec, een 4.3” 800×480 IPS capacitief aanraakscherm, een HDMI‑uitgang, een FLIR® Lepton® thermische socket en een 5MP OV5640‑camera voor zichtbaar licht. Daarnaast bevat de print Wi‑Fi, een microSD‑socket, een laserafstandsmeter, een zoemer en een krachtige witte verlichting.

OpenMV Pure Thermal

Voor het volledige datasheet, foto’s en afmetingen, zie de OpenMV Pure Thermal productpagina.

Hoogtepunten

  • STMicroelectronics STM32H743XI Cortex‑M7 op 480 MHz.

  • Hardware JPEG‑encoder/decoder.

  • 64 MB extern SDRAM (~400 MB/s) plus 1 MB intern SRAM.

  • 2 MB intern flashgeheugen + 32 MB extern QSPI‑flashgeheugen (~50 MB/s leessnelheid).

  • OV5640 5MP rolling‑shutter sensor voor zichtbaar licht.

  • FLIR® Lepton® socket — geschikt voor elke Lepton 1/2/2.5/3/3.5‑module, radiometrisch of niet‑radiometrisch, met temperatuur per pixel in graden Celsius.

  • 4.3” 800×480 IPS capacitief aanraakscherm (24‑bits kleur @ 60 Hz) met ondersteuning voor maximaal 5 aanraakpunten en gebaren.

  • HDMI‑uitgang via TFP410 DVI‑serializer — tot 1280×720 @ 60 Hz.

  • Wi‑Fi via WINC1500; MJPEG over RTSP wordt standaard ondersteund.

  • Full‑speed USB‑C (12 Mb/s, stroombegrensd op 900 mA) — verschijnt als VCP + USB‑massaopslag op de host en verzorgt ook het opladen.

  • microSD‑socket — SD tot 2 GB, SDHC tot 32 GB, SDXC tot 2 TB.

  • VL53L1CX laserafstandsmeter (tot ~4 m).

  • Zoemer met softwarematig geregeld volume / frequentie.

  • Krachtige witte LED‑verlichting naast de RGB‑status‑LED voor de gebruiker.

  • LiPo‑batterijconnector met USB‑opladen bij 500 mA.

  • 10 I/O‑pinnen, 5 V‑tolerant met 3.3 V‑uitgang, 25 mA per pin (120 mA totaal), interruptgeschikt. P6 is niet 5 V‑tolerant wanneer deze in ADC‑ of DAC‑modus wordt gebruikt.

  • ARM 10‑pins SWD‑connector voor ST‑LINK / J‑Link debuggen.

  • Qwiic‑connector voor I²C‑randapparaten.

Notitie

De print heeft een gleuf op de linkeronderrand voor een optionele ¼”–20 statiefmoer. Deze wordt niet af fabriek gemonteerd — soldeer er een in de gleuf als je de print op een standaard camerastatief wilt monteren.

Pinout

OpenMV Pure Thermal pinout

Pinreferentie

Pinnaam

Functie

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

digitale I/O

RESET

trek naar GND om de print te resetten

SYN

frame‑sync pad — niet aangesloten

VIN

shield VIN pad — niet aangesloten

BOOT0

trek naar 3.3 V bij inschakelen voor DFU / ROM‑bootloader

BUZZER

piëzo‑zoemer op de print (aangestuurd via TIM2/PWM)

LED_RED

rode kanaal van de RGB‑status‑LED (actief laag)

LED_GREEN

groene kanaal van de RGB‑status‑LED (actief laag)

LED_BLUE

blauwe kanaal van de RGB‑status‑LED (actief laag)

LED_WHITE

krachtige witte verlichtings‑LED

Notitie

De pads SYN en VIN op het shield/de header hebben geen elektrische verbinding op de Pure Thermal — ze zijn er alleen voor headercompatibiliteit. Voed de print in plaats daarvan via USB‑C of de LiPo‑batterijconnector op de print (zie Voedingspinnen hieronder). Merk ook op dat de VIN‑pad op de print is bedrukt met VBAT (een labelfout) — de positie is de standaard VIN‑pin van de OpenMV‑header en is hoe dan ook niet aangesloten.

Voedingspinnen

  • 3.3V — geregelde 3.3 V‑rail. Tot 250 mA beschikbaar voor shields.

  • GND — gemeenschappelijke massa.

De Pure Thermal wordt gevoed via USB‑C of de LiPo‑batterijconnector op de print. De USB‑C‑poort is stroombegrensd op 900 mA totaal en verzorgt ook het opladen van de LiPo bij 500 mA, dus het aansluiten van een batterij naast USB wordt ondersteund.

De aan/uit‑knop op de print schakelt de systeemrails aan en uit en werkt ongeacht of de print via USB of via de LiPo wordt gevoed. Houd de knop een paar seconden ingedrukt om van toestand te wisselen — een korte tik wordt genegeerd om per ongeluk uitschakelen te voorkomen.

De bronselectie volgt twee eenvoudige regels:

  • De batterij voedt de print alleen wanneer de spanning boven 3 V ligt. Onder die drempelwaarde koppelt de PMIC op de print de batterij los om deze tegen overontlading te beschermen.

  • Wanneer USB aanwezig is, voedt USB de print en wordt een eventueel aangesloten LiPo op de achtergrond opgeladen.

De LiPo‑connector beschikt ook over omgekeerde‑spanningsbeveiliging, zodat het verkeerd om aansluiten van de batterij de print niet beschadigt.

Notitie

De print stuurt ook de batterijspanning en een batterijstroom‑meetsignaal terug naar ADC‑kanalen van de MCU, maar firmware‑ondersteuning hiervoor is nog niet toegevoegd.

Herstel‑ en debugpinnen

  • RESET — trek naar GND om de print te resetten. De Pure Thermal heeft ook een speciale RESET‑knop op de print die hetzelfde doet.

  • BOOT0 — trek naar 3.3 V tijdens het voeden van de print om de STM32 ROM‑bootloader (DFU‑modus) te starten. OpenMV IDE gebruikt deze modus om de bootloader op de print opnieuw te flashen. Een speciale BOOT0‑knop op de print doet hetzelfde — houd deze ingedrukt terwijl je voeding aanlegt.

De print biedt een SWD‑debugheader (RST / SWCLK / SWDIO / SWO) naast de GPIO‑header, compatibel met ST‑LINK‑ en SEGGER J‑Link‑adapters. Er is ook een aparte ARM 10‑pins SWD‑connector gemonteerd — die voert dezelfde SWD‑signalen (geen volledige JTAG), maar in de standaard 0.05” 10‑pins vormfactor.

Notitie

De SWO‑trace‑pin wordt gedeeld met de SPI‑klok van de FLIR® Lepton® op de print. SWO kan niet tegelijk met de Lepton worden gebruikt — kies het een of het ander.

Een derde PURE Modules Debug‑connector is op de print gemonteerd. Deze maakt een handvol debug‑gerichte signalen beschikbaar (SWCLK, SWDIO, RST, SPI2_MISO, SPI2_MOSI, VBUS, 3.3 V, GND en twee GPIO‑pinnen) voor het aansluiten van bijbehorende modules. De twee GPIO‑pinnen op deze connector worden aangestuurd door een interne bit‑banged I²C‑bus in plaats van een hardware‑randapparaat.

Alle drie de debugconnectoren (de inline SWD‑header, de ARM 10‑pins SWD‑connector en de PURE Modules Debug‑connector) zijn gerefereerd aan 3.3 V — zorg ervoor dat je debugadapter is ingesteld op 3.3 V‑logica voordat je verbinding maakt.

Randapparaten op de print

LED’s

De Pure Thermal heeft drie LED’s op de print:

  • RGB‑gebruikers‑LED — softwarematig bestuurbaar, beschikbaar als LED_RED, LED_GREEN en LED_BLUE

    from machine import LED
    
    LED("LED_RED").on()
    LED("LED_GREEN").on()
    LED("LED_BLUE").on()
    
  • Witte verlichting — aangestuurd via LED_WHITE. LED_WHITE is in hardware actief hoog bedraad, terwijl de firmware elke andere LED op de print als actief laag behandelt, gebruik dus low() / high() in plaats van on() / off() (die de logica zouden omkeren):

    from machine import LED
    
    light = LED("LED_WHITE")
    light.low()    # turn the white LED ON
    light.high()   # turn the white LED OFF
    
  • Oplaad‑LED — rechtstreeks aangestuurd door de hardware voor energiebeheer op de print, geen softwarebesturing. Hij werkt ongeacht of de systeemrails aan of uit staan (d.w.z. met de aan/uit‑knop in beide standen).

    Kleur

    Betekenis

    Blauw

    bezig met opladen — zie errata: gaat mogelijk niet uit wanneer het opladen voltooid is

    Groen

    opladen voltooid — zie errata: wordt mogelijk niet betrouwbaar geactiveerd

    Rood

    lage batterij (≤ 3.2 V, alleen wanneer niet actief wordt opgeladen)

Zoemer

De piëzo‑zoemer op de print is bedraad naar een timerkanaal — stuur deze aan met machine.PWM voor tonen met softwarematig geregelde frequentie (toonhoogte) en duty cycle (volume):

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

Camerasensor

De OV5640 is de primaire CSI op de Pure Thermal — geef cid=csi.OV5640 door om deze expliciet aan te spreken:

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

De OV5640 heeft een JPEG‑compressor aan boord. Stel csi.CSI.pixformat in op csi.JPEG en de sensor levert gecomprimeerde frames rechtstreeks aan de cam over de camerabus, wat opnamen met hoge resolutie praktisch maakt: csi.HD (1280×720), csi.FHD (1920×1080) en de volledige 5MP csi.WQXGA2 (2592×1944) streamen allemaal als JPEG. Stem de compressie af met csi.CSI.quality (0-100, hoger = grotere frames, meer detail):

cam.pixformat(csi.JPEG)
cam.framesize(csi.WQXGA2)
cam.quality(90)

De OV5640 heeft een autofocuslens met voice‑coil‑actuator. Activeer één enkele autofocuspas via csi.CSI.ioctl met csi.IOCTL_TRIGGER_AUTO_FOCUS — de sensor laat de focusmotor één keer doorlopen en focust scherp op wat er voor hem staat:

cam.ioctl(csi.IOCTL_TRIGGER_AUTO_FOCUS)

Stuur de ioctl opnieuw uit telkens wanneer de scène verandert — de autofocus is eenmalig, niet continu.

Notitie

De STROBE‑uitgang van de OV5640 (gebruikt voor gesynchroniseerde flits / IR‑verlichting) is op de Pure Thermal aangesloten op de MCU, maar firmware‑ondersteuning ervoor is nog niet toegevoegd.

Thermische camerasensor

De FLIR® Lepton® socket verschijnt als een tweede CSI op dezelfde csi — camerasensoren‑API. Geef cid=csi.LEPTON door om deze aan te spreken, en sla de hardware‑reset over:

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

Notitie

De VSYNC‑uitgang van de Lepton (één puls per thermisch frame) is op de Pure Thermal aangesloten op de MCU, maar firmware‑ondersteuning ervoor is nog niet toegevoegd.

Beide CSI’s kunnen naast elkaar draaien. Het onderstaande voorbeeld haalt een kleurenframe op uit de OV5640 en een thermisch frame uit de Lepton, en legt vervolgens de Lepton bovenop het kleurenframe met een Ironbow‑palet en een alphamasker dat bij lage intensiteit naar transparant vervaagt:

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

Machine learning

ml — Machine Learning draait gekwantiseerde TFLite‑modellen op de Cortex‑M7 met CMSIS‑NN‑kernels — snel genoeg voor compacte detectors met enkele frames per seconde. Modellen op het alleen‑lezen /rom‑bestandssysteem laden rechtstreeks vanuit het flashgeheugen zonder naar RAM te kopiëren. Hier is een 128×128 BlazeFace‑detector die het gedetecteerde gezicht en de zes oriëntatiepunten ervan op elk frame van de camera voor zichtbaar licht overlegt:

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

Laserafstandsmeter

De ST VL53L1CX time‑of‑flight afstandsmeter op de print is bedraad naar I²C‑bus 2. Gebruik de bevroren vl53l1x — VL53L1X ToF-afstandssensordriver‑driver om afstandsmetingen tot ~4 m te krijgen:

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‑uitvoer

Het 4.3” LCD op de print is 800 × 480 (WVGA) en wordt aangestuurd via de RGB‑display‑interface van de module display — display-stuurprogramma — geef framesize=display.FWVGA door om de native resolutie te matchen:

import display

lcd = display.RGBDisplay(framesize=display.FWVGA, refresh=60)
lcd.backlight(True)           # turn the LCD backlight on
lcd.write(img)

De achtergrondverlichting is bedraad naar een GPIO, dus backlight() accepteert True / False (of een willekeurige waarde 0–100, waarbij 0 uit is en alles wat niet nul is aan staat):

lcd.backlight(False)           # turn the backlight off
lcd.backlight(True)            # back on

Aanraakscherm

De capacitieve aanraakcontroller is de FT5X06; multi‑touch‑posities en gebaargebeurtenissen worden beschikbaar gemaakt via ft5x06 — Touchscreen-driver. Registreer een callback om op aanrakingen te reageren en lees daarin de actieve punten uit:

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‑uitvoer

De firmware verdeelt de LCD‑framebuffer ook naar de tfp410 — DVI/HDMI-controller HDMI‑serializer op de print, zodat een externe monitor weergeeft wat er op het LCD staat. Instantieer tfp410.TFP410 om de HDMI‑uitvoer in te schakelen:

import tfp410

hdmi = tfp410.TFP410()

Als je alleen HDMI‑uitvoer wilt en het LCD op de print je niet uitmaakt, schakel dan de achtergrondverlichting uit en verhoog de framebuffer‑resolutie boven WVGA. De TFP410 ondersteunt tot 1280×720 @ 60 Hz, dus bijvoorbeeld:

lcd = display.RGBDisplay(framesize=display.HD, refresh=60)
lcd.backlight(False)         # the on‑board LCD can't render HD
hdmi = tfp410.TFP410()

Het paneel op de print is vast ingesteld op 800×480, dus alles boven WVGA heeft alleen zin op de externe HDMI‑monitor.

Om te weten wanneer een HDMI‑monitor is aangesloten of losgekoppeld, registreer je een hot‑plug‑callback op de TFP410. De callback wordt aangeroepen met True bij aansluiten en False bij loskoppelen:

def on_hotplug(connected):
    print("HDMI", "connected" if connected else "disconnected")

hdmi.hotplug_callback(on_hotplug)

Je kunt de verbindingsstatus ook op elk moment opvragen met isconnected() (alleen wanneer er geen callback is geregistreerd).

De HDMI‑poort voert ook de DDC‑ (display data) en CEC‑kanalen (consumer electronics control), beschikbaar gemaakt via de klasse class DisplayData – Display-gegevens. Gebruik deze om het EDID‑blok van de aangesloten monitor te lezen (zodat je je kunt aanpassen aan de native resolutie / verversingsfrequentie) of om CEC‑frames te verzenden/ontvangen voor het besturen van andere HDMI‑apparaten op dezelfde verbinding:

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 draait via een Microchip WINC1500‑module, beschikbaar gemaakt via de class WINC – WiFi-shield-driver‑interface:

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

Notitie

Door onderdelentekorten zijn sommige Pure Thermal‑exemplaren geleverd zonder de WINC1500‑module gemonteerd. Als network.WINC een fout genereert of nooit verbinding maakt, controleer dan of de print een ontbrekende Wi‑Fi‑module heeft — de rest van de camera werkt precies hetzelfde zonder deze module.

microSD‑kaart

Wanneer een kaart wordt geplaatst, wordt deze automatisch gekoppeld op /sdcard en is bruikbaar via het reguliere bestandssysteem:

import os

for entry in os.listdir("/sdcard"):
    print(entry)

Busreferentie

GPIO

Gebruik machine.Pin om een van de bedrukte pinnen te lezen of aan te sturen. Uitgangen zijn 3.3 V CMOS, 5 V‑tolerant aan de ingangszijde, en kunnen tot 25 mA per pin opnemen/leveren (120 mA totaal over de hele 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())

Elke ingangspin kan ook een interrupt afvuren bij randovergangen:

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

Dezelfde hardware kan ook in target‑modus (slave) worden gebruikt via machine.I2CTarget om een geheugengebied beschikbaar te maken voor een andere I²C‑controller:

from machine import I2CTarget

buf = bytearray(32)
target = I2CTarget(2, addr=0x42, mem=buf)

De Qwiic‑connector op de print maakt een van deze I²C‑bussen beschikbaar voor plug‑and‑play‑modules. De Qwiic‑lijn wordt via open‑drain‑transistors niveauverschoven naar 5 V, dus de bus is beperkt tot alleen standaardmodus (100 kHz) en fast mode (400 kHz) — probeer geen fast‑mode‑plus of hogere snelheden via de Qwiic‑header te draaien.

De Qwiic‑connector levert 5 V om aangesloten modules te voeden; hij kan niet worden gebruikt om de Pure Thermal zelf te voeden — voed de print in plaats daarvan via USB‑C of de LiPo‑batterijconnector.

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 en DAC

P6 is de enige analoge pin voor de gebruiker. Hij kan worden gebruikt als een 12‑bits ADC‑ingang of als een DAC‑uitgang.

  • ADC — volledige schaal bij 3.3 V op de 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 — via pyb.DAC. De 8‑bits waarde beslaat 0–3.3 V:

    from pyb import DAC
    
    dac = DAC("P6")
    voltage = 1.65
    dac.write(int(voltage / 3.3 * 255))
    

In ADC‑ of DAC‑modus is P6 alleen 3.3 V‑tolerant — voer er geen 5 V op.

PWM

Pin

Timer / kanaal

P4

TIM2 CH3

P5

TIM2 CH4

P6

TIM2 CH1

P7

TIM4 CH1

P8

TIM4 CH2

Notitie

TIM1 is gereserveerd door de firmware om de pixelklok van de camerasensor te genereren, dus de TIM1‑kanalen die fysiek op P0/P1/P2 zitten, kunnen niet voor gebruikers‑PWM worden gebruikt zonder de camera te verstoren.

TIM4 wordt gedeeld met pyb.Servo — het instantiëren van een servo herconfigureert de hele timer voor 50 Hz‑werking, meng dus geen machine.PWM op P7/P8 met pyb.Servo in hetzelfde script.

Stuur er een aan via machine.PWM

from machine import Pin, PWM

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

Softwarematige bit‑banged bussen

machine.SoftI2C en machine.SoftSPI werken op elke GPIO als je een extra bus nodig hebt.

Thermische sensor (extern)

Naast de FLIR Lepton op de print bevat de firmware ook de fir — thermische sensor-driver (fir == far infrared)‑driver voor extern bedrade I²C thermische beeldsensoren:

  • MLX90621 — 16 × 4 IR‑array

  • MLX90640 — 32 × 24 IR‑array

  • MLX90641 — 16 × 12 IR‑array

  • AMG8833 — 8 × 8 IR‑array

Bedraad de module naar de I²C‑bus van de print en lees frames met 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())

De fir‑driver communiceert alleen met de sensor via I²C 2 — bedraad de module naar P4 (SCL) en 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)

Virtuele timers

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

Periodewaarden zijn in milliseconden. Roep deinit() aan om te stoppen en de slot vrij te geven.

Real‑time klok

from machine import RTC

rtc = RTC()
rtc.datetime((2026, 4, 30, 4, 12, 0, 0, 0))
print(rtc.datetime())

Als er een LiPo‑batterij is aangesloten, houdt de RTC de tijd bij, zelfs terwijl de systeemrails uit staan (uitgeschakeld via de aan/uit‑knop op de print). Met alleen USB aangesloten, snijdt het indrukken van de aan/uit‑knop ook de voeding naar de RTC af — de kloktijd overleeft dus geen voedingscyclus zonder aangesloten batterij.

Watchdog

from machine import WDT

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

Boot‑ en runtime‑informatie

USB‑bootloadervenster

Bij elke inschakeling draait de camera een korte bootloader (een paar seconden) waarmee OpenMV IDE de firmware kan bijwerken zonder dat de gebruiker DFU‑modus hoeft te activeren. Nadat het venster verloopt, draagt de bootloader over aan boot.py en vervolgens main.py.

Een draaiend script kan op verzoek de bootloader opnieuw activeren door machine.bootloader() aan te roepen.

Bestandssysteem en bootvolgorde

De Pure Thermal‑firmware koppelt bij het opstarten maximaal drie bestandssystemen:

  • Intern flashgeheugen — altijd gekoppeld op /flash. Bevat standaard main.py en README.txt; aangemaakt bij de allereerste boot.

  • microSD‑kaart — als er een kaart is geplaatst, wordt deze gekoppeld op /sdcard.

  • ROMFS — alleen‑lezen, in het geheugen gemapt bestandssysteem op /rom, gebruikt om grote data‑assets (bijv. AI‑modellen) te leveren die baat hebben bij zero‑copy‑toegang. Wordt automatisch door MicroPython bij het opstarten gekoppeld, voordat enige gebruikers‑Python draait.

Na het koppelen wordt de werkmap ingesteld op /sdcard wanneer de kaart aanwezig is, anders /flash. De interpreter draait vervolgens scripts vanuit die map:

  • boot.py wordt bij elke soft reset uitgevoerd.

  • main.py wordt alleen bij een koude start uitgevoerd, direct na boot.py.

Het plaatsen van een boot.py of main.py op de SD‑kaart overschrijft de kopie in het flashgeheugen zonder deze aan te raken.

Wanneer verbonden via USB, wordt het boot‑bestandssysteem (/sdcard als er een kaart aanwezig is, anders /flash) ook op de host opgesomd als een USB‑massaopslagstation. Werp het station uit voordat je de camera reset zodat de host zijn gecachete schrijfacties wegschrijft.

Notitie

Bestanden die zijn aangemaakt of gewijzigd door code die op de OpenMV Cam draait, verschijnen pas op de host nadat het station opnieuw is gekoppeld. Gebruik de SD‑kaart voor alle data die het script terugschrijft, en koppel opnieuw voordat je die bestanden vanaf de host leest.

Opslaggroottes

De Pure Thermal wordt geleverd met:

  • /flash24 MB FAT‑bestandssysteem, lezen/schrijven.

  • /rom8 MB alleen‑lezen, in het geheugen gemapt ROMFS, gebruikt om scripts en ML‑modellen te leveren die baat hebben bij zero‑copy mmap‑toegang.

  • /sdcard — volledige grootte van de geplaatste microSD‑kaart (indien aanwezig), lezen/schrijven.

Hard‑fault‑indicator

Als de RGB‑gebruikers‑LED snel door alle kleuren cyclet — snel genoeg dat het meer lijkt op een flikkerende witte LED dan op afzonderlijke kleurtinten — heeft de firmware een onherstelbare hard fault opgelopen. Flash de firmware opnieuw om te herstellen.

Hardware‑errata

Een handvol eigenaardigheden op printniveau is gedocumenteerd in de Pure Thermal hardware‑errata. Belangrijke punten om rekening mee te houden:

  • Interferentie met batterijconnector — componenten op de PCB bevinden zich direct onder de LiPo‑batterijconnector, en de uitstekende wig op de stekker van de batterijkabel kan eraan blijven haken bij het verwijderen van de kabel, waardoor soms onderdelen van de print worden getrokken. Knip de wig van de kabelstekker af met een zijkniptang vóór het eerste gebruik.

  • RTC stopt terwijl de print uit staat — de belastingscapaciteit op het 32 kHz‑kristal (Y2) is te hoog. Het verwijderen van C96 en C97 (het paar dat het kristal naast de STM32 flankeert) zorgt ervoor dat de RTC op back‑upvoeding blijft draaien. De meeste prints worden geleverd met deze condensatoren al verwijderd; als je RTC de tijd verliest wanneer deze losgekoppeld is, controleer dan die posities. Zie GitHub‑issues #1536 en #1600 voor de volledige discussie.

  • Oplaad‑indicator‑LED blijft blauw — de oplader kan zijn oplaadcyclus ergens tussen 4.15 V en 4.19 V beëindigen zonder de indicator van blauw (bezig met opladen) naar groen (opgeladen) te wisselen. De batterij is in dit geval nog steeds volledig opgeladen; vertrouw op een spanningsmeting, niet op de LED.

  • Bedrukking labelt VIN verkeerd als VBAT — de pad op de standaard VIN‑positie van de OpenMV‑header is op de Pure Thermal bedrukt met VBAT. Het label is fout, maar dat maakt in de praktijk niet uit omdat de pad hoe dan ook geen elektrische verbinding heeft.

Softwarebibliotheken

Zie de bibliotheekindex voor de volledige lijst met modules — inclusief welke uniek zijn voor de Pure Thermal‑build.