OpenMV Pure Thermal¶
ה‑OpenMV Pure Thermal הוא לוח דימות תרמי של מערכת שלמה הבנוי סביב STM32H743 של STMicroelectronics (Cortex‑M7 ב‑480 MHz) עם 64 MB של SDRAM חיצוני, 32 MB של זיכרון פלאש (flash) מסוג QSPI, מקודד JPEG חומרתי, מסך מגע קיבולי IPS בגודל ”4.3 ברזולוציית 800×480, יציאת HDMI, שקע תרמי FLIR® Lepton®, ומצלמת אור נראה OV5640 ברזולוציית 5MP. הוא כולל גם Wi‑Fi, שקע microSD, מד טווח בלייזר, זמזם, ומאיר לבן בעוצמה גבוהה.
לדף הנתונים המלא, תמונות, ומידות ראו את דף המוצר OpenMV Pure Thermal.
עיקרי הדברים¶
STMicroelectronics STM32H743XI Cortex‑M7 ב‑480 MHz.
מקודד/מפענח JPEG חומרתי.
64 MB SDRAM חיצוני (כ‑400 MB/s) בתוספת 1 MB SRAM פנימי.
2 MB זיכרון פלאש (flash) פנימי + 32 MB זיכרון פלאש (flash) חיצוני מסוג QSPI (קריאה כ‑50 MB/s).
חיישן אור נראה OV5640 ברזולוציית 5MP מסוג rolling‑shutter.
שקע FLIR® Lepton® — מקבל כל מודול Lepton 1/2/2.5/3/3.5, רדיומטרי או לא‑רדיומטרי, עם טמפרטורה לכל פיקסל במעלות צלזיוס.
מסך מגע קיבולי IPS בגודל ”4.3 ברזולוציית 800×480 (צבע 24‑סיביות ב‑60 Hz) עם תמיכה במחוות של עד 5 נקודות.
יציאת HDMI דרך הסריאלייזר TFP410 DVI — עד 1280×720 ב‑60 Hz.
Wi‑Fi דרך WINC1500; תמיכה ב‑MJPEG מעל RTSP מהקופסה.
USB‑C במהירות מלאה (12 Mb/s, מוגבל לזרם של 900 mA) — מופיע אצל המארח כ‑VCP + התקן אחסון USB, ומטפל גם בטעינה.
שקע microSD — SD עד 2 GB, SDHC עד 32 GB, SDXC עד 2 TB.
מד טווח בלייזר VL53L1CX (עד כ‑4 מ«).
זמזם עם עוצמה / תדר הנשלטים בתוכנה.
LED מאיר לבן בעוצמה גבוהה בנוסף ל‑LED הסטטוס RGB של המשתמש.
מחבר סוללת LiPo עם טעינת USB ב‑500 mA.
10 פיני I/O, סבילים ל‑5 V עם פלט של 3.3 V, 25 mA לכל פין (120 mA בסך הכול), בעלי יכולת פסיקה. P6 אינו סביל ל‑5 V כשהוא בשימוש במצב ADC או DAC.
מחבר ARM 10‑pin SWD לניפוי שגיאות עם ST‑LINK / J‑Link.
מחבר Qwiic להתקנים היקפיים מסוג I²C.
הערה
ללוח יש חריץ בקצה השמאלי‑תחתון שלו עבור אום חצובה אופציונלי מסוג ”¼–20. הוא אינו מותקן מהמפעל — הלחימו אחד בתוך החריץ אם ברצונכם להתקין את הלוח על חצובת מצלמה סטנדרטית.
מפרט פינים¶
מדריך פינים¶
שם הפין |
פונקציה |
|---|---|
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 |
I/O דיגיטלי |
RESET |
משכו ל‑GND כדי לאפס את הלוח |
SYN |
פד frame‑sync — לא מחובר |
VIN |
פד VIN של מגן — לא מחובר |
BOOT0 |
משכו ל‑3.3 V בעת הפעלה עבור DFU / מאתחל (bootloader) ROM |
BUZZER |
זמזם פיזואלקטרי מובנה (מונע על ידי TIM2/PWM) |
LED_RED |
ערוץ אדום של LED הסטטוס RGB (פעיל נמוך) |
LED_GREEN |
ערוץ ירוק של LED הסטטוס RGB (פעיל נמוך) |
LED_BLUE |
ערוץ כחול של LED הסטטוס RGB (פעיל נמוך) |
LED_WHITE |
LED מאיר לבן בעוצמה גבוהה |
הערה
לפדים SYN ו‑VIN במגן/בכותרת אין חיבור חשמלי ב‑Pure Thermal — הם קיימים רק לצורך תאימות כותרת. הזינו את הלוח דרך USB‑C או דרך מחבר סוללת ה‑LiPo המובנה במקום זאת (ראו פיני מתח להלן). שימו לב גם כי פד ה‑VIN מסומן בהדפס VBAT על הלוח (טעות תיוג) — המיקום הוא פין ה‑VIN הסטנדרטי של כותרת OpenMV ובכל מקרה אינו מחובר.
פיני מתח¶
3.3V — פס 3.3 V מיוצב. עד 250 mA זמינים עבור מגנים.
GND — הארקה משותפת.
ה‑Pure Thermal מוזן דרך USB‑C או דרך מחבר סוללת ה‑LiPo המובנה. יציאת ה‑USB‑C מוגבלת לזרם של 900 mA בסך הכול ומטפלת גם בטעינת ה‑LiPo ב‑500 mA, כך שחיבור סוללה במקביל ל‑USB נתמך.
כפתור ההפעלה המובנה מחליף את פסי המערכת בין מופעל לכבוי ופועל בין אם הלוח מוזן מ‑USB ובין אם מה‑LiPo. החזיקו את הכפתור למשך כמה שניות כדי לשנות מצב — לחיצה קצרה מתעלמים ממנה כדי למנוע כיבוי בשוגג.
בחירת המקור פועלת לפי שני כללים פשוטים:
הסוללה מזינה את הלוח רק כאשר מתחה מעל 3 V. מתחת לסף זה ה‑PMIC המובנה מנתק את הסוללה כדי להגן עליה מפני פריקת יתר.
כאשר USB נוכח, ה‑USB מזין את הלוח וכל LiPo מחובר נטען ברקע.
מחבר ה‑LiPo כולל גם הגנה מפני מתח הפוך, כך שחיבור הסוללה הפוך לא יגרום נזק ללוח.
הערה
הלוח גם מנתב את מתח הסוללה ואות חישת זרם הסוללה חזרה לערוצי ה‑ADC של ה‑MCU, אך תמיכת קושחה עבור אף אחד מהם טרם נוספה.
פיני שחזור וניפוי שגיאות¶
RESET — משכו ל‑GND כדי לאפס את הלוח. ל‑Pure Thermal יש גם כפתור RESET ייעודי על הלוח שעושה את אותו הדבר.
BOOT0 — משכו ל‑3.3 V בעת הזנת הלוח כדי להיכנס למאתחל (bootloader) ה‑ROM של ה‑STM32 (מצב DFU). OpenMV IDE משתמש במצב זה כדי לבצע flash מחדש למאתחל המובנה. כפתור BOOT0 ייעודי על הלוח עושה את אותו הדבר — החזיקו אותו תוך כדי הזנת המתח.
הלוח חושף כותרת ניפוי שגיאות SWD (RST / SWCLK / SWDIO / SWO) לצד כותרת ה‑GPIO, תואמת למתאמי ST‑LINK ו‑SEGGER J‑Link. מותקן גם מחבר נפרד ARM 10‑pin SWD — הוא נושא את אותם אותות SWD (ללא JTAG מלא) אך בתצורת 0.05“ 10‑pin הסטנדרטית.
הערה
פין המעקב SWO משותף עם שעון ה‑SPI של ה‑FLIR® Lepton® המובנה. לא ניתן להשתמש ב‑SWO בו זמנית עם ה‑Lepton — בחרו אחד מהשניים.
מחבר שלישי PURE Modules Debug מותקן על הלוח. הוא חושף קומץ אותות מוכווני ניפוי שגיאות (SWCLK, SWDIO, RST, SPI2_MISO, SPI2_MOSI, VBUS, 3.3 V, GND, ושני פיני GPIO) לחיבור מודולים נלווים. שני פיני ה‑GPIO במחבר זה מונעים על ידי אפיק I²C פנימי במימוש bit‑banged ולא על ידי התקן היקפי חומרתי.
כל שלושת מחברי ניפוי השגיאות (כותרת ה‑SWD המוטמעת, מחבר ה‑ARM 10‑pin SWD, ומחבר ה‑PURE Modules Debug) מתייחסים ל‑3.3 V — ודאו שמתאם ניפוי השגיאות שלכם מוגדר ללוגיקת 3.3 V לפני החיבור.
התקנים היקפיים מובנים¶
נוריות LED¶
ל‑Pure Thermal יש שלוש נוריות LED על הלוח:
LED RGB של המשתמש — נשלט בתוכנה, חשוף כ‑
LED_RED,LED_GREENו‑LED_BLUEfrom machine import LED LED("LED_RED").on() LED("LED_GREEN").on() LED("LED_BLUE").on()
מאיר לבן — מונע דרך
LED_WHITE.LED_WHITEמחווט פעיל גבוה בחומרה בעוד שהקושחה מתייחסת לכל LED מובנה אחר כאל פעיל נמוך, לכן השתמשו ב‑low()/high()במקום ב‑on()/off()(אשר היו הופכים את ההיגיון):from machine import LED light = LED("LED_WHITE") light.low() # turn the white LED ON light.high() # turn the white LED OFF
LED טעינה — מונע ישירות על ידי חומרת ניהול המתח המובנית, ללא שליטה תוכנתית. הוא פועל בין אם פסי המערכת מופעלים או כבויים (כלומר עם כפתור ההפעלה בכל אחד מהמצבים).
צבע
משמעות
כחול
טעינה — ראו עררטה: ייתכן שלא יכבה כשהטעינה מסתיימת
ירוק
הטעינה הושלמה — ראו עררטה: ייתכן שלא יופעל באופן אמין
אדום
סוללה חלשה (≤ 3.2 V, רק כשאינה בטעינה פעילה)
זמזם¶
הזמזם הפיזואלקטרי המובנה מחווט לערוץ טיימר — הניעו אותו עם machine.PWM עבור צלילים עם תדר (גובה צליל) ומחזור פעולה (עוצמה) הנשלטים בתוכנה:
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()
חיישן המצלמה¶
ה‑OV5640 הוא ה‑CSI הראשי ב‑Pure Thermal — העבירו cid=csi.OV5640 כדי לפנות אליו במפורש:
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 יש מדחס JPEG מובנה. הגדירו את csi.CSI.pixformat ל‑csi.JPEG והחיישן מספק פריימים דחוסים ישירות למצלמה דרך אפיק המצלמה, מה שהופך צילומים ברזולוציה גבוהה למעשיים: csi.HD (1280×720), csi.FHD (1920×1080), וה‑5MP המלא csi.WQXGA2 (2592×1944) כולם משודרים כ‑JPEG. כווננו את הדחיסה עם csi.CSI.quality (0-100, גבוה יותר = פריימים גדולים יותר, יותר פירוט):
cam.pixformat(csi.JPEG)
cam.framesize(csi.WQXGA2)
cam.quality(90)
ל‑OV5640 יש עדשת מיקוד אוטומטי המופעלת על ידי סליל קולי. הפעילו מעבר מיקוד אוטומטי בודד דרך csi.CSI.ioctl עם csi.IOCTL_TRIGGER_AUTO_FOCUS — החיישן מסרוק את מנוע המיקוד פעם אחת ונועל על מה שנמצא מולו:
cam.ioctl(csi.IOCTL_TRIGGER_AUTO_FOCUS)
הוציאו את ה‑ioctl מחדש בכל פעם שהסצנה משתנה — המיקוד האוטומטי הוא חד‑פעמי, לא רציף.
הערה
פלט ה‑STROBE של ה‑OV5640 (המשמש לפלאש / תאורת IR מסונכרנים) מחווט ל‑MCU ב‑Pure Thermal, אך תמיכת קושחה עבורו טרם נוספה.
חיישן מצלמה תרמית¶
שקע ה‑FLIR® Lepton® מופיע כ‑CSI שני באותו ה‑API של csi — חיישני מצלמה. העבירו cid=csi.LEPTON כדי לפנות אליו, ודלגו על איפוס החומרה:
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()
הערה
פלט ה‑VSYNC של ה‑Lepton (פולס אחד לכל פריים תרמי) מחווט ל‑MCU ב‑Pure Thermal, אך תמיכת קושחה עבורו טרם נוספה.
שני ה‑CSI יכולים לפעול זה לצד זה. הדוגמה שלהלן מושכת פריים צבעוני מה‑OV5640 ופריים תרמי מה‑Lepton, ואז מניחה את ה‑Lepton מעל הפריים הצבעוני בשכבת על באמצעות פלטת Ironbow ומסכת אלפא הדועכת לשקיפות בעוצמות נמוכות:
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,
)
למידת מכונה¶
ml — למידת מכונה מריץ מודלים מסוג TFLite מקוונטים על ה‑Cortex‑M7 עם גרעיני CMSIS‑NN — מהיר מספיק עבור מזהים קומפקטיים בכמה פריימים לשנייה. מודלים על מערכת הקבצים לקריאה בלבד /rom נטענים ישירות מהזיכרון פלאש (flash) ללא העתקה ל‑RAM. הנה מזהה BlazeFace בגודל 128×128 המניח בשכבת על את הפנים שזוהו ואת ששת נקודות הציון שלהן על כל פריים ממצלמת האור הנראה:
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")
מד טווח בלייזר¶
מד הטווח מסוג time‑of‑flight VL53L1CX של ST המובנה מחווט ל‑אפיק I²C 2. השתמשו במנהל ההתקן הקפוא vl53l1x — מנהל התקן לחיישן מרחק VL53L1X ToF כדי לקבל קריאות מרחק עד כ‑4 מ«:
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¶
ה‑LCD המובנה בגודל ”4.3 הוא 800 × 480 (WVGA) ומונע דרך ממשק תצוגת ה‑RGB של מודול display — מנהל התקן תצוגה — העבירו framesize=display.FWVGA כדי להתאים לרזולוציה המקורית שלו:
import display
lcd = display.RGBDisplay(framesize=display.FWVGA, refresh=60)
lcd.backlight(True) # turn the LCD backlight on
lcd.write(img)
התאורה האחורית מחווטת ל‑GPIO, כך ש‑backlight() מקבל True / False (או כל ערך 0–100, כאשר 0 הוא כבוי וכל ערך שאינו אפס הוא מופעל):
lcd.backlight(False) # turn the backlight off
lcd.backlight(True) # back on
מסך מגע¶
בקר המגע הקיבולי הוא FT5X06; מיקומי מגע מרובה ואירועי מחוות חשופים דרך ft5x06 — מנהל התקן למסך מגע. רשמו פונקציית callback כדי להגיב למגעים ולקרוא את הנקודות הפעילות בתוכה:
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¶
הקושחה גם מפיצה את חוצץ הפריימים (frame buffer) של ה‑LCD אל הסריאלייזר HDMI מסוג tfp410 — בקר DVI/HDMI המובנה, כך שצג חיצוני משקף את מה שמוצג על ה‑LCD. צרו מופע של tfp410.TFP410 כדי לאפשר את פלט ה‑HDMI:
import tfp410
hdmi = tfp410.TFP410()
אם אתם רוצים רק פלט HDMI ולא אכפת לכם מה‑LCD המובנה, כבו את התאורה האחורית והעלו את רזולוציית חוצץ הפריימים (frame buffer) מעל WVGA. ה‑TFP410 תומך בעד 1280×720 ב‑60 Hz, כך שלמשל:
lcd = display.RGBDisplay(framesize=display.HD, refresh=60)
lcd.backlight(False) # the on‑board LCD can't render HD
hdmi = tfp410.TFP410()
הפאנל המובנה קבוע ב‑800×480, כך שכל דבר מעל WVGA משמעותי רק על צג ה‑HDMI החיצוני.
כדי לדעת מתי צג HDMI חובר או נותק, רשמו פונקציית callback של hot‑plug על ה‑TFP410. ה‑callback מופעל עם True בעת חיבור ו‑False בעת ניתוק:
def on_hotplug(connected):
print("HDMI", "connected" if connected else "disconnected")
hdmi.hotplug_callback(on_hotplug)
ניתן גם לבדוק את מצב החיבור בכל עת באמצעות isconnected() (רק כאשר לא רשומה פונקציית callback).
יציאת ה‑HDMI נושאת גם את ערוצי ה‑DDC (נתוני תצוגה) וה‑CEC (בקרת מוצרי אלקטרוניקה צרכנית), החשופים דרך המחלקה class DisplayData – נתוני תצוגה. השתמשו בה כדי לקרוא את בלוק ה‑EDID של הצג המחובר (כך שתוכלו להסתגל לרזולוציה / קצב הרענון המקוריים שלו) או כדי לשלוח/לקבל פריימים של CEC לשליטה בהתקני HDMI אחרים על אותו החוט:
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 פועל מעל מודול WINC1500 של Microchip, החשוף דרך ממשק class WINC – מנהל התקן של מגן WiFi
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])
הערה
עקב מחסור ברכיבים, חלק מיחידות ה‑Pure Thermal נשלחו ללא מודול WINC1500 מאוכלס. אם network.WINC מעלה שגיאה או לעולם אינו מתחבר, בדקו אם חסר מודול Wi‑Fi בלוח — שאר המצלמה עובדת בדיוק באותו האופן בלעדיו.
כרטיס microSD¶
כאשר מוכנס כרטיס הוא מותקן אוטומטית ב‑/sdcard וניתן לשימוש דרך מערכת הקבצים הרגילה:
import os
for entry in os.listdir("/sdcard"):
print(entry)
מדריך אפיקים¶
GPIO¶
השתמשו ב‑machine.Pin כדי לקרוא או להניע כל אחד מהפינים המסומנים בהדפס. הפלטים הם 3.3 V CMOS, סבילים ל‑5 V בצד הקלט, ויכולים לשקוע/לספק עד 25 mA לכל פין (120 mA בסך הכול על פני כל הכותרת).
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())
כל פין קלט יכול גם להפעיל פסיקה במעברי קצה:
def handler(pin):
print("triggered:", pin)
Pin("P1", Pin.IN, Pin.PULL_UP).irq(
handler, Pin.IRQ_FALLING | Pin.IRQ_RISING,
)
UART¶
אפיק |
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¶
אפיק |
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")
ניתן להשתמש באותה חומרה גם במצב יעד (slave) דרך machine.I2CTarget כדי לחשוף אזור זיכרון לבקר I²C אחר:
from machine import I2CTarget
buf = bytearray(32)
target = I2CTarget(2, addr=0x42, mem=buf)
מחבר ה‑Qwiic המובנה חושף אחד מאפיקי ה‑I²C הללו עבור מודולים מסוג plug‑and‑play. קו ה‑Qwiic מוסט ברמה ל‑5 V דרך טרנזיסטורים מסוג open‑drain, כך שהאפיק מוגבל ל‑מצב סטנדרטי (100 kHz) ול‑מצב מהיר (400 kHz) בלבד — אל תנסו להריץ fast‑mode‑plus או קצבים גבוהים יותר דרך כותרת ה‑Qwiic.
מחבר ה‑Qwiic מוציא 5 V כדי להזין מודולים מחוברים; הוא אינו יכול לשמש להזנת ה‑Pure Thermal עצמו — הזינו את הלוח דרך USB‑C או דרך מחבר סוללת ה‑LiPo במקום זאת.
SPI¶
אפיק |
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)¶
אפיק |
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 ו‑DAC¶
P6 הוא פין האנלוג היחיד של המשתמש. ניתן להשתמש בו כקלט ADC של 12‑סיביות או כפלט DAC.
ADC — קנה מידה מלא ב‑3.3 V בפין:
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 — דרך
pyb.DAC. הערך של 8‑סיביות מכסה 0–3.3 V:from pyb import DAC dac = DAC("P6") voltage = 1.65 dac.write(int(voltage / 3.3 * 255))
במצב ADC או DAC, P6 הוא סביל ל‑3.3 V בלבד — אל תזינו אליו 5 V.
PWM¶
פין |
טיימר / ערוץ |
|---|---|
P4 |
TIM2 CH3 |
P5 |
TIM2 CH4 |
P6 |
TIM2 CH1 |
P7 |
TIM4 CH1 |
P8 |
TIM4 CH2 |
הערה
TIM1 שמור על ידי הקושחה ליצירת שעון הפיקסלים של חיישן המצלמה, כך שלא ניתן להשתמש בערוצי TIM1 הנמצאים פיזית על P0/P1/P2 עבור PWM של המשתמש מבלי לשבש את המצלמה.
TIM4 משותף עם pyb.Servo — יצירת מופע של servo מגדירה מחדש את כל הטיימר לפעולה ב‑50 Hz, לכן אל תערבבו machine.PWM על P7/P8 עם pyb.Servo באותו הסקריפט.
הניעו כל אחד מהם דרך machine.PWM
from machine import Pin, PWM
pwm = PWM(Pin("P7"), freq=1_000, duty_u16=32768)
אפיקים תוכנתיים במימוש bit‑banged¶
machine.SoftI2C ו‑machine.SoftSPI פועלים על כל GPIO אם אתם זקוקים לאפיק נוסף.
חיישן תרמי (חיצוני ללוח)¶
בנוסף ל‑FLIR Lepton המובנה, הקושחה כוללת גם את מנהל ההתקן fir — מנהל התקן לחיישן תרמי (fir == far infrared) עבור מדמי תרמיים מסוג I²C המחווטים חיצונית:
MLX90621 — מערך IR בגודל 16 × 4
MLX90640 — מערך IR בגודל 32 × 24
MLX90641 — מערך IR בגודל 16 × 12
AMG8833 — מערך IR בגודל 8 × 8
חווטו את המודול לאפיק ה‑I²C של הלוח וקראו פריימים עם fir.init() + fir.snapshot()
import time
import image
import fir
fir.init() # auto‑detects the sensor
clock = time.clock()
while True:
clock.tick()
try:
img = fir.snapshot(x_scale=5, y_scale=5,
color_palette=image.PALETTE_IRONBOW,
hint=image.BICUBIC,
copy_to_fb=True)
except OSError:
continue
print(clock.fps())
מנהל ההתקן fir מדבר עם החיישן רק דרך I²C 2 — חווטו את המודול ל‑P4 (SCL) ול‑P5 (SDA).
תזמון¶
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)
טיימרים וירטואליים¶
from machine import Timer
one_shot = Timer(-1)
one_shot.init(period=5_000, mode=Timer.ONE_SHOT,
callback=lambda t: print("once"))
periodic = Timer(-1)
periodic.init(period=2_000, mode=Timer.PERIODIC,
callback=lambda t: print("tick"))
ערכי המחזור הם במילישניות. קראו ל‑deinit() כדי לעצור ולשחרר את החריץ.
שעון זמן אמת¶
from machine import RTC
rtc = RTC()
rtc.datetime((2026, 4, 30, 4, 12, 0, 0, 0))
print(rtc.datetime())
אם סוללת LiPo מחוברת, ה‑RTC שומר על הזמן גם כאשר פסי המערכת כבויים (כובו דרך כפתור ההפעלה המובנה). כאשר רק USB מחובר, לחיצה על כפתור ההפעלה מנתקת מתח גם מה‑RTC — כך שזמן השעון לא ישרוד מחזור הפעלה ללא סוללה מחוברת.
Watchdog¶
from machine import WDT
wdt = WDT(timeout=5_000)
while True:
# ...do work...
wdt.feed()
מידע על אתחול וזמן ריצה¶
חלון מאתחל ה‑USB¶
בכל הפעלה המצלמה מריצה מאתחל (bootloader) קצר (כמה שניות) המאפשר ל‑OpenMV IDE לעדכן את הקושחה מבלי שהמשתמש יצטרך להיכנס למצב DFU. לאחר פקיעת החלון המאתחל מעביר את השליטה ל‑boot.py ולאחר מכן ל‑main.py.
סקריפט פועל יכול להיכנס מחדש למאתחל לפי דרישה על ידי קריאה ל‑machine.bootloader().
מערכת הקבצים וסדר האתחול¶
קושחת ה‑Pure Thermal מתקינה עד שלוש מערכות קבצים בעת האתחול:
זיכרון פלאש (flash) פנימי — תמיד מותקן ב‑
/flash. מכיל אתmain.pyואתREADME.txtכברירת מחדל; נוצר באתחול הראשון ממש.כרטיס microSD — אם מוכנס כרטיס הוא מותקן ב‑
/sdcard.ROMFS — מערכת קבצים לקריאה בלבד הממופה לזיכרון ב‑
/romהמשמשת לאספקת נכסי נתונים גדולים (למשל מודלי AI) הנהנים מגישה ללא העתקה. מותקנת אוטומטית על ידי MicroPython בעת ההפעלה, לפני שמורץ קוד Python כלשהו של המשתמש.
לאחר ההתקנה, ספריית העבודה מוגדרת ל‑/sdcard כאשר הכרטיס נוכח, אחרת ל‑/flash. המפרש מריץ אז סקריפטים מאותה ספרייה:
boot.pyמורץ בכל איפוס רך.main.pyמורץ רק באתחול קר, מיד לאחרboot.py.
הנחת boot.py או main.py על כרטיס ה‑SD דורסת את העותק בזיכרון פלאש (flash) מבלי לגעת בו.
כאשר מחובר דרך USB, מערכת קבצי האתחול (/sdcard אם כרטיס נוכח, אחרת /flash) נחשבת גם כן כדיסק אחסון USB אצל המארח. הוציאו את הדיסק לפני איפוס המצלמה כדי שהמארח יבצע flush לכתיבות שבמטמון שלו.
הערה
קבצים שנוצרו או שונו על ידי קוד הפועל על OpenMV Cam לא יופיעו אצל המארח עד שהדיסק יותקן מחדש. השתמשו בכרטיס ה‑SD עבור כל נתון שהסקריפט כותב בחזרה, והתקינו מחדש לפני קריאת קבצים אלה מהמארח.
גדלי אחסון¶
ה‑Pure Thermal נשלח עם:
/flash— מערכת קבצים FAT בגודל 24 MB, קריאה/כתיבה./rom— ROMFS לקריאה בלבד הממופה לזיכרון בגודל 8 MB, המשמש לאספקת סקריפטים ומודלי ML הנהנים מגישת mmap ללא העתקה./sdcard— הגודל המלא של כרטיס ה‑microSD שמוכנס (כאשר נוכח), קריאה/כתיבה.
מחוון תקלה קשה¶
אם ה‑LED RGB של המשתמש עובר במהירות בין כל הצבעים — מהר מספיק כך שזה נוטה להיראות כ‑LED לבן מהבהב ולא כגוונים נפרדים — הקושחה נתקלה בתקלה קשה בלתי ניתנת לשחזור. בצעו flash מחדש לקושחה כדי להתאושש.
עררטה חומרתית¶
קומץ מוזרויות ברמת הלוח מתועדות בעררטה החומרתית של Pure Thermal. פריטים מרכזיים שכדאי להיות מודעים אליהם:
הפרעת מחבר הסוללה — רכיבים על ה‑PCB יושבים ישירות מתחת למחבר סוללת ה‑LiPo, והטריז הבולט בתקע של כבל הסוללה עלול להיתפס בהם כאשר הכבל מוסר, ולעיתים למשוך רכיבים מהלוח. גזרו את הטריז מתקע הכבל בעזרת קוצץ flush לפני השימוש הראשון.
ה‑RTC נעצר כאשר הלוח כבוי — קיבול העומס על גביש ה‑32 kHz (Y2) גבוה מדי. הסרת C96 ו‑C97 (הזוג המקיף את הגביש לצד ה‑STM32) מאפשרת ל‑RTC להמשיך לפעול על מתח גיבוי. רוב הלוחות נשלחים כשהקבלים הללו כבר הוסרו; אם ה‑RTC שלכם מאבד את הזמן בעת ניתוק, בדקו את המיקומים הללו. ראו את הסוגיות בגיטהאב #1536 ו‑#1600 עבור השרשור המלא.
LED מחוון הטעינה נשאר כחול — המטען עשוי לסיים את מחזור הטעינה שלו בכל מקום בין 4.15 V ל‑4.19 V מבלי להעביר את המחוון מכחול (טעינה) לירוק (טעון). הסוללה עדיין טעונה במלואה במקרה זה; סמכו על מדידת מתח, לא על ה‑LED.
ההדפס מתייג בטעות את VIN כ‑VBAT — הפד במיקום ה‑VIN הסטנדרטי של כותרת OpenMV מסומן בהדפס
VBATב‑Pure Thermal. התיוג שגוי, אך אין לכך משמעות בפועל מכיוון שלפד אין חיבור חשמלי בכל מקרה.
ספריות תוכנה¶
ראו את אינדקס הספרייה לרשימה המלאה של המודולים — כולל אילו מהם ייחודיים לבניית ה‑Pure Thermal.