Arduino Nano 33 BLE Sense

警告

このボードはサポート対象外になりました。 Arduino Nano 33 BLE Sense 向けの最後の OpenMV ファームウェアリリースは 4.7.0 です。このターゲットに対して、今後のファームウェア更新、バグ修正、新機能の提供は行われません。以下の情報は、4.7.0 以前を実行しているユーザー向けに保存されています。

Arduino Nano 33 BLE Sense は、Nordic Semiconductor nRF52840 を中心に構築された 45 × 18 mm の Arduino-Nano フォームファクターのボードです。nRF52840 は、64 MHz で動作する FPU 付きの単一の ARM Cortex-M4 で、256 KB の内部 SRAM と 1 MB の内部フラッシュを備えています。BLE はオンダイのラジオから提供され、ボードには 9 軸 IMU、LPS22HB 気圧計、HTS221 / HS3003 温度 / 湿度センサー、APDS9960 環境光 / カラー / 近接 / ジェスチャーセンサー、そして MP34DT05 PDM マイクが搭載されています。OpenMV ファームウェアは、これらすべてを MicroPython から駆動します。

Arduino Nano 33 BLE Sense

完全なデータシート、写真、寸法については、Arduino Nano 33 BLE Rev2 製品ページ を参照してください。

ハイライト

  • Nordic nRF52840 — 64 MHz で動作する FPU 付き Cortex-M4。256 KB の内部 SRAM1 MB の内部フラッシュ を搭載。

  • Bluetooth LE 5.0 — オンダイのラジオと Nordic SoftDevice s140 経由。

  • 9 軸 IMU — Rev 1 では LSM9DS1、Rev 2 では BMI270 + BMM150。フリーズされた imu ドライバが起動時に両方をプローブします。

  • LPS22HB 気圧計、HTS221 / HS3003 温度・湿度センサー、APDS9960 環境光 / カラー / 近接 / ジェスチャーセンサー、そして MP34DT05 PDM マイク。

  • Micro USB コネクタ — 電源供給、プログラミング、CDC REPL 用。

  • 標準の Nano ヘッダー上の 22 本のユーザー I/O ピンTX/RXD2D13(デジタル)、A0A7(アナログ)。

ピン配置

Arduino Nano 33 BLE Sense のピン配置

ピンリファレンス

ピン名

リファレンス

機能

TX

3.3 V

UART1 TX

RX

3.3 V

UART1 RX

D2

3.3 V

PWM

D3

3.3 V

PWM

D4

3.3 V

PWM

D5

3.3 V

PWM

D6

3.3 V

PWM

D7

3.3 V

PWM

D8

3.3 V

PWM

D9

3.3 V

PWM

D10

3.3 V

PWM

D11

3.3 V

PWM / SPI0 MOSI

D12

3.3 V

PWM / SPI0 MISO

D13

3.3 V

PWM / SPI0 SCK

A0

3.3 V

ADC / PWM

A1

3.3 V

ADC / PWM

A2

3.3 V

ADC / PWM

A3

3.3 V

ADC / PWM

A4 / I2C_SDA

3.3 V

ADC / PWM / I2C0 SDA

A5 / I2C_SCL

3.3 V

ADC / PWM / I2C0 SCL

A6

3.3 V

ADC / PWM

A7

3.3 V

ADC / PWM

RESET

3.3 V

オンボードの RESET ボタンを押すか、GND に引いてリセットします

LED_BUILTIN

D13 上のオレンジ色のユーザー LED

LED_RED

RGB LED の赤チャンネル(アクティブロー)

LED_GREEN

RGB LED の緑チャンネル(アクティブロー)

LED_BLUE

RGB LED の青チャンネル(アクティブロー)

警告

Nano 33 BLE Sense の I/O ピンは 3.3 V 専用 であり、5 V トレラントではありません。5 V を流し込むと nRF52840 が損傷します。

電源ピン

  • VIN — 4.5 ~ 21 V 入力。オンボードのレギュレータを介してボードに電源を供給します。USB の 5 V ラインからもダイオードを介して供給されるため、USB と VIN を同時に接続しても互いに逆流させることなく使用できます。

  • +5V — デフォルトでは未接続です。

  • +3V3 — 3.3 V レギュレータの出力。

  • AREF — アナログリファレンスピン。このボードでは nRF52840 に配線されていません。ADC は常に 3.3 V を基準とします。

  • GND — 共通グラウンド。

