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 Rev2 製品ページ を参照してください。
ハイライト¶
Nordic nRF52840 — 64 MHz で動作する FPU 付き Cortex-M4。256 KB の内部 SRAM と 1 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/RX、D2~D13(デジタル)、A0~A7(アナログ)。
ピン配置¶
ピンリファレンス¶
ピン名 |
リファレンス |
機能 |
|---|---|---|
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 |
— |
|
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_RED、LED_GREEN、LED_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 |
|
D1 |
|
D2 |
|
D3 |
|
D4 |
|
D5 |
|
D6 |
|
D7 |
|
HSYNC |
|
VSYNC |
|
PXCLK |
|
MXCLK |
|
POWER |
|
RESET |
|
SCL |
|
SDA |
|
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 などの機能に直接アクセスするには、対応するフリーズされたドライバ(lsm9ds1、bmi270、または 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 リファレンスを参照してください — UUID、Service、Characteristic、Peripheral、Scanner、ScanEntry、そして 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/RX を machine.UART とともに使用します:
from machine import UART
uart = UART(1, baudrate=115200)
uart.write("hello")
uart.read(5)
I²C¶
バス |
SDA |
SCL |
|---|---|---|
I2C0 |
|
|
I2C1 |
|
|
どちらのバスも、ピンを 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 ペリフェラル(PWM0~PWM3)を公開し、それぞれが 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.SoftI2C と machine.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.pyとREADME.txtを保持します。初回起動時に作成されます。
マウント後、インタープリタは /flash からスクリプトを実行します。
boot.pyは すべての ソフトリセット時に実行されます。main.pyは コールドブート時のみ、boot.pyの直後に実行されます。
新しく書き込まれたボードに同梱されるデフォルトの main.py は、ハートビートとしてユーザー RGB LED の 青 チャンネルを点滅させるだけです(短いパルス 2 回、短い間隔)。これにより、ホストを接続しなくてもファームウェアが正常に起動したことを確認できます。
/flash は、このボードでは USB マスストレージドライブとして公開され ません。
ストレージサイズ¶
Nano 33 BLE Sense には次が同梱されています。
/flash— 64 KB の FAT ファイルシステム、読み書き可能。
Nano 33 BLE Sense のビルドには ROMFS が含まれていません。Python モジュールは /flash に直接配置してください。
ソフトウェアライブラリ¶
モジュールの完全なリストについては、ライブラリインデックス を参照してください。Nano 33 BLE Sense のビルド固有のモジュールも含まれています。