Arduino Nano 33 BLE Sense

Aviso

Esta placa não é mais suportada. A última versão do firmware OpenMV para a Arduino Nano 33 BLE Sense é a 4.7.0. Nenhuma atualização de firmware, correção de bugs ou novo recurso será lançado para este alvo. As informações abaixo são preservadas para usuários que executam a 4.7.0 ou versões anteriores.

A Arduino Nano 33 BLE Sense é uma placa de 45 × 18 mm no formato Arduino-Nano construída em torno do Nordic Semiconductor nRF52840 — um único ARM Cortex-M4 com FPU rodando a 64 MHz, com 256 KB de SRAM interna e 1 MB de flash interna. O BLE vem do rádio integrado ao chip, e a placa traz uma IMU de 9 eixos, um barômetro LPS22HB, um sensor de temperatura / umidade HTS221 / HS3003, um sensor de luz ambiente / cor / proximidade / gesto APDS9960 e um microfone PDM MP34DT05. O firmware OpenMV controla todos esses dispositivos a partir do MicroPython.

Arduino Nano 33 BLE Sense

Para a folha de dados completa, fotos e dimensões, consulte a página do produto Arduino Nano 33 BLE Rev2.

Destaques

  • Nordic nRF52840 Cortex-M4 com FPU a 64 MHz com 256 KB de SRAM interna e 1 MB de flash interna.

  • Bluetooth LE 5.0 via rádio integrado ao chip e Nordic SoftDevice s140.

  • IMU de 9 eixosLSM9DS1 na Rev 1, BMI270 + BMM150 na Rev 2. O driver congelado imu sonda ambos na inicialização.

  • Barômetro LPS22HB, sensor de temperatura e umidade HTS221 / HS3003, sensor de luz ambiente / cor / proximidade / gesto APDS9960 e microfone PDM MP34DT05.

  • Conector Micro USB para alimentação, programação e um REPL CDC.

  • 22 pinos de I/O de usuário nos headers padrão do Nano — TX/RX, D2D13 (digital), A0A7 (analógico).

Pinagem

Pinagem da Arduino Nano 33 BLE Sense

Referência de pinos

Nome do pino

Referência

Função

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

pressione o botão RESET integrado à placa ou puxe para GND para reiniciar

LED_BUILTIN

LED de usuário laranja em D13

LED_RED

Canal vermelho do LED RGB (ativo em nível baixo)

LED_GREEN

Canal verde do LED RGB (ativo em nível baixo)

LED_BLUE

Canal azul do LED RGB (ativo em nível baixo)

Aviso

Os pinos de I/O da Nano 33 BLE Sense são somente 3.3 V — eles não toleram 5 V. Aplicar 5 V neles danificará o nRF52840.

Pinos de alimentação

  • VIN — entrada de 4.5 – 21 V. Alimenta a placa através do regulador integrado. Também é alimentado, através de um diodo, a partir do trilho de 5 V do USB, de modo que o USB e o VIN podem estar presentes ao mesmo tempo sem retroalimentar um ao outro.

  • +5V — desconectado por padrão.

  • +3V3 — saída do regulador de 3.3 V.

  • AREF — pino de referência analógica. Não é conectado ao nRF52840 nesta placa — o ADC é sempre referenciado a 3.3 V.

  • GND — terra comum.

A Nano 33 BLE Sense pode ser alimentada por qualquer um dos caminhos:

  • Micro USB — fornece 5 V ao regulador integrado.

  • Pino VIN — aplique uma fonte regulada de 4.5 – 21 V.

Nota

Um jumper de solda na parte inferior da placa rotulado VUSB faz a ponte entre +5V e o trilho de 5 V do USB. Feche-o para que o pino de header +5V realmente conduza 5 V.

Nota

Um jumper de solda normalmente fechado na saída do regulador chaveado de 4.5–21 V integrado à placa pode ser cortado para desabilitar o regulador, de modo que a placa possa ser alimentada diretamente por uma fonte externa de 3.3 V em +3V3.

Pinos de recuperação e depuração

  • RESET — tanto um pad exposto quanto um botão RESET momentâneo na parte superior da placa, ligado à linha de reset do nRF52840. Puxe para GND ou pressione o botão para reiniciar.

A Nano 33 BLE Sense usa o toque duplo de reset (double-tap) padrão do Arduino para entrar no bootloader do Arduino. Pressione rapidamente o botão RESET duas vezes — a placa entra no modo bootloader e o OpenMV IDE pode gravar uma nova imagem de firmware.

Os sinais SWD do nRF52840 estão expostos em pads metalizados na parte de trás da placa. Todos os sinais de depuração são referenciados a 3.3 V.

Periféricos integrados à placa

LEDs

A Nano 33 BLE Sense tem um LED RGB de usuário — controlado através dos canais serigrafados LED_RED, LED_GREEN e LED_BLUE — além de um LED laranja LED_BUILTIN separado em D13. Todos os quatro são controláveis por software através de machine.LED

from machine import LED

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

Um LED verde de alimentação separado na placa acende sempre que o trilho de +3.3 V está ativo e não é controlável pelo usuário.