Nano 33 BLE Sense は、いずれかの経路で電源を供給できます。

  • Micro USB — オンボードのレギュレータに 5 V を供給します。

  • VIN ピン — 安定化された 4.5 ~ 21 V の電源を供給します。

注釈

ボード裏面の VUSB とラベル付けされたはんだジャンパは、+5V を USB の 5 V ラインに橋渡しします。これを閉じると、+5V ヘッダーピンが実際に 5 V を伝送するようになります。

注釈

オンボードの 4.5 ~ 21 V スイッチングレギュレータの出力にあるノーマルクローズのはんだジャンパを切断するとレギュレータを無効化でき、+3V3 上の外部 3.3 V 電源からボードを直接給電できるようになります。

リカバリーおよびデバッグピン

  • RESET — 露出したパッドと、ボード上面のモーメンタリ RESET ボタンの両方があり、nRF52840 のリセットラインに接続されています。GND に引くかボタンを押すとリセットします。

Nano 33 BLE Sense は、Arduino のブートローダーに入るために Arduino 標準の ダブルタップリセット を使用します。RESET ボタンを素早く 2 回押すと、ボードはブートローダーモードに入り、OpenMV IDE で新しいファームウェアイメージを書き込めます。

nRF52840 の SWD 信号は、ボード裏面のめっきパッドに露出しています。すべてのデバッグ信号は 3.3 V 基準 です。

オンボードのペリフェラル

LED

Nano 33 BLE Sense には、シルク印刷された LED_REDLED_GREENLED_BLUE の各チャンネルを通じて駆動されるユーザー RGB LED と、D13 上の独立したオレンジ色の LED_BUILTIN があります。これら 4 つはすべて machine.LED を通じてソフトウェアで制御できます:

from machine import LED

LED("LED_RED").on()
LED("LED_GREEN").on()
LED("LED_BLUE").on()
LED("LED_BUILTIN").on()

ボード上の独立した緑色の 電源 LED は、+3.3 V ラインが立ち上がっている間は常に点灯し、ユーザーが制御することはできません。

カメラセンサー

Nano 33 BLE Sense 上の OpenMV ファームウェアは、OmniVision OV7670 パラレル CMOS センサーをサポートします。ボードにはオンボードの画像センサーがありません。以下に挙げるシルク印刷されたヘッダーピンに OV7670 モジュールを配線し、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()

注釈

OV7670 は 14 本のピンを使用します。ファームウェアは次のように配線します。

センサー信号

Nano 33 BLE Sense のピン

D0

D10

D1

TX

D2

RX

D3

D2

D4

D3

D5

D5

D6

D6

D7

D4

HSYNC

A1

VSYNC

D8

PXCLK

A0

MXCLK

D9

POWER

A3

RESET

A2

SCL

A5(I²C 0)

SDA

A4(I²C 0)

OV7670 の I²C 制御バスは、A5/A4 に露出している外部 I²C 0 と同じです。センサーは 7 ビットアドレス 0x21 に位置するため、カメラを配線する際は、そのバス上のユーザーデバイスはこのアドレスを避ける必要があります。

IMU

9 軸 IMU は、フリーズされた imu モジュールを通じて公開されます。このモジュールは、ボードに LSM9DS1(Rev 1)が搭載されているか、BMI270 + BMM150(Rev 2)が搭載されているかを自動検出し、統一された imu.IMU クラスを提供します。これらのセンサーは内部 I²C 1 バス(P14 / P15)上にあります:

import time
from machine import I2C, Pin
from imu import IMU

bus = I2C(1, scl=Pin("P15"), sda=Pin("P14"))
sensor = IMU(bus)

while True:
    print(sensor.accel())     # (x, y, z) in g
    print(sensor.gyro())      # (x, y, z) in deg/s
    print(sensor.magnet())    # (x, y, z) magnetometer
    time.sleep_ms(100)

タップ検出や FIFO などの機能に直接アクセスするには、対応するフリーズされたドライバ(lsm9ds1bmi270、または bmm150)をインポートし、同じバス上でインスタンス化します。

環境センサー

気圧計(LPS22HB)と温度・湿度センサー(Rev 1 では HTS221、Rev 2 では HS3003)は、IMU と同じ内部 I²C 1 バスを共有します:

import time
from machine import I2C, Pin
from lps22h import LPS22H
from hts221 import HTS221

