Arduino Nicla Vision¶
Arduino Nicla Vision คือบอร์ดการมองเห็นของเครื่องขนาด 22.86 × 22.86 มม. ที่สร้างบน STMicroelectronics STM32H747AII6 ซึ่งเป็น SoC แบบ dual-core ที่รวม Cortex-M7 ที่ 400 MHz กับ Cortex-M4 ที่ 200 MHz เข้าด้วยกัน เฟิร์มแวร์ OpenMV ทำงานบน M7 core ทั้งหมด บอร์ดนี้จับคู่ MCU กับ GC2145 CMOS sensor สี 2 MP, LSM6DSOX IMU 6 แกน, ไมโครโฟน MEMS MP34DT06, ตัววัดระยะ time-of-flight VL53L1CB, Wi-Fi + Bluetooth LE 5.1 และวงจรชาร์จแบตเตอรี่พร้อม fuel gauge
สำหรับข้อมูลชีต รูปภาพ และขนาดครบถ้วน ดูได้ที่ หน้าผลิตภัณฑ์ Arduino Nicla Vision
ไฮไลต์¶
STMicroelectronics STM32H747AII6 dual Cortex-M7 (400 MHz) + Cortex-M4 (200 MHz) เฟิร์มแวร์ OpenMV ทำงานบน M7 core เท่านั้น
แฟลชภายใน 2 MB บวก แฟลช QSPI ภายนอก 16 MB (ใช้สำหรับแอปพลิเคชัน + ROMFS)
SRAM ภายใน 1 MB
Hardware JPEG encoder/decoder
GC2145 CMOS sensor สี 2 MP
IMU บนบอร์ด (LSM6DSOX accelerometer + gyroscope), ไมโครโฟน MEMS (MP34DT06JTR) และ VL53L1CB ตัววัดระยะ time-of-flight (สูงสุด ~4 เมตร)
Wi-Fi b/g/n (2.4 GHz) + Bluetooth LE 5.1 ผ่านโมดูล Murata 1DX (CYW4343W) — เชื่อมต่อกับเสาอากาศที่ให้มาผ่าน U.FL connector บนบอร์ด
USB ความเร็วสูง (480 Mb/s) ผ่าน Micro USB โดยใช้ ULPI PHY ภายนอก (USB3320C)
พิน I/O ผู้ใช้ 13 พิน บน Arduino edge headers — LPIOs ดิจิทัลสี่พิน (
D0–D3), อินพุตแอนะล็อก 1.8 V สามพิน (A0–A2), คู่ I²CSCL/SDAและ SPI สี่พินSCLK/CIPO/COPI/CSรองรับแบตเตอรี่ — ขั้วต่อ Li-Po ด้านหลัง, วงจรชาร์จแบบ BQ และ MAX17262 fuel gauge บนบัส PMIC ภายใน
5-pin ESLOV connector ด้านหลังสำหรับต่อขยาย I²C โดยไม่ต้องบัดกรี
Warning
พินดิจิทัลเป็น 3.3 V โดยค่าเริ่มต้น แต่ผ่าน level shifters ที่โปรแกรมด้วยซอฟต์แวร์ได้ (VDDIO_EXT) ซึ่งสามารถกำหนดใหม่เป็น 1.8 V ได้ พินแอนะล็อก (A0–A2) เป็น 1.8 V เท่านั้น — ไม่ผ่าน level shifters และเชื่อมต่อโดยตรงกับ MCU การจ่าย 3.3 V เข้า A0–A2 จะทำให้ SoC เสียหาย
Pinout¶
ตารางอ้างอิงพิน¶
พินผู้ใช้สิบสามพินปรากฏบน Arduino edge headers (J1 และ J2) สัญญาณดีบัก รีคัฟเวอรี่ และ PMIC เพิ่มเติมถูกนำไปยัง test pads ด้านหลังบอร์ด
ชื่อพิน |
อ้างอิง |
ฟังก์ชัน |
|---|---|---|
D0 |
3.3 V |
GPIO / LPIO0 (J1-1) |
D1 |
3.3 V |
LPUART1 TX / TIM1 CH2 / LPIO1 (J2-3) |
D2 |
3.3 V |
LPUART1 RX / TIM1 CH3 / LPIO2 (J2-4) |
D3 |
3.3 V |
GPIO / LPIO3 (J2-5) |
A0 |
1.8 V |
ADC1 channel 4 (J1-8) |
A1 |
1.8 V |
ADC2 channel 2 (J1-7) |
A2 |
1.8 V |
ADC3 channel 5 (J1-2) |
SCL |
3.3 V |
I2C1 SCL / UART4 RX / TIM4 CH3 (J2-2) |
SDA |
3.3 V |
I2C1 SDA / UART4 TX / TIM4 CH4 (J2-1) |
SCLK |
3.3 V |
SPI4 SCK / TIM1 CH3N (J1-6) |
CIPO |
3.3 V |
SPI4 MISO / TIM1 CH3 (J1-5) |
COPI |
3.3 V |
SPI4 MOSI / TIM1 CH4 (J1-4) |
CS |
3.3 V |
SPI4 NSS / TIM1 CH2 (J1-3) |
RESET |
3.3 V |
ดึงลง GND (หรือกดสวิตช์บนบอร์ด) เพื่อรีเซ็ตบอร์ด |
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
D0–D3 และ SCLK/CIPO/COPI/CS อยู่หลัง TXB0108 bidirectional level shifter — ส่วนนั้นรองรับเฉพาะการขับ GPIO แบบ push-pull ดังนั้นการสื่อสารบัสแบบ open-drain (เช่น 1-Wire หรือ I²C แบบ bit-bang บนพินเหล่านั้น) จะไม่ทำงาน
SCL/SDA อยู่หลัง NTS0304 shifter แยกต่างหากที่รองรับทั้งการขับแบบ push-pull และ open-drain ซึ่งเป็นเหตุผลที่ I²C 1 ทำงานได้ที่นั่น
shifter ทั้งสองอ้างอิงกับ VDDIO_EXT (3.3 V โดยค่าเริ่มต้นจาก PMIC บนบอร์ด) และความแรงในการขับถูกจำกัดเมื่อเทียบกับ GPIO โดยตรง — ออกแบบมาสำหรับระดับสัญญาณมากกว่าโหลดพลังงาน
พินพลังงาน¶
พินบน edge header:
VIN (J2-9) — ราง 3.6 – 5 V ของระบบหลัก PMIC รับอินพุตจากที่นี่
VDDIO_EXT (J2-7) — เอาต์พุต ของราง level-shifter ที่ 1.8 V หรือ 3.3 V (3.3 V โดยค่าเริ่มต้น) ใช้สิ่งนี้เพื่อจ่ายไฟให้อุปกรณ์ต่อพ่วงภายนอก 1.8 V หรือ 3.3 V ที่เชื่อมต่อกับพิน LPIO/SPI/I²C เพื่อให้ใช้ระดับลอจิกเดียวกันกับ headers
VBAT (J3-2) — อินพุตแบตเตอรี่ Li-Po PMIC บนบอร์ดชาร์จเซลล์จาก VIN และรายงานสถานะการชาร์จผ่าน fuel gauge
NTC (J3-1) — อินพุต thermistor Li-Po เสริม
GND (J2-6) — กราวด์ร่วม
NC (J2-8) — ไม่ได้เชื่อมต่อ
Test pads ด้านหลังบอร์ด:
+3V3 — ราง 3.3 V หลัก
D_P / D_N — คู่ข้อมูล USB high-speed (หลัง PHY)
USB และ ESLOV connector ต่างก็จ่ายพลังงาน VIN ผ่าน LM66100 ideal diodes คู่ (หนึ่งต่อแหล่งจ่าย) ดังนั้นแหล่งจ่ายใดแหล่งหนึ่งสามารถจ่ายไฟให้บอร์ดได้เองและทั้งสองจะไม่ back-drive กัน หากคุณขับ VIN ภายนอกบน J2-9 แหล่งจ่ายนั้นจะมีลำดับความสำคัญสูงกว่า — diodes จะหยุดนำไฟจาก USB / ESLOV เมื่อราง external สูงกว่า
ดังนั้นบอร์ดสามารถรับพลังงานผ่านเส้นทางใดเส้นทางหนึ่งต่อไปนี้:
Micro USB — 5 V เข้า VIN ผ่าน ideal diode ฝั่ง USB
ESLOV connector — สูงสุด 5 V บนพิน
VESLOVของ J5 ถูกนำเข้า VIN ผ่าน ideal diode ฝั่ง ESLOV (ดู ESLOV connector)พิน VIN (J2-9) — จ่ายแหล่งจ่าย 3.6 – 5 V ที่ควบคุมแล้วโดยตรง
แบตเตอรี่ Li-Po — เชื่อมต่อกับขั้วต่อแบตเตอรี่ J4 ด้านหลัง หรือ กับ pads VBAT/GND/NTC บน J3 / J2-6 อย่าเชื่อมต่อแบตเตอรี่สองก้อนพร้อมกัน
ESLOV connector¶
J5 ด้านหลังบอร์ดคือ ESLOV connector Molex 5 พินแบบไม่ต้องบัดกรี:
พิน |
ชื่อ |
ฟังก์ชัน |
|---|---|---|
J5-1 |
VESLOV |
อินพุตพลังงาน (≤ 5 V) — OR'd เข้า |
J5-2 |
INT |
อินพุต interrupt ภายนอกบน |
J5-3 |
SCL_EXT |
ใช้ร่วมกับ pad |
J5-4 |
SDA_EXT |
ใช้ร่วมกับ pad |
J5-5 |
GND |
กราวด์ร่วม |
SCL_EXT/SDA_EXT ของ ESLOV และ SCL/SDA ของ J2 เป็นพินเดียวกัน — บัส I²C 1 หนึ่งบัสที่เปิดเผยบนขั้วต่อสองตัว
Tip
ใช้ battery life estimator เพื่อประมาณระยะเวลาที่ Nicla Vision จะทำงานจากแบตเตอรี่สำหรับ duty cycle active/deep-sleep ที่กำหนด
พินรีคัฟเวอรี่และดีบัก¶
RESET — ทั้งสวิตช์ชั่วคราวด้านบนบอร์ดและ pad (J3-4 / test pad P5) ที่ต่อกับสาย NRST ของ SoC ดึงลง GND เพื่อรีเซ็ต
Nicla Vision ใช้ double-tap reset มาตรฐานของ Arduino เพื่อเข้า bootloader ของ Arduino — กดปุ่ม reset สองครั้งอย่างรวดเร็วและบอร์ดจะ enumerate เป็นอุปกรณ์ DFU OpenMV IDE ใช้โหมดนี้เพื่อ reflash เฟิร์มแวร์
สัญญาณ STM32 SWD เปิดเผยที่ด้านหลังของบอร์ดผ่านแถว test pads ระหว่าง headers J2 สองตัว บัดกรี header 2.54 มม. (100-mil) ลงในพินเหล่านั้นเพื่อต่อ ST-LINK หรือ J-Link adapter:
P1 / P2 — บัส I²C PMIC ภายในบน PF0 (SDA) และ PF1 (SCL) นี่คือ
machine.I2C(2)บน Nicla Vision และนำ PMIC, fuel gauge และ ToF trafficP3 — TMS / SWDIO (PA13)
P4 — TCK / SWCLK (PA14)
P5 — NRST
P6 — TDO / SWO (PB3)
P7 — ราง +1V8 (แหล่งจ่าย I/O ของ SoC — ยังเป็นค่าอ้างอิงที่ถูกต้องสำหรับ debug adapter)
P8 —
VOTP_PMIC— สำหรับการโปรแกรมในโรงงานเท่านั้น ต้องปล่อยว่างไว้
สัญญาณดีบักทั้งหมดอ้างอิง 1.8 V — I/O ring ของ STM32H747 บนบอร์ดนี้ทำงานจากราง +1V8 ตั้งค่า debug adapter ของคุณสำหรับลอจิก 1.8 V ก่อนเชื่อมต่อ
อุปกรณ์ต่อพ่วงบนบอร์ด¶
LED¶
Nicla Vision มี RGB LED ผู้ใช้หนึ่งตัวที่ควบคุมได้ด้วยซอฟต์แวร์ผ่าน machine.LED
from machine import LED
LED("LED_RED").on()
LED("LED_GREEN").on()
LED("LED_BLUE").on()
DL2 CHARGE LED แยกต่างหากที่ด้านข้างของบอร์ดเชื่อมต่อโดยตรงกับเอาต์พุต CHGB ของ PMIC — จะสว่างขณะแบตเตอรี่ Li-Po กำลังถูกชาร์จจาก USB / ESLOV / VIN และไม่สามารถควบคุมด้วยผู้ใช้ได้
Camera sensor¶
GC2145 ถูกควบคุมผ่านโมดูล csi --- เซ็นเซอร์กล้อง
import csi
cam = csi.CSI()
cam.reset()
cam.pixformat(csi.RGB565)
cam.framesize(csi.QVGA)
cam.snapshot(time=2000) # let auto‑exposure settle
while True:
img = cam.snapshot()
เมื่อคุณขอ framesize เล็ก ไดรเวอร์ GC2145 จะครอบหน้าต่างการอ่านเล็กๆ ตามสัดส่วนจาก sensor — โดยค่าเริ่มต้น อัตราส่วน downscale จากการอ่านไปยังเอาต์พุตถูกจำกัดไว้ที่ 3x เพื่อให้ frame rate สูง csi.IOCTL_SET_FOV_WIDE เพิ่มขีดจำกัดนั้นเป็น 5x ซึ่งหมายความว่าไดรเวอร์ดึงจากพื้นที่ที่กว้างขึ้นของ sensor เมื่อ streaming ที่ความละเอียดเล็ก ผลลัพธ์คือ field of view ที่กว้างขึ้นอย่างเห็นได้ชัดที่ framesizes เล็ก แลกกับ throughput บางส่วน:
cam.ioctl(csi.IOCTL_SET_FOV_WIDE, True)
cam.ioctl(csi.IOCTL_GET_FOV_WIDE) # returns the current setting
M4 core¶
Cortex-M4 core เปิดเผยผ่าน openamp สำหรับการสื่อสารระหว่างโปรเซสเซอร์ เฟิร์มแวร์ OpenMV ทำงานบน M7 เท่านั้น M4 ไม่มี MicroPython runtime เป็นของตัวเอง ดังนั้นการใช้งาน M4 หมายถึงการสร้าง firmware image C แยกต่างหากและโหลดจาก filesystem ผ่าน openamp.RemoteProc เฟิร์มแวร์ตัวอย่างสำเร็จรูปที่ implement virtual UART endpoint มีให้ใช้ที่ repository openamp_vuart — ทำตาม README เพื่อ build vuart.elf
import openamp
import time
def ept_recv_callback(src_addr, data):
print("Received:", data.decode())
ept = openamp.Endpoint("vuart-channel", callback=ept_recv_callback)
rproc = openamp.RemoteProc("vuart.elf")
rproc.start()
count = 0
while True:
if ept.is_ready():
ept.send("Hello World %d!" % count, timeout=1000)
count += 1
time.sleep_ms(1000)
ในทางปฏิบัติ การรองรับนี้ควรถือว่าเป็นการสาธิต openamp interface มากกว่าแพลตฟอร์ม dual-core ที่ใช้งานได้จริง — M4 ไม่สามารถรีเซ็ตได้อย่างอิสระจาก M7 ดังนั้นการหยุด M4 จะบังคับให้รีบูตระบบทั้งหมด
ไมโครโฟน¶
ไมโครโฟน PDM MP34DT06JTR บนบอร์ดถูกจับภาพผ่าน audio --- โมดูล Audio บน peripheral DFSDM ของ STM32 บัฟเฟอร์แต่ละตัวมาเป็น bytearray PCM signed-16-bit พร้อมส่งเข้า ulab/numpy สำหรับ DSP — เช่น ตัวตรวจจับความดัง:
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¶
LSM6DSOX 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)
IMU เชื่อมต่อกับบัส SPI ภายในเฉพาะ (SPI5) จึงไม่ขัดแย้งกับ SPI4 ของผู้ใช้ที่เปิดเผยบน headers
ตัววัดระยะ time-of-flight¶
ST VL53L1CB ตัววัดระยะ time-of-flight บนบอร์ดอยู่บนบัส I²C PMIC ภายใน (I²C 2) ใช้ไดรเวอร์ frozen vl53l1x --- ไดรเวอร์เซนเซอร์วัดระยะ VL53L1X ToF เพื่ออ่านระยะทางได้สูงสุด ~4 เมตร:
import time
from machine import I2C
import vl53l1x
bus = I2C(2) # internal bus (PMIC / fuel gauge / ToF)
tof = vl53l1x.VL53L1X(bus)
while True:
print("Distance:", tof.read(), "mm")
time.sleep_ms(100)
Battery fuel gauge¶
Maxim MAX17262 ModelGauge m5 fuel gauge ติดตามแรงดัน กระแส อุณหภูมิ และสถานะการชาร์จของแบตเตอรี่ Li-Po อยู่บน I²C 2 ที่แอดเดรส 0x36
MAX17262 มีการวัดกระแส ภายใน ดังนั้น current register อ่านออกมาเป็นไมโครแอมป์โดยตรงโดยไม่ต้องใช้ค่า Rsense ภายนอก การอ่าน fuel gauge ไม่ก่อให้เกิดอันตราย — ไม่มีไดรเวอร์ให้ใช้ แต่ register ที่บันทึกไว้ใน MAX17262 datasheet สามารถอ่านได้โดยตรง:
import time
import struct
from machine import I2C
FUEL_GAUGE = 0x36 # MAX17262
def read_reg(bus, addr, reg):
return struct.unpack("<H", bus.readfrom_mem(addr, reg, 2))[0]
def read_signed(bus, addr, reg):
v = read_reg(bus, addr, reg)
return v - 0x10000 if v & 0x8000 else v
bus = I2C(2)
while True:
# 0x05 RepCap — remaining capacity, raw × 0.5 mAh
rep_cap = read_reg(bus, FUEL_GAUGE, 0x05) * 0.5
# 0x06 RepSOC — state of charge, raw / 256 %
soc = read_reg(bus, FUEL_GAUGE, 0x06) / 256
# 0x08 Temp — die temperature, signed, raw / 256 °C
temp = read_signed(bus, FUEL_GAUGE, 0x08) / 256
# 0x09 VCell — battery voltage, raw × 78.125 µV
vcell = read_reg(bus, FUEL_GAUGE, 0x09) * 78.125 / 1_000_000
# 0x0A Current — signed, raw × 156.25 µA
current = read_signed(bus, FUEL_GAUGE, 0x0A) * 156.25 / 1000
# 0x0B AvgCurrent — averaged current
avg_curr = read_signed(bus, FUEL_GAUGE, 0x0B) * 156.25 / 1000
# 0x10 FullCapRep — learned full capacity, raw × 0.5 mAh
full_cap = read_reg(bus, FUEL_GAUGE, 0x10) * 0.5
# 0x11 TTE — time-to-empty (valid while discharging), raw × 5.625 s
tte_s = read_reg(bus, FUEL_GAUGE, 0x11) * 5.625
# 0x20 TTF — time-to-full (valid while charging), raw × 5.625 s
ttf_s = read_reg(bus, FUEL_GAUGE, 0x20) * 5.625
# 0x17 Cycles — charge-cycle counter, 1% per LSB
cycles = read_reg(bus, FUEL_GAUGE, 0x17) / 100
print("V: %.3f V" % vcell)
print("Capacity: %.1f / %.1f mAh (%.1f %%)" % (rep_cap, full_cap, soc))
print("Temp: %.1f C" % temp)
print("Current: %.1f mA (avg %.1f mA)" % (current, avg_curr))
print("TTE: %.0f s TTF: %.0f s" % (tte_s, ttf_s))
print("Cycles: %.2f" % cycles)
print()
time.sleep_ms(1000)
Current เป็น signed two's-complement: บวกขณะชาร์จ ลบขณะ discharge TTE มีความหมายเฉพาะเมื่อกระแสเป็นลบ TTF มีความหมายเฉพาะเมื่อกระแสเป็นบวก
Power management IC¶
NXP MC34PF1550A0EP PMIC จัดการตัวควบคุมแรงดันทุกตัวบน Nicla Vision — ราง +3V3 หลัก, ราง +1V8 SoC core/I/O, VDDIO_EXT ไปยัง level shifters และวงจรชาร์จ Li-Po อยู่บน I²C 2 ที่แอดเดรส 0x08
Warning
การอ่าน PMIC registers ไม่เป็นอันตราย แต่การเขียนนั้นอันตรายมาก การกำหนดค่า buck regulator หรือการตั้งค่าวงจรชาร์จผิดอาจทำให้บอร์ด แบตเตอรี่ หรือทั้งสองเสียหายถาวร ถือว่า PMIC เป็น read-only เว้นแต่คุณจะรู้แน่ชัดว่ากำลังทำอะไร
สิ่งที่ PMIC บอกได้ที่ fuel gauge ไม่สามารถบอกได้มากที่สุดคือ state machine ของวงจรชาร์จ — ว่าบอร์ดกำลังทำงานจาก USB / ESLOV / VIN อยู่หรือไม่ อยู่ในขั้นตอนไหนของ charge cycle ของ Li-Po และวงจรชาร์จอยู่ใน thermal หรือ watchdog fault หรือไม่ charger registers อยู่ที่ offset 0x80 ใน I²C address space หลักของ PF1550 (ดู §22.2 ของ PF1550 datasheet) ดังนั้นตัวอย่าง CHG_INT_OK ที่ charger address 0x04 จะอ่านจาก PMIC register 0x84
import time
from machine import I2C
PMIC = 0x08
# Charger state machine (low nibble of CHG_SNS, register 0x87)
CHG_STATES = {
0x0: "precharge",
0x1: "fast charge (constant current)",
0x2: "fast charge (constant voltage)",
0x3: "end of charge",
0x4: "done",
0x6: "timer fault",
0x7: "thermistor suspend",
0x8: "off — input invalid or charger disabled",
0x9: "battery overvoltage",
0xA: "thermal shutdown",
0xC: "linear mode (not charging)",
}
bus = I2C(2)
while True:
# 0x84 CHG_INT_OK — single-bit indicators
ok = bus.readfrom_mem(PMIC, 0x84, 1)[0]
vbus_ok = bool(ok & (1 << 5)) # bit 5 — VBUS valid (USB/ESLOV/VIN)
bat_ok = bool(ok & (1 << 2)) # bit 2 — battery OK
chg_ok = bool(ok & (1 << 3)) # bit 3 — charger actively charging
thm_ok = bool(ok & (1 << 7)) # bit 7 — thermistor in normal range
# 0x87 CHG_SNS — charger state + thermal regulation flag
chg_sns = bus.readfrom_mem(PMIC, 0x87, 1)[0]
state = CHG_STATES.get(chg_sns & 0x0F, "reserved")
treg = bool(chg_sns & (1 << 7)) # thermal regulation active
print("VBUS valid: ", vbus_ok)
print("battery OK: ", bat_ok)
print("charger active: ", chg_ok)
print("thermistor normal: ", thm_ok)
print("thermal reg active: ", treg)
print("state: ", state)
print()
time.sleep_ms(1000)
Register read-only อื่นๆ ที่น่าดูใน datasheet (ทั้งหมดที่ charger-offset 0x80): 0x80 CHG_INT (latched charger interrupts — fault flags), 0x86 VBUS_SNS (สถานะ VBUS แบบหลายบิตรวมถึง OVLO / UVLO / DPM) และ 0x88 BATT_SNS (การมีอยู่ของแบตเตอรี่และสถานะ overcurrent)
Wi-Fi¶
Murata 1DX (CYW4343W) บนบอร์ดเปิดเผยผ่าน network --- การกำหนดค่าเครือข่าย เป็น station interface เชื่อมต่อเสาอากาศที่ให้มากับ U.FL connector บนบอร์ดก่อนเปิดใช้งาน radio:
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¶
Murata 1DX เดียวกันยังเปิดเผย Bluetooth LE 5.1 ด้วย ใช้ aioble --- Async BLE สำหรับ BLE แบบ asyncio-friendly — ตัวอย่างเช่น advertise เป็น peripheral และรอให้ central เชื่อมต่อ:
import asyncio
import aioble
async def run():
while True:
conn = await aioble.advertise(250_000, name="Nicla-Vision")
print("Connected:", conn.device)
await conn.disconnected()
asyncio.run(run())
อ้างอิงบัส¶
GPIO¶
ใช้ machine.Pin เพื่ออ่านหรือขับพิน silkscreened ใดก็ได้ เอาต์พุตเป็น 3.3 V CMOS (VDDIO_EXT ค่าเริ่มต้น) และ level shifters จำกัดความแรงในการขับต่อพินไว้ที่ไม่กี่มิลลิแอมป์ — ออกแบบมาสำหรับระดับสัญญาณมากกว่าโหลดพลังงาน
from machine import Pin
out = Pin("D0", Pin.OUT)
out.on()
out.off()
out.value(1)
inp = Pin("D1", Pin.IN, Pin.PULL_UP)
print(inp.value())
พินอินพุตใดก็ได้สามารถยิง interrupt บน edge transitions ได้:
def handler(pin):
print("triggered:", pin)
Pin("D1", Pin.IN, Pin.PULL_UP).irq(
handler, Pin.IRQ_FALLING | Pin.IRQ_RISING,
)
UART¶
บัส |
TX |
RX |
|---|---|---|
UART4 |
SDA |
SCL |
from machine import UART
uart = UART(4, baudrate=115200)
uart.write("hello")
uart.read(5)
Note
UART4 ใช้พินร่วมกับ I²C 1 — pads SDA/SCL เดียวกันรองรับทั้งสองบัส เลือก UART หรือ I²C ไม่ใช่ทั้งสอง บนพินเหล่านั้น
D1/D2 บน silkscreen ยังอ่านว่า UART_TX/UART_RX แต่บนเฟิร์มแวร์นี้พินเหล่านั้นถูกนำไปยัง LPUART1 ไม่ใช่ machine.UART machine.UART(1) เองถูกสงวนไว้สำหรับ Bluetooth controller ในชิปและไม่สามารถเข้าถึงได้บน headers
I²C¶
บัส |
SCL |
SDA |
|---|---|---|
I2C1 |
SCL |
SDA |
from machine import I2C
i2c = I2C(1, freq=400_000)
i2c.scan()
i2c.writeto(0x76, b"hi")
pads SCL/SDA บน J2 และพิน SCL_EXT/SDA_EXT ของ ESLOV connector ลงบนบัส I²C 1 เดียวกัน — ดู ESLOV connector ด้านบนสำหรับ ESLOV pinout
hardware เดียวกันยังสามารถใช้ในโหมด target (slave) ผ่าน machine.I2CTarget เพื่อเปิดเผยพื้นที่หน่วยความจำให้กับ I²C controller อื่น:
from machine import I2CTarget
buf = bytearray(32)
target = I2CTarget(1, addr=0x42, mem=buf)
SPI¶
บัส |
MOSI |
MISO |
SCK |
CS |
|---|---|---|---|---|
SPI4 |
COPI |
CIPO |
SCLK |
CS |
from machine import SPI
from machine import Pin
spi = SPI(4, baudrate=10_000_000)
cs = Pin("CS", Pin.OUT, value=1) # CS is not driven by the SPI peripheral
cs.value(0)
spi.write(b"hello")
cs.value(1)
ADC¶
Nicla Vision เปิดเผยช่อง ADC 12-bit สามช่องบน A0, A1 และ A2 ทั้งสามช่องอ้างอิง 1.8 V — read_u16 คืนค่า 0–65535 ตลอดช่วง 0–1.8 V ที่พิน:
from machine import ADC
import time
adc = ADC("A0")
while True:
voltage = adc.read_u16() * 1.8 / 65535
print(voltage)
time.sleep_ms(100)
Warning
อินพุต ADC ของ Nicla Vision อ้างอิง 1.8 V (และไม่มี level shifter หน้า SoC) การจ่ายสัญญาณ 3.3 V เข้าไปจะทำให้ converter ทำงานเต็มพิกัดและอาจทำลายพิน — แบ่งแรงดันสูงกว่าลงด้วยภายนอก
PWM¶
พิน |
Timer / channel |
|---|---|
D1 |
TIM1 CH2 |
D2 |
TIM1 CH3 |
SCL |
TIM4 CH3, TIM16 CH1 |
SDA |
TIM4 CH4, TIM17 CH1 |
SCLK |
TIM1 CH3N |
CIPO |
TIM1 CH3 |
COPI |
TIM1 CH4 |
CS |
TIM1 CH2 |
ขับพินใดก็ได้ผ่าน machine.PWM
from machine import Pin, PWM
pwm = PWM(Pin("D1"), freq=1_000, duty_u16=32768)
Note
พินหลายพินใช้ช่อง TIM1 ร่วมกัน:
TIM1 CH2 อยู่บน
D1และCSTIM1 CH3 อยู่บน
D2และCIPO;SCLKเอาต์พุต complement แบบกลับ (TIM1 CH3N) ของช่องเดียวกันTIM1 CH4 อยู่บน
COPIเพียงอย่างเดียว
เลือกผู้ใช้หนึ่งรายต่อ timer channel พิน SPI สี่พิน (SCLK/CIPO/COPI/CS) ยังไม่สามารถขับด้วย PWM ขณะที่ machine.SPI(4) กำลังใช้งานอยู่
บัสแบบ Software bit-bang¶
machine.SoftI2C และ machine.SoftSPI ทำงานบน GPIO ใดก็ได้หากคุณต้องการบัสเพิ่มเติม
Thermal sensor (นอกบอร์ด)¶
เฟิร์มแวร์รวมไดรเวอร์ fir --- ไดรเวอร์เซนเซอร์ความร้อน (fir == far infrared) สำหรับ thermal imager ที่ต่อจากภายนอก:
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 สื่อสารกับ sensor ผ่าน I²C 1 เท่านั้น — ต่อโมดูลกับ pads SCL / SDA บน silkscreen
การจับเวลา¶
time¶
โมดูล time ครอบคลุม delays แบบ blocking, 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 เก็บเวลา wall-clock ข้ามการรีเซ็ต:
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())
Watchdog¶
machine.WDT รีเซ็ตบอร์ดหากแอปพลิเคชันค้าง เมื่อเริ่มแล้วไม่สามารถหยุดหรือกำหนดค่าใหม่ได้ — feed มันเป็นระยะในลูปหลัก:
from machine import WDT
wdt = WDT(timeout=5_000) # 5 second window
while True:
# ...do work...
wdt.feed()
ข้อมูล Boot และ runtime¶
การอัปเดตเฟิร์มแวร์ (DFU)¶
Nicla Vision ใช้ double-tap reset มาตรฐานของ Arduino เพื่อเข้า bootloader ของ Arduino กดปุ่ม reset สองครั้งอย่างรวดเร็ว — บอร์ดจะ enumerate ใหม่ผ่าน USB เป็นอุปกรณ์ DFU และ OpenMV IDE สามารถ flash firmware image ใหม่ได้
สคริปต์ที่กำลังทำงานสามารถเข้า bootloader ได้ตามต้องการโดยเรียก machine.bootloader()
import machine
machine.bootloader()
Filesystem และลำดับ Boot¶
เฟิร์มแวร์ Nicla Vision mount ได้สูงสุดสอง filesystem ตอน boot:
แฟลชภายใน — mount ที่
/flashเสมอ เก็บmain.pyและREADME.txtโดยค่าเริ่มต้น สร้างใน boot ครั้งแรกROMFS — filesystem read-only แบบ memory-mapped ที่
/rommount โดยอัตโนมัติโดย MicroPython ตอนเริ่มต้น
หลัง mount แล้ว working directory จะถูกตั้งเป็น /flash จากนั้น interpreter จะรันสคริปต์จากไดเรกทอรีนั้น:
boot.pyถูก execute ใน ทุก soft reset (cold boot,Ctrl‑Dจาก REPL หรือเมื่อ script ที่กำลังทำงานคืนค่า)main.pyถูก execute เฉพาะ cold boot เท่านั้น ทันทีหลังboot.pysoft resets ถัดมาจะรันboot.pyอีกครั้งแต่ตกลงไปที่ REPL โดยตรง — หากต้องการรันmain.pyใหม่ต้องรีเซ็ตบอร์ดอย่างสมบูรณ์
main.py ค่าเริ่มต้นที่บรรจุมาบนบอร์ดที่เพิ่ง flash ใหม่จะกระพริบช่อง blue ของ RGB LED ผู้ใช้เป็น heartbeat (สองพัลส์สั้น ช่วยว่างสั้น) เพื่อให้รู้ว่าเฟิร์มแวร์ boot สำเร็จโดยไม่มี host เชื่อมต่ออยู่
sys.path ได้รับการขยายให้รวมทั้งสอง filesystem และไดเรกทอรีย่อย lib/ ของพวกเขา ดังนั้น modules ที่ import ได้สามารถอยู่ใน /flash/lib หรือ /rom/lib
เมื่อเชื่อมต่อผ่าน USB /flash ยัง enumerate เป็น USB mass-storage drive บน host ด้วย ทำให้คุณแก้ไข boot.py, main.py และไฟล์อื่นๆ ได้โดยตรง Eject drive ก่อนรีเซ็ตกล้อง เพื่อให้ host flush cached writes
Note
เนื่องจาก OS ถือว่า drive เป็น block device แบบ passive ไฟล์ที่สร้างหรือแก้ไขโดยโค้ดที่ทำงานบนกล้องจะไม่แสดงจนกว่า host จะ mount drive ใหม่ หาก OS และกล้องเขียน filesystem เดียวกันพร้อมกัน OS จะชนะและเขียนทับการเปลี่ยนแปลงที่กล้องทำ ใช้ SD card สำหรับข้อมูลใดๆ ที่สคริปต์เขียนกลับ และ mount ใหม่ก่อนอ่านไฟล์เหล่านั้นจาก host
Note
ช่อง red ของ RGB LED ผู้ใช้อาจสว่างขึ้นชั่วคราวขณะที่ host กำลังอ่านหรือเขียน USB mass-storage drive — นี่คือ activity indicator ที่ขับโดยเฟิร์มแวร์ ไม่ใช่ข้อผิดพลาด
ขนาดพื้นที่จัดเก็บ¶
Nicla Vision บรรจุมาพร้อมกับ:
/flash— FAT filesystem 11 MB อ่าน/เขียน/rom— ROMFS read-only แบบ memory-mapped 4 MB ใช้สำหรับบรรจุสคริปต์และ ML models ที่ได้รับประโยชน์จากการเข้าถึง mmap แบบ zero-copy
ตัวบ่งชี้ hard fault¶
หากช่อง RGB LED ของผู้ใช้วนซ้ำสีต่างๆ อย่างรวดเร็ว — เร็วพอที่มักจะดูเหมือน LED สีขาวกะพริบ มากกว่าสีที่แยกจากกัน — แสดงว่าเฟิร์มแวร์ประสบกับ hard fault ที่ไม่สามารถกู้คืนได้ Reflash เฟิร์มแวร์เพื่อกู้คืน หาก reflash ไม่ช่วย บอร์ดอาจเสียหายทางกายภาพ
ซอฟต์แวร์ไลบรารี¶
ดู library index สำหรับรายการโมดูลครบถ้วน — รวมถึงรายการที่ไม่ซ้ำกับ Nicla Vision build