Sensor de câmera

O firmware OpenMV na Nano 33 BLE Sense suporta o sensor CMOS paralelo OmniVision OV7670. A placa não possui sensor de imagem integrado — conecte um módulo OV7670 aos pinos de header serigrafados listados abaixo e controle-o através do módulo csi — sensores de câmera

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

Nota

O OV7670 ocupa 14 pinos. O firmware os conecta da seguinte forma:

Sinal do sensor

Pino da 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)

O barramento de controle I²C do OV7670 é o mesmo I²C 0 externo exposto em A5/A4. O sensor fica no endereço de 7 bits 0x21 — os dispositivos de usuário nesse barramento devem evitar esse endereço quando a câmera estiver conectada.

IMU

A IMU de 9 eixos é exposta através do módulo congelado imu, que detecta automaticamente se a placa tem o LSM9DS1 (Rev 1) ou o BMI270 + BMM150 (Rev 2) e apresenta uma classe imu.IMU unificada. Os sensores ficam no barramento interno 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)

Para acesso direto a recursos como detecção de toque ou ao FIFO, importe o driver congelado correspondente (lsm9ds1, bmi270 ou bmm150) e instancie-o no mesmo barramento.

Sensores ambientais

O barômetro (LPS22HB) e o sensor de temperatura / umidade (HTS221 na Rev 1, HS3003 na Rev 2) compartilham o mesmo barramento interno I²C 1 com a IMU:

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)

Luz / cor / proximidade / gesto

O Broadcom APDS9960 fica no mesmo barramento interno I²C 1 e fornece detecção de luz ambiente, cor RGB, proximidade e gestos:

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)

Microfone

O microfone PDM MP34DT05 integrado à placa é capturado através de audio — Módulo de Áudio. Cada buffer chega como um bytearray PCM de 16 bits com sinal, pronto para ser alimentado em ulab/numpy para 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

Bluetooth

O rádio Bluetooth LE 5.0 do nRF52840 roda sobre o Nordic SoftDevice s140 e é exposto através do módulo legado ubluepy — as APIs modernas bluetooth / aioble — BLE Assíncrono não estão habilitadas nesta build. Tanto o papel de peripheral (servidor GATT, anunciar) quanto o de central (observador / scanner GAP + conectar) estão disponíveis.

Anuncie como peripheral com um único serviço Environmental Sensing e uma característica de temperatura notificável — o callback event_handler é disparado na conexão, desconexão e em escritas de 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])

Faça a varredura de dispositivos próximos que estão anunciando, no papel de central:

from ubluepy import Scanner

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

Consulte a referência de ubluepy para a API completa — UUID, Service, Characteristic, Peripheral, Scanner, ScanEntry e o namespace constants.

Referência de barramentos

GPIO

Use machine.Pin para ler ou acionar qualquer um dos pinos serigrafados. As saídas são CMOS de 3.3 V — 15 mA por pino, 25 mA no total para todas as GPIOs.

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

Qualquer pino de entrada também pode disparar uma interrupção em transições de borda:

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

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

UART

Barramento

TX

RX

UART1

TX

RX

Use os nomes de serigrafia TX/RX com machine.UART

from machine import UART

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

I²C

Barramento

SDA

SCL

I2C0

I2C_SDA / A4

I2C_SCL / A5

I2C1

P14

P15

Ambos os barramentos precisam ter seus pinos passados explicitamente para 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()

Nota

O barramento 1 é o barramento interno de sensores em P14/P15 (não está nos headers de usuário) — ele atende a IMU, o barômetro, o sensor ambiental e o APDS9960. Os drivers de sensor congelados o utilizam diretamente; o código de usuário também pode varrê-lo, mas os endereços já estão ocupados pelos sensores integrados à placa.

SPI

Barramento

MOSI

MISO

SCK

CS

SPI0

D11

D12

D13

D10

A linha CS não é acionada pelo periférico SPI — configure D10 como saída e alterne-a manualmente em torno da transferência:

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)

Nota

D13 funciona também como o LED laranja LED_BUILTIN — acionar SPI nesse barramento fará o LED piscar em sincronia com o clock do barramento.

ADC

O nRF52840 tem oito canais ADC de 12 bits (SAADC) expostos em A0–A7, todos referenciados a 3.3 Vread_u16 retorna 0–65535 ao longo de 0–3.3 V no pino. O pino AREF da placa não é conectado, portanto a referência é sempre 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

O nRF52840 expõe quatro periféricos PWM (PWM0PWM3), cada um acionando quatro canais, totalizando 16 slots de PWM por hardware. Diferentemente de portas de função fixa, os periféricos roteiam através da matriz GPIOTE — qualquer GPIO pode ser uma saída PWM, portanto não há um mapeamento fixo de pino para slice. O custo dessa flexibilidade são duas restrições incorporadas no silício:

  • Todos os quatro canais dentro de um módulo compartilham um único período/frequência.

  • Cada canal tem seu próprio ciclo de trabalho (duty cycle) e polaridade.

Conceitualmente, os 16 slots se parecem com isto:

Módulo

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