bus = I2C(1, scl=Pin("P15"), sda=Pin("P14"))
lps = LPS22H(bus)
try:
    hts = HTS221(bus)
except OSError:
    from hs3003 import HS3003
    hts = HS3003(bus)

while True:
    print("pressure:    %.2f hPa" % lps.pressure())
    print("temperature: %.2f C"   % lps.temperature())
    print("humidity:    %.2f %%"  % hts.humidity())
    time.sleep_ms(500)

光 / カラー / 近接 / ジェスチャー

Broadcom の APDS9960 は同じ内部 I²C 1 バス上にあり、環境光、RGB カラー、近接、ジェスチャーのセンシングを提供します:

import time
from machine import I2C, Pin
from apds9960 import uAPDS9960 as APDS9960

bus = I2C(1, scl=Pin("P15"), sda=Pin("P14"))
apds = APDS9960(bus)
apds.enableLightSensor()

while True:
    print("ambient light:", apds.readAmbientLight())
    time.sleep_ms(250)

マイク

オンボードの MP34DT05 PDM マイクは、audio --- オーディオモジュール を通じてキャプチャされます。各バッファは符号付き 16 ビット PCM の bytearray として届き、DSP のために ulab/numpy にそのまま渡せます:

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

Bluetooth

nRF52840 の Bluetooth LE 5.0 ラジオは Nordic SoftDevice s140 上で動作し、レガシーの ubluepy モジュールを通じて公開されます。最新の bluetooth / aioble --- 非同期 BLE API は、このビルドでは有効化されていません。ペリフェラル(GATT サーバー、アドバタイズ)と セントラル(GAP オブザーバー / スキャナー + 接続)の両方のロールが利用可能です。

単一の Environmental Sensing サービスと通知可能な温度キャラクタリスティックを持つペリフェラルとしてアドバタイズします。event_handler コールバックは、接続、切断、CCCD 書き込み時に発火します:

from ubluepy import Service, Characteristic, UUID, Peripheral, constants
from machine import LED

def event_handler(event_id, handle, data):
    if event_id == constants.EVT_GAP_CONNECTED:
        LED("LED_GREEN").on()
    elif event_id == constants.EVT_GAP_DISCONNECTED:
        LED("LED_GREEN").off()
        periph.advertise(device_name="Nano 33", services=[svc])

svc = Service(UUID("181A"))                          # Environmental Sensing
char = Characteristic(UUID("2A6E"),                  # Temperature
                      props=Characteristic.PROP_NOTIFY | Characteristic.PROP_READ,
                      attrs=Characteristic.ATTR_CCCD)
svc.addCharacteristic(char)

periph = Peripheral()
periph.addService(svc)
periph.setConnectionHandler(event_handler)
periph.advertise(device_name="Nano 33", services=[svc])

セントラルロールで近くのアドバタイズデバイスをスキャンします:

from ubluepy import Scanner

for entry in Scanner().scan(1_000):                  # 1 second window
    print(entry.addr(), entry.rssi(), "dBm")

完全な API については ubluepy リファレンスを参照してください — UUIDServiceCharacteristicPeripheralScannerScanEntry、そして constants 名前空間。

バスリファレンス

GPIO

シルク印刷されたピンのいずれかを読み取ったり駆動したりするには machine.Pin を使用します。出力は 3.3 V CMOS で、1 ピンあたり 15 mA、全 GPIO 合計で 25 mA です。

from machine import Pin

out = Pin("D2", Pin.OUT)
out.on()
out.off()
out.value(1)

inp = Pin("D3", Pin.IN, Pin.PULL_UP)
print(inp.value())

どの入力ピンも、エッジ遷移で割り込みを発火させることができます:

def handler(pin):
    print("triggered:", pin)

Pin("D3", Pin.IN, Pin.PULL_UP).irq(
    handler, Pin.IRQ_FALLING | Pin.IRQ_RISING,
)

UART

バス

TX

RX

UART1

TX

RX

シルク印刷名の TX/RXmachine.UART とともに使用します:

from machine import UART

uart = UART(1, baudrate=115200)
uart.write("hello")
uart.read(5)

I²C

バス

SDA

SCL

I2C0

I2C_SDA / A4

I2C_SCL / A5

I2C1

P14

P15

どちらのバスも、ピンを machine.I2C に明示的に渡す必要があります:

from machine import I2C, Pin

