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

สำหรับข้อมูลชีต รูปภาพ และขนาดครบถ้วน ดูได้ที่ หน้าผลิตภัณฑ์ 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 ดิจิทัลสี่พิน (D0D3), อินพุตแอนะล็อก 1.8 V สามพิน (A0A2), คู่ I²C SCL/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 Nicla Vision 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

D0D3 และ 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 เข้า VIN ผ่าน LM66100 ideal diode

J5-2

INT

อินพุต interrupt ภายนอกบน PD9

J5-3

SCL_EXT

ใช้ร่วมกับ pad SCL บน J2 — บัส I²C 1 เดียวกันกับ user header

J5-4

SDA_EXT

ใช้ร่วมกับ pad SDA บน J2 — บัส I²C 1 เดียวกันกับ user header

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 traffic

  • P3 — TMS / SWDIO (PA13)

  • P4 — TCK / SWCLK (PA14)

  • P5 — NRST

  • P6 — TDO / SWO (PB3)

  • P7 — ราง +1V8 (แหล่งจ่าย I/O ของ SoC — ยังเป็นค่าอ้างอิงที่ถูกต้องสำหรับ debug adapter)

  • P8VOTP_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 Vread_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 และ CS

  • TIM1 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 ที่ /rom mount โดยอัตโนมัติโดย MicroPython ตอนเริ่มต้น

หลัง mount แล้ว working directory จะถูกตั้งเป็น /flash จากนั้น interpreter จะรันสคริปต์จากไดเรกทอรีนั้น:

  • boot.py ถูก execute ใน ทุก soft reset (cold boot, Ctrl‑D จาก REPL หรือเมื่อ script ที่กำลังทำงานคืนค่า)

  • main.py ถูก execute เฉพาะ cold boot เท่านั้น ทันทีหลัง boot.py soft 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