Cada linha roda em uma frequência; as quatro células de uma linha acionam, cada uma, um pino escolhido independentemente com seu próprio ciclo de trabalho. Linhas diferentes podem rodar em frequências completamente diferentes.

Acione qualquer pino serigrafado (ou os LEDs integrados à placa) via machine.PWM

from machine import Pin, PWM

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

Aviso

A alocação automática consome um módulo inteiro por chamada. Quando você cria um PWM sem os kwargs device=/channel=, o driver pega o primeiro módulo livre e vincula seu pino apenas ao canal 0 dele. Os três canais restantes desse módulo ficam ociosos e só podem ser alcançados através de device=/channel= explícitos. Isso limita as chamadas PWM(Pin(...)) sem auxílio a quatro antes de o driver levantar ValueError: all PWM devices in use — mesmo que doze slots ainda estejam tecnicamente livres.

Para usar mais de quatro PWMs, ou para compartilhar deliberadamente uma frequência entre pinos, passe device (0–3) e 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)

O ciclo de trabalho aceita duty (0–100%), duty_u16 (0–65535) ou duty_ns. Adicione invert=1 para inverter a polaridade da saída (útil para o LED RGB ativo em nível baixo).

Nota

Como a frequência é uma propriedade por módulo, chamar pwm.freq(new_freq) em qualquer canal de um módulo executa novamente nrfx_pwm_init para o módulo inteiro e altera a frequência vista por todos os outros canais que o compartilham.

Nota

As frequências permitidas abrangem aproximadamente 4 Hz a 5.3 MHz, derivadas do clock base de 16 MHz com prescalers 1/2/4/8/16/32/64/128 e um contador de período de 15 bits. O driver escolhe automaticamente o divisor mais próximo — freq() reporta o valor solicitado, não o valor exato alcançável.

Barramentos por software (bit-banged)

machine.SoftI2C e machine.SoftSPI funcionam em qualquer GPIO caso você precise de um barramento adicional.

Sensor térmico (externo à placa)

O firmware inclui o driver fir — driver de sensor térmico (fir == far infrared) para câmeras térmicas conectadas externamente:

  • MLX90621 — matriz IR de 16 × 4

  • MLX90640 — matriz IR de 32 × 24

  • MLX90641 — matriz IR de 16 × 12

  • AMG8833 — matriz IR de 8 × 8

Conecte o módulo ao barramento I²C da placa e leia os quadros com 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())

O driver fir só se comunica com o sensor através do I²C 0 — conecte o módulo aos pads I2C_SCL / I2C_SDA (A5 / A4).

Temporização

time

O módulo time cobre delays bloqueantes, ticks monotônicos e medição de tempo decorrido:

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)

Timers virtuais

machine.Timer agenda callbacks periódicos ou de disparo único sem consumir um slot de timer por hardware. Passe -1 como id para usar um timer virtual (por software):

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

Os valores de período são em milissegundos. Chame deinit() para parar e liberar o slot.

Relógio de tempo real

machine.RTC mantém o horário do relógio de parede entre reinicializações. O RTC do nRF52840 é ligado ao oscilador interno do chip e não sobrevive a uma perda total de energia — ajuste o horário em cada inicialização a frio se isso for importante para sua aplicação:

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 reinicia a placa se a aplicação travar. Uma vez iniciado, não pode ser parado ou reconfigurado — alimente-o periodicamente dentro do seu laço principal:

from machine import WDT

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

Informações de boot e tempo de execução

Atualização de firmware

A Nano 33 BLE Sense usa o toque duplo de reset (double-tap) padrão do Arduino para entrar no bootloader do Arduino. Pressione rapidamente o botão RESET duas vezes — a placa entra no modo bootloader e o OpenMV IDE pode gravar uma nova imagem de firmware.

Um script em execução pode reentrar no bootloader sob demanda chamando machine.bootloader()

import machine

machine.bootloader()

Sistema de arquivos e ordem de boot

O firmware da Nano 33 BLE Sense monta um único sistema de arquivos na inicialização:

  • Flash interna — sempre montada em /flash e usada como diretório de trabalho. Contém main.py e README.txt por padrão; criada na primeira inicialização.

Após a montagem, o interpretador então executa scripts a partir de /flash:

  • boot.py é executado a cada soft reset.

  • main.py é executado somente na inicialização a frio, imediatamente após boot.py.

O main.py padrão fornecido em uma placa recém-gravada apenas pisca o canal azul do LED RGB de usuário como um heartbeat (dois pulsos curtos, intervalo curto), para que você possa saber que o firmware inicializou corretamente sem nenhum host conectado.

/flash não é exposto como uma unidade de armazenamento em massa USB nesta placa.

Tamanhos de armazenamento

A Nano 33 BLE Sense vem com:

  • /flash — sistema de arquivos FAT de 64 KB, leitura/escrita.

A build da Nano 33 BLE Sense não inclui um ROMFS; entregue os módulos Python diretamente em /flash.

Bibliotecas de software

Consulte o índice da biblioteca para a lista completa de módulos — incluindo quais são exclusivos da build da Nano 33 BLE Sense.