bus0 = I2C(0, scl=Pin("I2C_SCL"), sda=Pin("I2C_SDA"), freq=400_000)
bus0.scan()

bus1 = I2C(1, scl=Pin("P15"), sda=Pin("P14"), freq=400_000)
bus1.scan()

注釈

バス 1 は P14/P15 上の内部センサーバス(ユーザーヘッダー上にはありません)で、IMU、気圧計、環境センサー、APDS9960 に対応します。フリーズされたセンサードライバはこれを直接使用します。ユーザーコードもスキャンできますが、アドレスはすでにオンボードセンサーによって占有されています。

SPI

バス

MOSI

MISO

SCK

CS

SPI0

D11

D12

D13

D10

CS ラインは SPI ペリフェラルによって駆動されません。D10 を出力として構成し、転送の前後で手動で切り替えてください:

from machine import SPI, Pin

spi = SPI(0, baudrate=10_000_000)
cs = Pin("D10", Pin.OUT, value=1)   # CS is not driven by the SPI peripheral

cs.value(0)
spi.write(b"hello")
cs.value(1)

注釈

D13 はオレンジ色の LED_BUILTIN を兼ねています。このバスで SPI を駆動すると、バスクロックに合わせて LED が点滅します。

ADC

nRF52840 には A0~A7 に露出した 8 つの 12 ビット ADC チャンネル(SAADC)があり、すべて 3.3 V 基準 です。read_u16 は、ピンでの 0 ~ 3.3 V にわたって 0 ~ 65535 を返します。ボードの AREF ピンは配線されていないため、リファレンスは常に 3.3 V です:

from machine import ADC
import time

adc = ADC("A0")
while True:
    voltage = adc.read_u16() * 3.3 / 65535
    print(voltage)
    time.sleep_ms(100)

PWM

nRF52840 は 4 つの PWM ペリフェラルPWM0PWM3)を公開し、それぞれが 4 チャンネル を駆動するため、合計で 16 個のハードウェア PWM スロット になります。固定機能のポートとは異なり、これらのペリフェラルは GPIOTE マトリックスを経由してルーティングされるため、どの GPIO も PWM 出力にできます。したがってピンとスライスのマッピングは存在しません。その柔軟性の代償として、シリコンに組み込まれた 2 つの制約があります。

  • 1 つのモジュール内の 4 つのチャンネルは、単一の周期 / 周波数 を共有します。

  • 各チャンネルは、独自のデューティサイクル と極性を持ちます。

概念的には、16 個のスロットは次のようになります。

モジュール

Ch 0

Ch 1

Ch 2

Ch 3

PWM0

duty

duty

duty

duty

PWM1

duty

duty

duty

duty

PWM2

duty

duty

duty

duty

PWM3

duty

duty

duty

duty

各行は 1 つの周波数で動作します。行内の 4 つのセルは、それぞれ独立して選択されたピンを独自のデューティサイクルで駆動します。異なる行は、まったく異なる周波数で動作できます。

シルク印刷されたピン(またはオンボードの LED)を machine.PWM 経由で駆動します:

from machine import Pin, PWM

pwm = PWM(Pin("D3"), freq=1_000, duty_u16=32768)

警告

自動割り当ては 1 回の呼び出しでモジュール全体を消費します。 device=/channel= キーワード引数なしで PWM を作成すると、ドライバは最初の空きモジュールを取得し、ピンをその チャンネル 0 のみにバインドします。そのモジュールの残り 3 つのチャンネルはアイドル状態のままで、明示的な device=/channel= を通じてのみ到達できます。このため、技術的にはまだ 12 個のスロットが空いているにもかかわらず、補助なしの PWM(Pin(...)) 呼び出しは 4 回 に制限され、その後ドライバは ValueError: all PWM devices in use を送出します。

4 つを超える PWM を使用する、またはピン間で意図的に周波数を共有するには、device(0 ~ 3)と channel(0 ~ 3)を渡します:

# Two PWMs on the same module → forced to share frequency,
# but each gets its own duty cycle.
pwm_a = PWM(Pin("D3"), device=0, channel=0,
            freq=1_000, duty_u16=32768)
pwm_b = PWM(Pin("D5"), device=0, channel=1,
            freq=1_000, duty_u16=16384)

# A third PWM on a separate module, free to pick any frequency.
pwm_c = PWM(Pin("D6"), device=1, channel=0,
            freq=20_000, duty_u16=49152)

