OpenMV AE3¶
OpenMV AE3 ถูกสร้างขึ้นบน Alif Ensemble E3 ซึ่งเป็น SoC แบบ dual ARM Cortex‑M55 (คอร์ HP 400 MHz + คอร์ HE 160 MHz) พร้อม NPU ออนชิปสองตัว (HP NPU 400 MHz / 204 GOPS + HE NPU 160 MHz / 46 GOPS) บอร์ดนี้จับคู่ NPU กับ sensor ชัตเตอร์แบบ global PAG7936 ขนาด 1 MP, USB‑C ความเร็วสูง, Wi‑Fi, Bluetooth 5.1, IMU แบบ LSM6DSM, ไมโครโฟน และ rangefinder แบบ time-of-flight ขนาด 8×8 VL53L8CX ทั้งหมดบนบอร์ดขนาด 30 × 30 มม.
สำหรับ datasheet ฉบับเต็ม รูปถ่าย และขนาด ดูได้ที่ หน้าผลิตภัณฑ์ OpenMV AE3
จุดเด่น¶
Alif Ensemble E3 — dual ARM Cortex‑M55 พร้อม Helium 128‑bit SIMD, คอร์ HP 400 MHz + คอร์ HE 160 MHz (~640 / ~256 DMIPS, CoreMark 1748 / 752)
Dual NPUs: HP NPU 400 MHz / 204 GOPS + HE NPU 160 MHz / 46 GOPS สำหรับ AI/ML — รัน YOLO object detection ควบคู่กับงานอื่นๆ
2D GPU แบบฮาร์ดแวร์สำหรับการปรับขนาด
SRAM ภายใน 13.5 MB พร้อม MRAM ออนชิป 5.5 MB และ octal flash ภายนอก 32 MB (DDR 8‑bit 100 MHz, อ่านได้ 200 MB/s)
backup RAM 4 KB พร้อม RTC ออนชิป
PAG7936 sensor สีแบบ global-shutter ขนาด 1 MP
IMU ออนบอร์ด (LSM6DSM accelerometer + gyroscope), ไมโครโฟน และ sensor แบบ time-of-flight 8×8 VL53L8CX (สูงสุด 4 ม.)
USB‑C ความเร็วสูง (480 Mb/s) พร้อมการกรอง EMI และการป้องกัน TVS, Wi‑Fi a/b/g/n + Bluetooth 5.1 (เสาอากาศแบบชิปหรือตัวเลือก U.FL)
พิน I/O ผู้ใช้ 10 พิน — P0–P3 บน side headers, P4–P5 บนตัวเชื่อมต่อ Qwiic และ P6–P9 บน B2B header ที่ด้านหลัง นอกจากนี้ยังมีการเดินสายดีบักและ recovery เพิ่มเติมไปยัง B2B header ด้วย
พินทั้งหมดรองรับเอาต์พุต 3.3 V / ทนต่อ 3.3 V, 25 mA ต่อพิน, รองรับอินเทอร์รัปต์ อินพุต ADC อ้างอิงที่ 1.8 V
LED RGB ของผู้ใช้, ปุ่มผู้ใช้, สวิตช์ recovery, ตัวเชื่อมต่อ Qwiic
deep sleep 80 µA ที่ 3.3 V (idle 24 mA, active 50–60 mA)
Warning
พิน I/O ของ AE3 ไม่ทนต่อ 5 V อย่าเชื่อมต่ออุปกรณ์โดยตรงกับ MCU 5 V เช่น Arduino Mega — ให้ใช้ level shifter สำหรับสัญญาณ 5 V ใดๆ
แผนผังพิน¶
อ้างอิงพิน¶
AE3 เปิดเผยพินผู้ใช้ 10 พินบน side headers (P0–P9) สัญญาณเพิ่มเติม รวมถึง JTAG และสาย recovery ถูกเดินสายไปยัง B2B (board‑to‑board) header ที่ด้านหลัง ของบอร์ดสำหรับ shields และ carrier boards
ชื่อพิน |
อ้างอิง |
ฟังก์ชัน |
|---|---|---|
P0 |
3.3 V |
SPI0 MOSI / I2C2 SCL / UART4 TX / TIM0 T1 / PDM D3 |
P1 |
3.3 V |
SPI0 MISO / I2C2 SDA / UART4 RX / TIM0 T0 |
P2 |
3.3 V |
SPI0 SCLK / LPI2C SDA / UART5 TX / TIM1 T1 |
P3 |
3.3 V |
SPI0 SS / LPI2C SCL / UART5 RX / TIM1 T0 / PDM C3 |
P4 |
3.3 V |
I2C1 SCL / UART1 TX / TIM2 T1 / PDM C0 / CAN TX |
P5 |
3.3 V |
I2C1 SDA / UART1 RX / TIM2 T0 / PDM D0 / CAN RX |
P6 |
1.8 V |
I2C1 SDA / UART3 CTS / TIM9 T0 (B2B only) |
P7 |
1.8 V |
I2C1 SCL / UART3 RTS / TIM9 T1 (B2B only) |
P8 |
1.8 V |
I3C SDA / UART3 RX / TIM5 T0 / ADC ch S10 (B2B only) |
P9 |
1.8 V |
I3C SCL / UART3 TX / TIM5 T1 / ADC ch S11 (B2B only) |
P10 |
1.8 V |
GPIO / JTAG TCK (B2B only) |
P11 |
1.8 V |
GPIO / JTAG TDO (B2B only) |
P13 |
1.8 V |
GPIO / JTAG TMS (B2B only) |
P14 |
1.8 V |
GPIO / JTAG TDI (B2B only) |
RESET |
3.3 V |
ดึงลง GND เพื่อรีเซ็ตบอร์ด |
SW |
3.3 V |
ปุ่มผู้ใช้ (active low) |
LED_RED |
3.3 V |
ช่องสีแดงของ RGB LED (active low) |
LED_GREEN |
3.3 V |
ช่องสีเขียวของ RGB LED (active low) |
LED_BLUE |
3.3 V |
ช่องสีน้ำเงินของ RGB LED (active low) |
Note
P0–P5 อยู่บน side headers (อ้างอิง 3.3 V); P6–P9 เปิดเผยเฉพาะบน B2B header ที่ด้านหลังของบอร์ดและอ้างอิง 1.8 V การจ่ายแรงดัน 3.3 V เข้าสู่พินที่อ้างอิง 1.8 V จะทำให้ SoC เสียหาย — ตรวจสอบให้แน่ใจว่าสัญญาณที่เชื่อมต่อกับ B2B header อยู่ที่ 1.8 V
พินจ่ายไฟ¶
3.3V — ราง power หลักของ AE3 ราง 3.3 V เดียวกันนี้ถูกเปิดเผยบน GPIO header solder pads, ตัวเชื่อมต่อ Qwiic และ B2B header ที่ด้านหลังของบอร์ด
1.8V — เปิดเผยบน B2B header เป็น เอาต์พุตเท่านั้น ใช้เพื่อจ่ายไฟให้กับอุปกรณ์ต่อพ่วงที่ใช้ลอจิก 1.8 V บน B2B carrier; อย่าจ่ายไฟจากภายนอกบอร์ด
GND — กราวด์ร่วม
AE3 ไม่มีพิน VIN และไม่มีวงจรชาร์จ LiPo สามารถจ่ายไฟผ่านสามทางใดก็ได้:
USB‑C — ตัวควบคุมออนบอร์ดลดแรงดัน 5 V จาก USB เป็น 3.3 V และต่อเข้ากับราง 3.3 V
ตัวเชื่อมต่อ Qwiic — จ่ายแรงดัน 3.3 V ที่ควบคุมแล้วเข้าสู่ Qwiic header เพื่อจ่ายไฟให้บอร์ดจากโมดูล Qwiic
GPIO header / B2B 3.3 V pads — จ่ายแรงดัน 3.3 V ที่ควบคุมแล้วเข้าสู่ 3.3 V pads ใดๆ บน I/O header หรือตัวเชื่อมต่อ B2B
ตัวควบคุม USB ป้อนราง power ผ่าน ideal diode ดังนั้นแหล่งจ่ายไฟ 3.3 V ภายนอกที่ด้าน Qwiic / GPIO / B2B สามารถจ่ายไฟให้บอร์ดได้แม้ว่า USB ยังคงต่ออยู่ โดยไม่ต้อง back-drive ตัวควบคุม USB
Tip
ใช้ ตัวประมาณอายุแบตเตอรี่ เพื่อจำลองว่า AE3 จะทำงานนานเท่าใดบนแบตเตอรี่สำหรับ duty cycle active / deep-sleep ที่กำหนด
Recovery และพินดีบัก¶
RESET — ดึงลง GND เพื่อรีเซ็ตบอร์ด การปล่อยจะให้ SoC เริ่มต้นทำงานตามปกติ
มี recovery switch บน หน้า (ด้าน camera) ของบอร์ด ที่มุมล่างซ้าย เมื่อเปิดใช้งาน จะบังคับให้ SE UART ของ AE3 ส่งออกผ่าน USB เพื่อให้ OpenMV IDE สามารถ reflash bootloader ออนบอร์ดได้ recovery mode เดียวกันนี้สามารถเปิดใช้งานจากระยะไกลได้โดยการดึงพิน RECOVERY บนตัวเชื่อมต่อ B2B ลงต่ำ
AE3 รองรับทั้ง SWD และ JTAG แบบเต็มรูปแบบในการดีบัก:
1.8 V SWD header ที่ด้านข้างของบอร์ดสำหรับสาย Tag-Connect ECV3-06-CTX และเปิดเผยสัญญาณ SWD สี่ตัว (TCK / TMS / TDO / RSTN) พร้อม GND
B2B header ที่ด้านหลังของบอร์ดเปิดเผยพินดีบักเดียวกัน (P10 = TCK, P11 = TDO, P13 = TMS, P14 = TDI) พร้อม RSTN ของระบบและ JTAG RSTN แยกต่างหาก พินเหล่านี้สามารถใช้สำหรับ SWD (TCK + TMS) หรือ JTAG แบบเต็มรูปแบบ ไลน์ JTAG RSTN จำเป็นเฉพาะในโหมด full-JTAG เท่านั้น
สัญญาณดีบักทั้งหมด อ้างอิง 1.8 V — ตรวจสอบให้แน่ใจว่า debug adapter ของคุณได้รับการกำหนดค่าสำหรับลอจิก 1.8 V ก่อนเชื่อมต่อ
อุปกรณ์ต่อพ่วงออนบอร์ด¶
LED¶
AE3 มี RGB LED ผู้ใช้หนึ่งดวง ควบคุมด้วยซอฟต์แวร์ผ่าน machine.LED
from machine import LED
LED("LED_RED").on()
LED("LED_GREEN").on()
LED("LED_BLUE").on()
Camera sensor¶
PAG7936 ถูกขับเคลื่อนผ่านโมดูล csi --- เซ็นเซอร์กล้อง
import csi
cam = csi.CSI()
cam.reset()
cam.pixformat(csi.RGB565)
cam.framesize(csi.HD) # 1280×800
cam.snapshot(time=2000) # let auto‑exposure settle
while True:
img = cam.snapshot()
PAG7936 รองรับ triggered mode — การรวมพิกเซลสอดคล้องกับการเรียก csi.CSI.snapshot แต่ละครั้งอย่างแม่นยำแทนที่จะเป็น free-running frame clock ซึ่งมีประโยชน์สำหรับการซิงค์การจับภาพกับ event ภายนอกหรือ sensor อื่น เปิดใช้งานผ่าน csi.CSI.ioctl ด้วย csi.IOCTL_SET_TRIGGERED_MODE อัตราเฟรมจะลดลงเหลือประมาณครึ่งหนึ่งของโหมด free-running เนื่องจากการอ่านไม่ pipeline กับการรวมเฟรมถัดไปอีกต่อไป:
cam.ioctl(csi.IOCTL_SET_TRIGGERED_MODE, True)
NPU¶
NPU ออนชิปสองตัวของ AE3 (HP NPU 400 MHz / 204 GOPS + HE NPU 160 MHz / 46 GOPS) ถูกเปิดเผยผ่านโมดูล ml --- Machine Learning โมเดลที่จัดเก็บบน filesystem แบบ read-only /rom โหลดโดยตรงจาก flash โดยไม่ต้องคัดลอกไปยัง RAM ดังนั้นแม้แต่ detectors ขนาดใหญ่ก็สามารถใส่ไว้ร่วมกับ framebuffer สดได้อย่างสบาย รัน YOLOv8 detector บนทุกเฟรมและวาดการทำนายทับบนภาพสด:
import csi
import time
import ml
from ml.postprocessing.ultralytics import YoloV8
# Initialize the sensor.
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)
# Load YOLO V8 model from ROM FS.
model = ml.Model("/rom/yolov8n_192.tflite", postprocess=YoloV8(threshold=0.4))
print(model)
# Visualization parameters.
n = len(model.labels)
model_class_colors = [
(int(255 * i // n), int(255 * (n - i - 1) // n), 255)
for i in range(n)
]
clock = time.clock()
while True:
clock.tick()
img = csi0.snapshot()
# boxes is a list of list per class of ((x, y, w, h), score) tuples
boxes = model.predict([img])
# Draw bounding boxes around the detected objects
for i, class_detections in enumerate(boxes):
rects = [r for r, score in class_detections]
labels = [model.labels[i] for j in range(len(rects))]
colors = [model_class_colors[i] for j in range(len(rects))]
ml.utils.draw_predictions(img, rects, labels, colors, format=None)
print(clock.fps(), "fps")
HE core¶
AE3 บรรจุคอร์ Cortex‑M55 สองคอร์ไว้ใน MCU เดียว: คอร์ high-performance (HP) ที่รัน MicroPython instance หลัก, camera, HP NPU, USB และอื่นๆ; และ คอร์ high-efficiency (HE) ที่ทำงานที่พลังงานต่ำกว่ามากและบูตเข้าสู่ MicroPython instance เล็กๆ ของตัวเอง ทั้งสองคอร์ใช้ Open-AMP / RPMsg message bus ร่วมกัน ดังนั้น HP core สามารถส่ง Python functions ไปยัง HE core รับผลลัพธ์กลับมา และทำให้ทั้งสองส่วนแยกออกจากกัน
จุดเข้าที่ง่ายที่สุดคือ decorator @openamp.async_remote มันจัดส่ง Python function ไปยัง HE core และ HE core รันมันเป็น asyncio task หลังจากลงทะเบียน tasks แล้ว ให้สร้าง openamp.RemoteProc ด้วยที่อยู่ flash ของ HE firmware และเรียก rproc.start() เพื่อบูต second core เมื่อไม่มี callback เอาต์พุต print() ของ function ที่ decorated จะถูกส่งต่อผ่าน default endpoint ไปยัง stdout ของ HP core — มีประโยชน์สำหรับ "hello world":
import time
import openamp
@openamp.async_remote
async def task1(ept):
import asyncio
while True:
print("Hello from the HE core!")
await asyncio.sleep(1)
# Boot the HE core. This runs the registered tasks.
rproc = openamp.RemoteProc(0x80320000)
rproc.start()
while True:
print("Hello from the HP core!")
time.sleep(1)
สำหรับ bidirectional messaging ให้ส่ง callback ไปยัง decorator callback จะทำงานบน HP core เมื่อใดก็ตามที่ HE task เรียก ept.send()
import time
import openamp
def task_callback(src_addr, data):
print("HP received:", data.decode())
@openamp.async_remote(task_callback)
async def task1(ept):
import asyncio
count = 0
while True:
ept.send(f"count = {count}")
count += 1
await asyncio.sleep(1)
rproc = openamp.RemoteProc(0x80320000)
rproc.start()
while True:
time.sleep(1)
HE core มี HE NPU ของตัวเอง (160 MHz, 46 GOPS) ดังนั้นมันสามารถรัน ML model ที่สองได้พร้อมกันกับสิ่งที่ HP NPU ของ HP core กำลังยุ่งอยู่ การแยกที่มีประโยชน์คือการวาง trigger / classifier model ที่เปิดตลอดเวลาขนาดเล็กไว้ที่ฝั่ง HE และให้ HP core ตอบสนองเฉพาะเมื่อมีบางอย่างน่าสนใจถูกตั้งค่าสถานะ — keyword spotting จากไมโครโฟนออนบอร์ดเหมาะสมดีเนื่องจากมันต่อเนื่อง, bandwidth ต่ำ และ HE core ใช้พลังงานต่ำกว่า HP มาก helper ml.apps.MicroSpeech ที่ถูก frozen รู้จัก "Yes" และ "No" ออกจากกล่อง — พูดคำเหล่านั้นดังๆ และชัดเจนเข้าไมค์ออนบอร์ดเพื่อทริกเกอร์การตรวจจับ:
import time
import openamp
def task_callback(src_addr, data):
print("Heard:", data.decode())
@openamp.async_remote(task_callback)
async def task1(ept):
from ml.apps import MicroSpeech
speech = MicroSpeech(gain_db=24)
while True:
label, scores = speech.listen(timeout=0, threshold=0.70)
if label:
ept.send(label)
rproc = openamp.RemoteProc(0x80320000)
rproc.start()
while True:
time.sleep(1)
สำหรับการแยกที่สมบูรณ์ยิ่งขึ้น ให้รัน BlazeFace บน HP NPU ในขณะที่ HE core จัดการ keyword spotting ในเบื้องหลัง — HP loop ซ้อนทับ keyword ล่าสุดที่ได้ยินบนเฟรม camera:
import csi
import time
import openamp
import ml
from ml.postprocessing.mediapipe import BlazeFace
label = None
label_ticks = 0
LABEL_HOLD_MS = 2000
def task_callback(src_addr, data):
global label, label_ticks
label = data.decode()
label_ticks = time.ticks_ms()
@openamp.async_remote(task_callback)
async def task1(ept):
from ml.apps import MicroSpeech
speech = MicroSpeech(gain_db=24)
while True:
l, scores = speech.listen(timeout=0, threshold=0.70)
if l:
ept.send(l)
# Start the HE core before initializing the camera on the HP core.
rproc = openamp.RemoteProc(0x80320000)
rproc.start()
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)
csi0.window((400, 400))
model = ml.Model("/rom/blazeface_front_128.tflite",
postprocess=BlazeFace(threshold=0.4))
clock = time.clock()
while True:
clock.tick()
img = csi0.snapshot()
for r, score, keypoints in model.predict([img]):
ml.utils.draw_predictions(img, [r], ("face",),
((0, 0, 255),), format=None)
ml.utils.draw_keypoints(img, keypoints, color=(255, 0, 0))
if label is not None:
if time.ticks_diff(time.ticks_ms(), label_ticks) < LABEL_HOLD_MS:
img.draw_string((4, 4), f"Heard: {label}",
color=(255, 0, 0), scale=2)
else:
label = None
print(clock.fps(), "fps")
HE core เหมาะกับงานแบบ always-on หรือ low-rate ที่คุณไม่ต้องการให้แข่งขันกับ camera/NPU pipeline ที่ฝั่ง HP — ML inference ขนาดเล็ก, DSP น้ำหนักเบาบนข้อมูลไมโครโฟนหรือ IMU และงานพื้นหลังที่คล้ายกัน
ข้อจำกัดบางประการที่ควรคำนึงถึง:
ใช้ไมโครโฟนและ IMU เมื่อขับเคลื่อนอุปกรณ์ต่อพ่วงจาก HE core — นั่นคือสิ่งที่ฝั่ง HE ถูกออกแบบมาเพื่อ แต่ละอุปกรณ์ต่อพ่วงสามารถเป็นเจ้าของได้โดยคอร์เดียวในแต่ละครั้ง ดังนั้นเลือก HP หรือ HE สำหรับมันและยึดติดกับนั้นตลอดอายุของสคริปต์
แต่ละ body ของ task
@openamp.async_remoteต้องจัดส่งได้ขนาดไม่เกิน 500 bytes ของ mpy bytecode — ทำให้ function เล็กและแยก logic ที่หนักกว่าออกเป็น library modules แยกต่างหากที่ถูก frozen เข้าไปใน firmwareImports ภายใน dispatched function เห็นเฉพาะโมดูลที่มีอยู่บน filesystem ของ HE core HE core มี ROMFS
/romของตัวเอง — แยกจาก/romของ HP core — ดังนั้นโมดูลและ ML models ที่คุณต้องการให้ใช้งานได้บน HE จำเป็นต้องถูกอบเข้าไปใน HE-side ROMFS image ไม่ใช่ HP
ไมโครโฟน¶
ไมโครโฟนออนบอร์ดถูกจับภาพผ่าน audio --- โมดูล Audio แต่ละบัฟเฟอร์มาถึงเป็น PCM bytearray แบบ signed‑16‑bit ซึ่งทำให้ง่ายต่อการป้อนเข้าสู่ ulab/numpy สำหรับ DSP เร็วๆ detector ความดัง — พิมพ์เมื่อปริมาณ RMS ข้ามค่าขีดแบ่ง:
import audio
from ulab import numpy as np
def loudness(pcmbuf):
samples = np.array(np.frombuffer(pcmbuf, dtype=np.int16), dtype=np.float)
rms = np.sqrt(np.mean(samples ** 2))
if rms > 10000:
print("Loud!", int(rms))
audio.init(channels=1, frequency=16000, gain_db=24)
audio.start_streaming(loudness)
while True:
pass
IMU¶
LSM6DSM accelerometer + gyroscope ออนบอร์ดถูกเปิดเผยผ่าน imu --- imu sensor
import imu
import time
while True:
print(imu.acceleration_mg()) # (x, y, z) in milli‑g
print(imu.angular_rate_mdps()) # (x, y, z) in milli‑deg/s
time.sleep_ms(100)
sensor แบบ time-of-flight¶
AE3 มี sensor แบบ time-of-flight หลายโซน 8×8 VL53L8CX ที่ส่งคืนการอ่านระยะทางสูงสุด 64 รายการต่อเฟรม โดยมีระยะสูงสุดประมาณ 4 ม. มันถูกเปิดเผยผ่านโมดูล tof --- ไดรเวอร์เซนเซอร์วัดระยะ time-of-flight — เรียก tof.init() เพื่อเริ่ม sensor และ tof.read_depth() เพื่อดึงเฟรม depth เป็น flat list ของการอ่านค่าเป็นมิลลิเมตร (หนึ่งต่อโซน):
import tof
tof.init()
while True:
depth, depth_min, depth_max = tof.read_depth()
print("min:", depth_min, "mm max:", depth_max, "mm")
อาร์เรย์ depth ยังสามารถวาดทับเฟรมสีจาก sensor หลักได้ — tof.draw_depth() วาดลงบน image.Image ที่มีอยู่ ในขณะที่ tof.snapshot() ส่งคืนภาพ depth ที่เรนเดอร์ใหม่:
import image
import tof
import csi
# Bring up the VL53L8CX time-of-flight sensor.
tof.init()
# Configure the main camera at VGA RGB565.
cam = csi.CSI()
cam.reset()
cam.pixformat(csi.RGB565)
cam.framesize(csi.VGA)
# Off-screen framebuffer used to compose the camera frame and the
# up-scaled depth heat-map side by side before pushing the result
# back to the live preview.
b = image.Image(640, 480, image.RGB565)
while True:
# Grab a colour frame from the main camera.
img = cam.snapshot()
try:
# Capture TOF data [depth map, min distance, max distance].
# vflip / hmirror align the ToF orientation with the camera.
depth, dmin, dmax = tof.read_depth(vflip=True, hmirror=True)
# Zones with no return read back as 0.0 — clamp them to the
# frame's max distance so the colour palette doesn't show
# them as "closest".
for i in range(0, len(depth)):
if depth[i] == 0.0:
depth[i] = dmax
except RuntimeError:
# The sensor occasionally faults on a frame; reset and skip.
tof.reset()
continue
# Draw the camera frame into the left half of the framebuffer,
# scaled to 60% so it leaves room for the depth heat-map on
# the right.
b.draw_image(img, x=0, y=64+8, x_scale=0.6, hint=image.BILINEAR)
# Up-sample the 8x8 depth array 30x with bicubic smoothing and
# blend it into the right half using the depth palette.
# scale=(0, 400) maps 0-400 mm to the full palette range.
tof.draw_depth(b, depth, x=320+64+16, y=64+8, alpha=255,
hint=image.BICUBIC, x_scale=30, y_scale=30,
scale=(0, 400), color_palette=image.PALETTE_DEPTH)
# Copy the composed framebuffer back into the live preview so
# OpenMV IDE shows both panels.
img.set(b)
Wi‑Fi¶
CYW43439 ออนบอร์ดถูกเปิดเผยผ่าน network --- การกำหนดค่าเครือข่าย เป็น station interface หลังจากเชื่อมต่อแล้ว ipconfig("addr4") จะส่งคืน pair (ip, netmask)
import network, time
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("ssid", "password")
while not wlan.isconnected():
time.sleep(1)
print("Wi‑Fi IP:", wlan.ipconfig("addr4")[0])
Bluetooth¶
CYW43439 เดียวกันนี้ยังเปิดเผย Bluetooth 5.1 ด้วย ใช้ aioble --- Async BLE สำหรับ BLE แบบ asyncio‑friendly — ตัวอย่างเช่น โฆษณาเป็น peripheral และรอให้ central เชื่อมต่อ:
import asyncio
import aioble
async def run():
while True:
conn = await aioble.advertise(250_000, name="OpenMV-AE3")
print("Connected:", conn.device)
await conn.disconnected()
asyncio.run(run())
อ้างอิง Bus¶
GPIO¶
ใช้ machine.Pin เพื่ออ่านหรือขับเคลื่อนพินที่มีการระบุซิลค์สกรีนใดๆ เอาต์พุตเป็น CMOS 3.3 V และสามารถ sink/source ได้สูงสุด 25 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())
พิน input ใดก็ตามยังสามารถทริกเกอร์อินเทอร์รัปต์บนการเปลี่ยนขอบได้:
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 |
RTS |
CTS |
|---|---|---|---|---|
UART1 |
P4 |
P5 |
— |
— |
UART3 |
P9 |
P8 |
P7 |
P6 |
UART4 |
P0 |
P1 |
— |
— |
UART5 |
P2 |
P3 |
— |
— |
from machine import UART
uart = UART(1, baudrate=115200)
uart.write("hello")
uart.read(5)
UART3 เป็น bus เดียวที่มี hardware flow control เนื่องจาก P6–P9 อยู่บน B2B header และอ้างอิง 1.8 V UART3 จึงทำงานได้เฉพาะผ่าน level shifter หรือ B2B carrier — อย่าเชื่อมต่อลอจิก 3.3 V โดยตรง
I²C¶
Bus |
SCL |
SDA |
|---|---|---|
I2C1 |
P4 |
P5 |
I2C2 |
P0 |
P1 |
LPI2C |
P3 |
P2 |
from machine import I2C
i2c = I2C(1, freq=400_000)
i2c.scan()
i2c.writeto(0x76, b"hi")
ตัวเชื่อมต่อ Qwiic ออนบอร์ดเปิดเผย I2C2 ที่ 3.3 V
I2C1 และ I2C2 ยังสามารถใช้ในโหมด target (slave) ผ่าน machine.I2CTarget เพื่อเปิดเผย memory region ให้กับ I²C controller อื่น:
from machine import I2CTarget
buf = bytearray(32)
target = I2CTarget(1, addr=0x42, mem=buf)
Note
อุปกรณ์ต่อพ่วง LPI2C ไม่ได้เปิดเผยใน firmware มันจะรองรับเฉพาะ โหมด target (slave) เท่านั้นหากถูกเปิดเผย และ I2C1 และ I2C2 ครอบคลุมทั้งการทำงานแบบ controller และ target อยู่แล้ว
SPI¶
Bus |
MOSI |
MISO |
SCK |
CS |
|---|---|---|---|---|
SPI0 |
P0 |
P1 |
P2 |
P3 |
from machine import SPI
from machine import Pin
spi = SPI(0, 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)
ADC¶
Alif Ensemble E3 เปิดเผยช่อง ADC 12‑bit สองช่องบน P8 และ P9 (เฉพาะ B2B header) อินพุตทั้งสองอ้างอิง 1.8 V — read_u16 ส่งคืน 0–65535 ตลอด 0–1.8 V ที่พิน:
from machine import ADC
import time
adc = ADC("P8")
while True:
voltage = adc.read_u16() * 1.8 / 65535
print(voltage)
time.sleep_ms(100)
Warning
อินพุต ADC ของ AE3 อ้างอิง 1.8 V ไม่ใช่ 3.3 V การจ่ายสัญญาณ 3.3 V ดิบเข้าไปจะทำให้ converter อิ่มตัวและอาจทำให้พินเสียหาย — ลดแรงดันที่สูงกว่าลงด้วยภายนอก
PWM¶
พิน |
Timer / channel |
|---|---|
P0 |
TIM0 T1 |
P1 |
TIM0 T0 |
P2 |
TIM1 T1 |
P3 |
TIM1 T0 |
P4 |
TIM2 T1 |
P5 |
TIM2 T0 |
P6 |
TIM9 T0 (B2B only) |
P7 |
TIM9 T1 (B2B only) |
P8 |
TIM5 T0 (B2B only) |
P9 |
TIM5 T1 (B2B only) |
ขับเคลื่อนทุกตัวผ่าน machine.PWM
from machine import Pin, PWM
pwm = PWM(Pin("P0"), freq=1_000, duty_u16=32768)
Bus แบบ software bit‑banged¶
machine.SoftI2C และ machine.SoftSPI ทำงานบน GPIO ใดๆ หากคุณต้องการ bus เพิ่มเติม
Thermal sensor (ภายนอกบอร์ด)¶
Firmware รวม driver fir --- ไดรเวอร์เซนเซอร์ความร้อน (fir == far infrared) สำหรับ AMG8833 8 × 8 thermal imager ที่ต่อสายภายนอก เชื่อมต่อโมดูลกับ I²C bus ที่ระบุด้านล่าง จากนั้นอ่านเฟรมด้วย 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())
driver fir คุยกับ sensor ผ่าน I²C 1 เท่านั้น — ต่อสายโมดูลกับ P4 (SCL) และ P5 (SDA)
เวลา¶
time¶
โมดูล time ครอบคลุม blocking delays, monotonic ticks และการวัดเวลาที่ผ่านไป:
import time
time.sleep(1) # seconds
time.sleep_ms(500)
time.sleep_us(10)
start = time.ticks_ms()
# ...do work...
elapsed = time.ticks_diff(time.ticks_ms(), start)
Virtual timers¶
machine.Timer กำหนดเวลา callbacks แบบ periodic หรือ one‑shot โดยไม่ใช้ hardware timer slot ส่ง -1 เป็น id เพื่อใช้ virtual (software) 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"))
ค่า Period เป็นมิลลิวินาที เรียก deinit() เพื่อหยุดและปล่อย slot
Real‑time clock¶
machine.RTC รักษาเวลานาฬิกาแขวนผ่านการรีเซ็ต สำรองด้วย backup RAM ออนชิป 4 KB ที่รอดจาก deep sleep:
from machine import RTC
rtc = RTC()
rtc.datetime((2026, 4, 30, 4, 12, 0, 0, 0)) # Y, M, D, weekday, h, m, s, subsec
print(rtc.datetime())
RTC ยังทำงานผ่าน deep sleep ดังนั้นคุณสามารถใช้มันเป็น wakeup source สำหรับ machine.deepsleep()
ข้อมูลการบูตและ runtime¶
หน้าต่าง USB bootloader¶
ในทุกการเปิดเครื่อง กล้องจะรัน bootloader สั้นๆ (สักสองสามวินาที) ที่ให้ OpenMV IDE อัปเดต firmware โดยไม่ต้องให้ผู้ใช้เข้าสู่โหมด DFU หลังจากหน้าต่างหมดเวลา bootloader จะส่งต่อให้ boot.py และจากนั้น main.py
สคริปต์ที่กำลังทำงานสามารถเข้าสู่ bootloader อีกครั้งตามต้องการโดยเรียก machine.bootloader()
import machine
machine.bootloader()
Filesystem และลำดับการบูต¶
AE3 firmware mount สูงสุดสอง filesystems เมื่อบูต:
Internal flash — mount ที่
/flashเสมอ เก็บmain.pyและREADME.txtโดยค่าเริ่มต้น สร้างขึ้นในการบูตครั้งแรกROMFS — filesystem แบบ read-only, memory-mapped ที่
/romใช้เพื่อจัดส่ง data assets ขนาดใหญ่ (เช่น AI models) ที่ได้ประโยชน์จากการเข้าถึงแบบ zero-copy Mount โดยอัตโนมัติโดย MicroPython เมื่อเริ่มต้น ก่อน Python ของผู้ใช้ใดๆ ทำงาน
หลังจาก mount แล้ว working directory จะถูกตั้งค่าเป็น /flash จากนั้น interpreter จะรันสคริปต์จากไดเรกทอรีนั้น:
boot.pyถูกรันในทุก soft reset (cold boot,Ctrl‑Dจาก REPL หรือเมื่อสคริปต์ที่กำลังทำงานส่งคืน)main.pyถูกรัน เฉพาะใน cold boot เท่านั้น ทันทีหลังจากboot.pysoft resets ต่อมาจะรันboot.pyอีกครั้งแต่ตกลงตรงไปยัง REPL — เพื่อรันmain.pyอีกครั้ง คุณต้องรีเซ็ตบอร์ดอย่างเต็มรูปแบบ
main.py เริ่มต้นที่จัดส่งบนบอร์ดที่ flash ใหม่เพียงแค่กะพริบช่อง สีน้ำเงิน ของ RGB LED ผู้ใช้เป็น heartbeat (สองพัลส์สั้น ช่องว่างสั้น) เพื่อให้คุณทราบว่า firmware บูตสะอาดโดยไม่มีโฮสต์ต่ออยู่
sys.path ถูกขยายให้รวมทั้งสอง filesystems และ subdirectories lib/ ของมัน ดังนั้นโมดูลที่ import ได้สามารถอยู่ใน /flash/lib หรือ /rom/lib
เมื่อเชื่อมต่อผ่าน USB, /flash ยังแสดงผลเป็น USB mass‑storage drive บนโฮสต์ด้วย ให้คุณแก้ไข boot.py, main.py และไฟล์อื่นๆ ได้โดยตรง Eject drive ก่อนรีเซ็ต camera เพื่อให้โฮสต์ flush การเขียนที่ cached ไว้
Note
เนื่องจาก OS จัดการ drive เป็น passive block device ไฟล์ที่สร้างหรือแก้ไขโดย code ที่ทำงานบน OpenMV Cam จะไม่แสดงขึ้นจนกว่าโฮสต์จะ mount drive อีกครั้ง หาก OS และ OpenMV Cam เขียน filesystem เดียวกันพร้อมกัน OS จะชนะและเขียนทับการเปลี่ยนแปลงที่ทำโดย camera
Note
ช่อง สีแดง ของ RGB LED ผู้ใช้อาจสว่างขึ้นชั่วคราวในขณะที่โฮสต์กำลังอ่านหรือเขียนไปยัง USB mass‑storage drive — นี่คือตัวบ่งชี้กิจกรรมที่ขับเคลื่อนด้วย firmware ไม่ใช่ข้อผิดพลาด
ขนาดพื้นที่จัดเก็บ¶
AE3 จัดส่งพร้อมกับ:
/flash— FAT filesystem ขนาด 8 MB, read/write/romบน HP core — 24 MB ROMFS แบบ read-only memory-mapped สำหรับสคริปต์และข้อมูลที่ HP core โหลดเมื่อเริ่มต้น/romบน HE core — 1 MB ROMFS แบบ read-only ที่ HE core เป็นเจ้าของ โมดูลและ ML models ที่คุณต้องการให้ใช้งานได้กับ tasks@openamp.async_remoteจำเป็นต้องถูกอบเข้าไปใน image นี้ ไม่ใช่ HP
ตัวบ่งชี้ hard-fault¶
หาก RGB LED ผู้ใช้หมุนวนผ่านสีทั้งหมดอย่างรวดเร็ว — เร็วพอที่มีแนวโน้มจะดูเหมือน LED สีขาวที่กะพริบ มากกว่าสีที่แตกต่างกัน — firmware ได้เจอ hard fault ที่ไม่สามารถกู้คืนได้ Reflash firmware เพื่อกู้คืน หากการ reflash ไม่ช่วย บอร์ดอาจเสียหายทางกายภาพ
Software libraries¶
ดู library index สำหรับรายการโมดูลทั้งหมด รวมถึงโมดูลที่เป็นเอกลักษณ์ของ AE3 build