OpenMV Pure Thermal¶
OpenMV Pure Thermal är ett komplett kort för termisk avbildning byggt kring STMicroelectronics STM32H743 (Cortex‑M7 @ 480 MHz) med 64 MB externt SDRAM, 32 MB QSPI‑flashminne, en hårdvaru‑JPEG‑codec, en 4,3” 800×480 IPS kapacitiv pekskärm, en HDMI‑utgång, en FLIR® Lepton® termisk sockel och en 5MP OV5640‑kamera för synligt ljus. Det rymmer även Wi‑Fi, en microSD‑sockel, en laseravståndsmätare, en summer och en högeffektsbelysning med vitt ljus.
För fullständigt datablad, bilder och mått, se produktsidan för OpenMV Pure Thermal.
Höjdpunkter¶
STMicroelectronics STM32H743XI Cortex‑M7 på 480 MHz.
Hårdvaru‑JPEG‑kodare/avkodare.
64 MB externt SDRAM (~400 MB/s) plus 1 MB internt SRAM.
2 MB internt flashminne + 32 MB externt QSPI‑flashminne (~50 MB/s läsning).
OV5640 5MP rolling‑shutter‑sensor för synligt ljus.
FLIR® Lepton®‑sockel — accepterar valfri Lepton 1/2/2.5/3/3.5‑modul, radiometrisk eller icke‑radiometrisk, med temperatur per pixel i grader Celsius.
4,3” 800×480 IPS kapacitiv pekskärm (24‑bitars färg @ 60 Hz) med stöd för upp till 5‑punktsgester.
HDMI‑utgång via TFP410 DVI‑serialiserare — upp till 1280×720 @ 60 Hz.
Wi‑Fi via WINC1500; MJPEG över RTSP stöds direkt.
Full‑speed USB‑C (12 Mb/s, strömbegränsad till 900 mA) — visas som VCP + USB‑masslagring för värddatorn och hanterar även laddning.
microSD‑sockel — SD upp till 2 GB, SDHC upp till 32 GB, SDXC upp till 2 TB.
VL53L1CX laseravståndsmätare (upp till ~4 m).
Summer med programvarustyrd volym/frekvens.
Högeffekts vit LED‑belysning utöver den användarstyrda RGB‑status‑LED:en.
LiPo‑batterikontakt med USB‑laddning vid 500 mA.
10 I/O‑stift, 5 V‑toleranta med 3,3 V‑utgång, 25 mA per stift (120 mA totalt), avbrottskapabla. P6 är inte 5 V‑tolerant när det används i ADC‑ eller DAC‑läge.
ARM 10‑stifts SWD‑kontakt för ST‑LINK‑/J‑Link‑felsökning.
Qwiic‑kontakt för I²C‑kringutrustning.
Anteckning
Kortet har ett spår på sin nedre vänstra kant för en valfri ¼”–20 stativmutter. Den är inte monterad från fabrik — löd fast en i spåret om du vill montera kortet på ett vanligt kamerastativ.
Stiftschema¶
Stiftreferens¶
Stiftnamn |
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 |
digital I/O |
RESET |
dra till GND för att återställa kortet |
SYN |
bildsynkpad — inte ansluten |
VIN |
shield VIN‑pad — inte ansluten |
BOOT0 |
dra till 3,3 V vid påslagning för DFU‑/ROM‑startladdare |
BUZZER |
inbyggd piezosummer (driven av TIM2/PWM) |
LED_RED |
röd kanal på RGB‑status‑LED (aktiv låg) |
LED_GREEN |
grön kanal på RGB‑status‑LED (aktiv låg) |
LED_BLUE |
blå kanal på RGB‑status‑LED (aktiv låg) |
LED_WHITE |
högeffekts vit belysnings‑LED |
Anteckning
Padarna SYN och VIN på shieldet/headern har ingen elektrisk anslutning på Pure Thermal — de finns där enbart för header‑kompatibilitet. Driv i stället kortet via USB‑C eller den inbyggda LiPo‑batterikontakten (se Strömstift nedan). Observera också att VIN‑paden är silkscreenmärkt VBAT på kortet (ett märkningsfel) — positionen är det standardiserade OpenMV‑header‑VIN‑stiftet och är inte anslutet i något fall.
Strömstift¶
3.3V — reglerad 3,3 V‑skena. Upp till 250 mA tillgängligt för shields.
GND — gemensam jord.
Pure Thermal drivs via USB‑C eller den inbyggda LiPo‑batterikontakten. USB‑C‑porten är strömbegränsad till totalt 900 mA och hanterar även LiPo‑laddning vid 500 mA, så att ansluta ett batteri samtidigt som USB stöds.
Den inbyggda strömknappen slår på och av systemskenorna och fungerar oavsett om kortet drivs från USB eller från LiPo:n. Håll in knappen i ett par sekunder för att byta tillstånd — en snabb tryckning ignoreras för att förhindra oavsiktlig avstängning.
Källval följer två enkla regler:
Batteriet driver endast kortet när dess spänning är över 3 V. Under den gränsen kopplar den inbyggda PMIC:en bort batteriet för att skydda det mot överurladdning.
När USB är anslutet driver USB kortet och en eventuellt ansluten LiPo laddas i bakgrunden.
LiPo‑kontakten har också omvänd‑spänningsskydd, så att ansluta batteriet bakvänt skadar inte kortet.
Anteckning
Kortet leder också tillbaka batterispänningen och en batteriströmsavkänningssignal till MCU:ns ADC‑kanaler, men firmware‑stöd för någondera har ännu inte lagts till.
Återställnings‑ och felsökningsstift¶
RESET — dra till GND för att återställa kortet. Pure Thermal har också en dedikerad RESET‑knapp på kortet som gör samma sak.
BOOT0 — dra till 3,3 V medan kortet får ström för att gå in i STM32 ROM‑startladdaren (DFU‑läge). OpenMV IDE använder detta läge för att flasha om den inbyggda startladdaren. En dedikerad BOOT0‑knapp på kortet gör samma sak — håll in den medan du slår på strömmen.
Kortet exponerar en SWD‑felsökningsheader (RST / SWCLK / SWDIO / SWO) bredvid GPIO‑headern, kompatibel med ST‑LINK‑ och SEGGER J‑Link‑adaptrar. En separat ARM 10‑stifts SWD‑kontakt är också monterad — den för samma SWD‑signaler (ingen fullständig JTAG) men i standardformatet 0,05” 10 stift.
Anteckning
Spårningsstiftet SWO delas med SPI‑klockan på den inbyggda FLIR® Lepton®. SWO kan inte användas samtidigt som Lepton — välj det ena eller det andra.
En tredje kontakt, PURE Modules Debug, är monterad på kortet. Den bryter ut en handfull felsökningsinriktade signaler (SWCLK, SWDIO, RST, SPI2_MISO, SPI2_MOSI, VBUS, 3,3 V, GND och två GPIO‑stift) för anslutning av tillbehörsmoduler. De två GPIO‑stiften på denna kontakt drivs av en intern bit‑bangad I²C‑buss snarare än av en hårdvarukringutrustning.
Alla tre felsökningskontakterna (den inbyggda SWD‑headern, ARM 10‑stifts SWD‑kontakten och PURE Modules Debug‑kontakten) är refererade till 3,3 V — se till att din felsökningsadapter är konfigurerad för 3,3 V‑logik innan du ansluter.
Inbyggd kringutrustning¶
LED:ar¶
Pure Thermal har tre LED:ar på kortet:
Användar‑RGB‑LED — programvarustyrd, exponerad som
LED_RED,LED_GREENochLED_BLUEfrom machine import LED LED("LED_RED").on() LED("LED_GREEN").on() LED("LED_BLUE").on()
Vit belysning — driven via
LED_WHITE.LED_WHITEär kopplad aktiv hög i hårdvara medan firmware behandlar alla andra inbyggda LED:ar som aktiv låg, så användlow()/high()snarare änon()/off()(vilket skulle invertera betydelsen):from machine import LED light = LED("LED_WHITE") light.low() # turn the white LED ON light.high() # turn the white LED OFF
Laddnings‑LED — driven direkt av den inbyggda strömhanteringshårdvaran, ingen programvarustyrning. Den fungerar oavsett om systemskenorna är på eller av (dvs. med strömknappen i endera läget).
Färg
Betydelse
Blå
laddar — se errata: kanske inte slocknar när laddningen är klar
Grön
laddning klar — se errata: kanske inte utlöses tillförlitligt
Röd
lågt batteri (≤ 3,2 V, endast när det inte aktivt laddas)
Summer¶
Den inbyggda piezosummern är kopplad till en timerkanal — driv den med machine.PWM för toner med programvarustyrd frekvens (tonhöjd) och pulskvot (volym):
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¶
OV5640 är den primära CSI:n på Pure Thermal — skicka cid=csi.OV5640 för att adressera den explicit:
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()
OV5640 har en inbyggd JPEG‑kompressor. Ställ in csi.CSI.pixformat till csi.JPEG så levererar sensorn komprimerade bildrutor direkt till kameran över kamerabussen, vilket gör högupplösta tagningar praktiska: csi.HD (1280×720), csi.FHD (1920×1080) och fulla 5MP csi.WQXGA2 (2592×1944) strömmas alla som JPEG. Justera komprimeringen med csi.CSI.quality (0‑100, högre = större bildrutor, mer detaljer):
cam.pixformat(csi.JPEG)
cam.framesize(csi.WQXGA2)
cam.quality(90)
OV5640 har en autofokuslins med röstspolaktuator (voice‑coil). Utlös en enstaka autofokuspassning via csi.CSI.ioctl med csi.IOCTL_TRIGGER_AUTO_FOCUS — sensorn sveper fokusmotorn en gång och låser på det som befinner sig framför den:
cam.ioctl(csi.IOCTL_TRIGGER_AUTO_FOCUS)
Skicka om ioctl närhelst scenen ändras — autofokus är engångs, inte kontinuerlig.
Anteckning
OV5640:s STROBE‑utgång (används för synkroniserad blixt/IR‑belysning) är kopplad till MCU:n på Pure Thermal, men firmware‑stöd för den har ännu inte lagts till.
Termisk kamerasensor¶
FLIR® Lepton®‑sockeln visas som en andra CSI på samma csi — kamerasensorer‑API. Skicka cid=csi.LEPTON för att adressera den, och hoppa över hårdvaruåterställningen:
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()
Anteckning
Lepton:s VSYNC‑utgång (en puls per termisk bildruta) är kopplad till MCU:n på Pure Thermal, men firmware‑stöd för den har ännu inte lagts till.
Båda CSI:erna kan köras sida vid sida. Exemplet nedan hämtar en färgbildruta från OV5640 och en termisk bildruta från Lepton, och lägger sedan Lepton ovanpå färgbildrutan med hjälp av en Ironbow‑palett och en alfamask som tonar ut till transparent vid låg intensitet:
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,
)
Maskininlärning¶
ml — Maskininlärning kör kvantiserade TFLite‑modeller på Cortex‑M7 med CMSIS‑NN‑kärnor — snabbt nog för kompakta detektorer vid några bildrutor per sekund. Modeller på det skrivskyddade filsystemet /rom laddas direkt från flashminnet utan att kopieras till RAM. Här är en 128×128 BlazeFace‑detektor som lägger det detekterade ansiktet och dess sex landmärken som överlägg på varje bildruta från kameran för synligt ljus:
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")
Laseravståndsmätare¶
Den inbyggda ST VL53L1CX time‑of‑flight‑avståndsmätaren är kopplad till I²C‑buss 2. Använd den frusna vl53l1x — Drivrutin för VL53L1X ToF-avståndssensor‑drivrutinen för att få avståndsavläsningar upp till ~4 m:
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‑utgång¶
Den inbyggda 4,3”‑LCD:n är 800 × 480 (WVGA) och drivs via RGB‑displaygränssnittet i display — display-drivrutin‑modulen — skicka framesize=display.FWVGA för att matcha dess inbyggda upplösning:
import display
lcd = display.RGBDisplay(framesize=display.FWVGA, refresh=60)
lcd.backlight(True) # turn the LCD backlight on
lcd.write(img)
Bakgrundsbelysningen är kopplad till en GPIO, så backlight() accepterar True / False (eller valfritt värde 0–100, där 0 är av och allt som inte är noll är på):
lcd.backlight(False) # turn the backlight off
lcd.backlight(True) # back on
Pekskärm¶
Den kapacitiva pekkontrollern är FT5X06; flerfingerspositioner och gesthändelser exponeras via ft5x06 — drivrutin för pekskärm. Registrera ett återanrop för att reagera på beröringar och läs de aktiva punkterna inuti det:
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‑utgång¶
Firmware skickar också ut LCD‑bildbufferten till den inbyggda HDMI‑serialiseraren tfp410 — DVI/HDMI-styrenhet, så att en extern bildskärm speglar det som visas på LCD:n. Instansiera tfp410.TFP410 för att aktivera HDMI‑utgången:
import tfp410
hdmi = tfp410.TFP410()
Om du bara vill ha HDMI‑utgång och inte bryr dig om den inbyggda LCD:n, stäng av bakgrundsbelysningen och höj bildbuffertens upplösning över WVGA. TFP410 stöder upp till 1280×720 @ 60 Hz, så till exempel:
lcd = display.RGBDisplay(framesize=display.HD, refresh=60)
lcd.backlight(False) # the on‑board LCD can't render HD
hdmi = tfp410.TFP410()
Den inbyggda panelen är fast på 800×480, så allt över WVGA är endast meningsfullt på den externa HDMI‑bildskärmen.
För att veta när en HDMI‑bildskärm har anslutits eller kopplats bort, registrera ett hot‑plug‑återanrop på TFP410. Återanropet utlöses med True vid anslutning och False vid frånkoppling:
def on_hotplug(connected):
print("HDMI", "connected" if connected else "disconnected")
hdmi.hotplug_callback(on_hotplug)
Du kan också när som helst läsa av anslutningstillståndet med isconnected() (endast när inget återanrop är registrerat).
HDMI‑porten för också kanalerna DDC (display data) och CEC (consumer electronics control), exponerade via klassen class DisplayData – Display-data. Använd den för att läsa den anslutna bildskärmens EDID‑block (så att du kan anpassa dig till dess inbyggda upplösning/uppdateringsfrekvens) eller för att skicka/ta emot CEC‑ramar för att styra andra HDMI‑enheter på samma ledning:
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 körs över en Microchip WINC1500‑modul, exponerad via class WINC – drivrutin för WiFi-sköld‑gränssnittet:
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])
Anteckning
På grund av komponentbrist levererades vissa Pure Thermal‑enheter utan WINC1500‑modulen monterad. Om network.WINC ger ett fel eller aldrig ansluter, kontrollera kortet för en saknad Wi‑Fi‑modul — resten av kameran fungerar exakt likadant utan den.
microSD‑kort¶
När ett kort sätts i monteras det automatiskt på /sdcard och kan användas via det vanliga filsystemet:
import os
for entry in os.listdir("/sdcard"):
print(entry)
Bussreferens¶
GPIO¶
Använd machine.Pin för att läsa eller driva något av de silkscreenmärkta stiften. Utgångar är 3,3 V CMOS, 5 V‑toleranta på inmatningssidan, och kan ta emot/leverera upp till 25 mA per stift (120 mA totalt över hela headern).
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())
Vilket inmatningsstift som helst kan också utlösa ett avbrott vid kantövergångar:
def handler(pin):
print("triggered:", pin)
Pin("P1", Pin.IN, Pin.PULL_UP).irq(
handler, Pin.IRQ_FALLING | Pin.IRQ_RISING,
)
UART¶
Buss |
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¶
Buss |
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")
Samma hårdvara kan också användas i target‑läge (slav) via machine.I2CTarget för att exponera ett minnesområde för en annan I²C‑styrenhet:
from machine import I2CTarget
buf = bytearray(32)
target = I2CTarget(2, addr=0x42, mem=buf)
Den inbyggda Qwiic‑kontakten bryter ut en av dessa I²C‑bussar för plug‑and‑play‑moduler. Qwiic‑linjen är nivåväxlad till 5 V via open‑drain‑transistorer, så bussen är begränsad till endast standardläge (100 kHz) och fast mode (400 kHz) — försök inte köra fast‑mode‑plus eller högre hastigheter genom Qwiic‑headern.
Qwiic‑kontakten levererar 5 V för att driva anslutna moduler; den kan inte användas för att driva själva Pure Thermal — driv i stället kortet via USB‑C eller LiPo‑batterikontakten.
SPI¶
Buss |
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)¶
Buss |
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 och DAC¶
P6 är det enda analoga användarstiftet. Det kan användas antingen som en 12‑bitars ADC‑ingång eller som en DAC‑utgång.
ADC — fullskala vid 3,3 V på stiftet:
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. Det 8‑bitars värdet täcker 0–3,3 V:from pyb import DAC dac = DAC("P6") voltage = 1.65 dac.write(int(voltage / 3.3 * 255))
I ADC‑ eller DAC‑läge är P6 endast 3,3 V‑tolerant — mata det inte med 5 V.
PWM¶
Stift |
Timer / kanal |
|---|---|
P4 |
TIM2 CH3 |
P5 |
TIM2 CH4 |
P6 |
TIM2 CH1 |
P7 |
TIM4 CH1 |
P8 |
TIM4 CH2 |
Anteckning
TIM1 är reserverad av firmware för att generera kamerasensorns pixelklocka, så de TIM1‑kanaler som fysiskt finns på P0/P1/P2 kan inte användas för användar‑PWM utan att förstöra kamerafunktionen.
TIM4 delas med pyb.Servo — att instansiera ett servo konfigurerar om hela timern för 50 Hz‑drift, så blanda inte machine.PWM på P7/P8 med pyb.Servo i samma skript.
Driv vilken som helst av dem via machine.PWM
from machine import Pin, PWM
pwm = PWM(Pin("P7"), freq=1_000, duty_u16=32768)
Programvaru‑bit‑bangade bussar¶
machine.SoftI2C och machine.SoftSPI fungerar på vilken GPIO som helst om du behöver en extra buss.
Termisk sensor (extern)¶
Utöver den inbyggda FLIR Lepton inkluderar firmware också fir — drivrutin för värmesensor (fir == far infrared)‑drivrutinen för externt kopplade I²C‑termiska avbildare:
MLX90621 — 16 × 4 IR‑array
MLX90640 — 32 × 24 IR‑array
MLX90641 — 16 × 12 IR‑array
AMG8833 — 8 × 8 IR‑array
Koppla modulen till kortets I²C‑buss och läs bildrutor med 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‑drivrutinen kommunicerar med sensorn endast över I²C 2 — koppla modulen till P4 (SCL) och P5 (SDA).
Tidssättning¶
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)
Virtuella 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"))
Periodvärden anges i millisekunder. Anropa deinit() för att stoppa och frigöra platsen.
Realtidsklocka¶
from machine import RTC
rtc = RTC()
rtc.datetime((2026, 4, 30, 4, 12, 0, 0, 0))
print(rtc.datetime())
Om ett LiPo‑batteri är anslutet håller RTC:n tiden även medan systemskenorna är avstängda (avstängda via den inbyggda strömknappen). Med endast USB anslutet bryter en tryckning på strömknappen även strömmen till RTC:n — så väggklockstiden kommer inte att överleva en strömcykling utan ett anslutet batteri.
Watchdog¶
from machine import WDT
wdt = WDT(timeout=5_000)
while True:
# ...do work...
wdt.feed()
Boot‑ och körtidsinformation¶
USB‑startladdarfönster¶
Vid varje påslagning kör kameran en kort startladdare (några sekunder) som låter OpenMV IDE uppdatera firmware utan att användaren behöver gå in i DFU‑läge. Efter att fönstret löpt ut lämnar startladdaren över till boot.py och sedan main.py.
Ett körande skript kan på begäran återgå till startladdaren genom att anropa machine.bootloader().
Filsystem och boot‑ordning¶
Pure Thermal‑firmware monterar upp till tre filsystem vid boot:
Internt flashminne — alltid monterat på
/flash. Innehållermain.pyochREADME.txtsom standard; skapas vid den allra första bootningen.microSD‑kort — om ett kort sätts i monteras det på
/sdcard.ROMFS — ett skrivskyddat, minnesmappat filsystem på
/romsom används för att leverera stora dataresurser (t.ex. AI‑modeller) som drar nytta av zero‑copy‑åtkomst. Monteras automatiskt av MicroPython vid uppstart, innan någon Python‑kod från användaren körs.
Efter monteringen sätts arbetskatalogen till /sdcard när kortet finns, annars /flash. Tolken kör sedan skript från den katalogen:
boot.pykörs vid varje mjuk återställning.main.pykörs endast vid kallstart, omedelbart efterboot.py.
Att lägga en boot.py eller main.py på SD‑kortet åsidosätter kopian i flashminnet utan att röra den.
Vid USB‑anslutning räknas boot‑filsystemet (/sdcard om ett kort finns, annars /flash) också upp som en USB‑masslagringsenhet på värddatorn. Mata ut enheten innan du återställer kameran så att värddatorn tömmer sina cachade skrivningar.
Anteckning
Filer som skapas eller ändras av kod som körs på OpenMV Cam kommer inte att synas på värddatorn förrän enheten monteras om. Använd SD‑kortet för all data som skriptet skriver tillbaka, och montera om innan du läser dessa filer från värddatorn.
Lagringsstorlekar¶
Pure Thermal levereras med:
/flash— 24 MB FAT‑filsystem, läs/skriv./rom— 8 MB skrivskyddat, minnesmappat ROMFS, används för att leverera skript och ML‑modeller som drar nytta av zero‑copy mmap‑åtkomst./sdcard— full storlek av vilket microSD‑kort som än sätts i (när det finns), läs/skriv.
Hard‑fault‑indikator¶
Om användar‑RGB‑LED:en snabbt cyklar genom alla färger — så snabbt att det tenderar att se ut som en glittrande vit LED snarare än distinkta färgtoner — har firmware drabbats av ett oåterkalleligt hard fault. Flasha om firmware för att återhämta dig.
Hårdvaru‑errata¶
En handfull egenheter på kortnivå dokumenteras i Pure Thermal hårdvaru‑errata. Viktiga punkter att vara medveten om:
Störning från batterikontakten — komponenter på kretskortet sitter direkt under LiPo‑batterikontakten, och den utskjutande kilen på batterikabelns kontakt kan fastna i dem när kabeln dras ut, vilket ibland drar loss delar från kortet. Trimma bort kilen från kabelkontakten med en avbitartång före första användning.
RTC:n stannar medan kortet är avstängt — lastkapacitansen på 32 kHz‑kristallen (Y2) är för hög. Att ta bort C96 och C97 (paret som flankerar kristallen bredvid STM32) gör att RTC:n kan fortsätta gå på backup‑ström. De flesta kort levereras med dessa kondensatorer redan borttagna; om din RTC tappar tid när den kopplas ur, kontrollera dessa positioner. Se GitHub‑ärendena #1536 och #1600 för hela tråden.
Laddningsindikator‑LED:en förblir blå — laddaren kan avsluta sin laddningscykel någonstans mellan 4,15 V och 4,19 V utan att växla indikatorn från blå (laddar) till grön (laddad). Batteriet är ändå fulladdat i detta fall; lita på en spänningsmätning, inte på LED:en.
Silkscreen märker felaktigt VIN som VBAT — paden i den standardiserade OpenMV‑header‑VIN‑positionen är silkscreenmärkt
VBATpå Pure Thermal. Märkningen är felaktig, men det spelar ingen roll i praktiken eftersom paden har ingen elektrisk anslutning i något fall.
Programvarubibliotek¶
Se biblioteksindex för den fullständiga listan över moduler — inklusive vilka som är unika för Pure Thermal‑bygget.