デューティサイクルは duty(0 ~ 100%)、duty_u16(0 ~ 65535)、または duty_ns を受け付けます。invert=1 を追加すると出力の極性を反転できます(アクティブローの RGB LED に便利です)。

注釈

周波数はモジュール単位のプロパティであるため、モジュールの いずれか のチャンネルで pwm.freq(new_freq) を呼び出すと、そのモジュール全体に対して nrfx_pwm_init が再実行され、それを共有する他のすべてのチャンネルが認識する周波数が変わります。

注釈

許容される周波数は、おおよそ 4 Hz から 5.3 MHz までで、16 MHz のベースクロックから、プリスケーラ 1/2/4/8/16/32/64/128 と 15 ビットの周期カウンタによって導出されます。ドライバは最も近い除数を自動的に選択します。freq() は、正確に達成可能な値ではなく、要求された値を報告します。

ソフトウェアビットバンギングバス

追加のバスが必要な場合、machine.SoftI2Cmachine.SoftSPI は任意の GPIO 上で動作します。

サーマルセンサー(オフボード)

ファームウェアには、外部に配線されたサーマルイメージャ向けの fir --- 熱センサードライバー(fir == 遠赤外線) ドライバが含まれています。

  • MLX90621 — 16 × 4 IR アレイ

  • MLX90640 — 32 × 24 IR アレイ

  • MLX90641 — 16 × 12 IR アレイ

  • AMG8833 — 8 × 8 IR アレイ

モジュールをボードの 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 0 経由でのみセンサーと通信します。モジュールを I2C_SCL / I2C_SDA パッド(A5 / A4)に配線してください。

タイミング

time

time モジュールは、ブロッキング遅延、モノトニックティック、経過時間の測定をカバーします:

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)

仮想タイマー

machine.Timer は、ハードウェアタイマースロットを消費せずに、周期的または単発のコールバックをスケジュールします。仮想(ソフトウェア)タイマーを使用するには、id として -1 を渡します:

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() を呼び出します。

リアルタイムクロック

machine.RTC は、リセットをまたいで実時刻を保持します。nRF52840 の RTC はオンチップ発振器に接続されており、完全な電源喪失には耐えられません。アプリケーションにとって重要であれば、コールドブートのたびに時刻を設定してください:

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())

ウォッチドッグ

machine.WDT は、アプリケーションがハングするとボードをリセットします。一度開始すると停止や再構成はできません。メインループ内で定期的にフィードしてください:

from machine import WDT

wdt = WDT(timeout=5_000)   # 5 second window
while True:
    # ...do work...
    wdt.feed()

ブートおよびランタイム情報

ファームウェア更新

Nano 33 BLE Sense は、Arduino のブートローダーに入るために Arduino 標準の ダブルタップリセット を使用します。RESET ボタンを素早く 2 回押すと、ボードはブートローダーモードに入り、OpenMV IDE で新しいファームウェアイメージを書き込めます。

実行中のスクリプトは、machine.bootloader() を呼び出すことで、オンデマンドでブートローダーに再び入ることができます:

import machine

machine.bootloader()

ファイルシステムとブート順序

Nano 33 BLE Sense ファームウェアは、起動時に単一のファイルシステムをマウントします。

  • 内部フラッシュ — 常に /flash にマウントされ、作業ディレクトリとして使用されます。デフォルトで main.pyREADME.txt を保持します。初回起動時に作成されます。

マウント後、インタープリタは /flash からスクリプトを実行します。

  • boot.pyすべての ソフトリセット時に実行されます。

  • main.pyコールドブート時のみboot.py の直後に実行されます。

新しく書き込まれたボードに同梱されるデフォルトの main.py は、ハートビートとしてユーザー RGB LED の チャンネルを点滅させるだけです(短いパルス 2 回、短い間隔)。これにより、ホストを接続しなくてもファームウェアが正常に起動したことを確認できます。

/flash は、このボードでは USB マスストレージドライブとして公開され ません

ストレージサイズ

Nano 33 BLE Sense には次が同梱されています。

  • /flash64 KB の FAT ファイルシステム、読み書き可能。

Nano 33 BLE Sense のビルドには ROMFS が含まれていません。Python モジュールは /flash に直接配置してください。

ソフトウェアライブラリ

モジュールの完全なリストについては、ライブラリインデックス を参照してください。Nano 33 BLE Sense のビルド固有のモジュールも含まれています。