V
Visla Hardware
Portal R&D
🧩 Moduli & Shield ✓ Verified · 2026-07-21 🆕 Nuovo ⚡ Low power ble ranging

XIAO nRF54LM20A Sense

Seeed Studio
📦 Dev board
€13.90
Seeed XIAO nRF54LM20A Sense
📡 Channel Sounding OK: ranging BLE 6.0 (~2 m, phase_slope)🛠️ GATT Config Service: provisioning tracker da app (no cellulare)BLE 6.0 · nRF54L 128MHzIMU + nPM1300 onboardCMSIS-DAP onboard (flash USB)
📑 Indice sezioni

Curiosity

Il fratello maggiore dell’XIAO nRF54L15: monta il nRF54LM20A — stessa famiglia nRF54L (Cortex-M33 128 MHz + coprocessore RISC-V FLPR, BLE 6.0 / Thread / Matter / Zigbee) ma con più memoria (~1.5 MB flash / 256 KB RAM). Versione Sense: IMU LSM6DS3TR-C 6 assi + PMIC nPM1300 (charging + fuel gauge) già a bordo. È la direzione MCU del Visla Tag di prossima generazione. Richiede Zephyr RTOS (Arduino non supporta ancora l’nRF54L). A differenza della L15 Sense, entra nella XIAO Expansion Board standard — verificato al bench Visla (OLED + buzzer + pulsante funzionanti).

Specs tecniche

ParametroValore
ChipNordic nRF54LM20A (Cortex-M33 128 MHz + RISC-V FLPR)
Memoria~1.5 MB flash / 256 KB RAM (più della L15)
Form factorXIAO standard 21×17.8 mm · 28 pin (D0-D27), 9 analogici
Sensori onboardIMU LSM6DS3TR-C 6 assi (accel+giro)
PMIC onboardnPM1300 (charging LiPo + fuel gauge)
ConnettivitàBLE 6.0 · Thread · Matter · Zigbee · 2.4 GHz proprietario
Debug/FlashCMSIS-DAP onboard → flash da USB-C, niente J-Link né UF2
SoftwareZephyr RTOS / nRF Connect SDK (no Arduino IDE)
Compat carrierXIAO Expansion Board ✅ (verificato) · XIAO Grove Base ✅

🔧 Bring-up dal bench Visla (21 lug 2026)

Bring-up completo su Zephyr con la XIAO Expansion Board (OLED SSD1306 + buzzer + pulsante + LED RGB): tutto funzionante. Sintesi per non ripartire da zero.

La board ha un debugger CMSIS-DAP integrato → si flasha da USB-C con openocd:

west flash --runner openocd     # openocd NCS via nrfutil toolchain-manager launch

openocd auto-sblocca l’APPROTECT di fabbrica (mass-erase via CTRL-AP). Reset manuale: openocd -f <board>/support/openocd.cfg -c "init; reset run; exit". Console = uart20 → USB CDC /dev/cu.usbmodem… a 115200.

Board definition: da Zephyr mainline

boards/seeed/xiao_nrf54lm20a è in Zephyr mainline ma NON in NCS 3.3.0 (che ha solo la xiao_nrf54l15). Il SoC è già supportato → si scaricano i file board da raw.githubusercontent.com/zephyrproject-rtos/zephyr/main/boards/seeed/xiao_nrf54lm20a/ (incluso support/openocd.cfg) dentro il workspace. Build: -b xiao_nrf54lm20a/nrf54lm20a/cpuapp.

I 3 gotcha (board mainline su NCS 3.3.0)

  1. usbhs_wrapper → vregusb: l’USB nativo referenzia &vregusb (disabled) → errore __device_dts_ord_NNN undeclared. Fix overlay: &usbhs_wrapper { status = “disabled”; }; (l’USB nativo non serve, la console è sul CMSIS-DAP).
  2. CFB (display) usa k_malloc → serve CONFIG_HEAP_MEM_POOL_SIZE=4096.
  3. OLED a pixel random: il TWIM nRF54 manda i 1024 B del framebuffer in una transazione ma il concat-buffer è 16 B → i2c_nrfx_twim: internal buffer insufficient (1+1024>16). Fix: &i2c22 { zephyr,concat-buf-size = <1088>; };.

Pinout Expansion Board (mappa XIAO LM20A)

PeripheralPin XIAOGPIO nRF54Note
OLED SSD1306 128×64D4/D5 (I2C)gpio1.3 / gpio1.7 (i2c22)@ 0x3C
Buzzer passivoA3 = D3gpio1.29no PWM instradato → bit-bang ~2.7-3 kHz
Pulsante utenteD1gpio1.31pull-up, active-low
LED RGB (blu/rosso/verde)gpio1.22 / 1.23 / 1.24onboard

Firmware di test: xiao-nrf54lm20a-test (OLED via CFB + buzzer + button + LED + BLE advertising). Da qui è nato anche un radar BLE (BLE observer) che sente i beacon Visla vicini e li mostra sull’OLED (device ID, RSSI, contatore pressioni) con beep alla pressione del pulsante.

📡 Channel Sounding — ranging BLE 6.0 (21 lug 2026)

La feature che rende l’nRF54 interessante per Visla: misura la distanza cm-level tra due device. Provata end-to-end al bench Visla — XIAO nRF54LM20A = initiatorHolyiot 25008 (nRF54L15) = reflector. Sull’OLED della XIAO compare la distanza in tempo reale + un allarme di prossimità tipo guinzaglio antifurto (beep oltre soglia).

Risultato al banco

Metodo di stimaLetturaNote
phase_slope~2.0 m (stabile)il più affidabile → è quello che usiamo
ifft0.6–1.8 mpiù rumoroso (multipath)
rtt~6 mround-trip time, il meno preciso su BLE

Spostando il reflector la lettura phase_slope segue la distanza; oltre PROXIMITY_ALARM_M (3 m di default) l’OLED passa a “!! LONTANO !!” con beep intermittente e LED verde spento.

Come è fatto

Sample NCS nrf/samples/bluetooth/channel_sounding (2 ruoli RAS: initiator / reflector). CS NON è broadcast: richiede una connessione tra due device CS-capable, entrambi col SoftDevice Controller di Nordic. Chip CS-capable: nRF54L15/L10, nRF54LM20A/B, nRF54H20 (il nRF54L05 no; nRF52 no).

Gotcha per portarlo su XIAO / Holyiot

  • Antenna singola (default) → nessun overlay cs_antenna_switch necessario.
  • XIAO initiator, overlay obbligatorio: la board mainline Seeed forza il controller Zephyr LL (no CS) → ripuntare sul SDC (&bt_hci_controller{disabled}; &bt_hci_sdc{okay}; chosen{zephyr,bt-hci=&bt_hci_sdc}) + il solito &usbhs_wrapper{disabled}.
  • Holyiot reflector: nessun overlay, usa già l’SDC di default. Flash via J-Link; la XIAO via CMSIS-DAP.
  • Reflector che non riparte dopo un flash della XIAO: resta incastrato “connesso” → power-cycle della CR2032 e riparte in advertising.

Firmware: cs-initiator-xiao (OLED distanza + allarme) · cs-reflector-holyiot.

🛠️ Config del tracker dall’app via BLE (21 lug 2026)

Provisioning del tracker GPS direttamente dall’app, senza cellulare. Un GATT Config Service custom sulla XIAO espone i parametri del tracker come caratteristiche leggibili/scrivibili: l’app si connette in BLE e li configura. Prototipato end-to-end usando il Mac come “app” (Python bleak) → letto la config di fabbrica, riscritto label=‘Tag-Mario’ interval=30s mode=HIGH, riletto ✅, con status notify live (batteria / uptime / GPS fix). L’OLED mostra la config corrente.

Servizio “Visla Config” (UUID base f5a1xxxx-9c3f-4b2a-9e11-435356010000)

CaratteristicaUUIDTipoAccesso
Report interval..0002uint16 LE (5–3600 s)R / W
GPS mode..0003uint8 (0 off·1 eco·2 norm·3 high)R / W
Tracker label..0004utf8 ≤20 BR / W
Status..0005batt% + uptime + fixR / Notify

Advertising nome Visla-Cfg + UUID128 nell’AD (così l’app filtra). Write validate lato firmware (range/lunghezza → BT_ATT_ERR_*).

È un pilastro del Visla Tag/v2: primo setup, cambio APN/server, intervalli — dallo smartphone, senza SIM attiva. Prossimi passi: persistenza in flash (subsystem settings), campi v2 (APN/server/token), pairing + write cifrate (ora il servizio è aperto), poi app iOS/Android.

Firmware: xiao-nrf54lm20a-ble-config (GATT service + OLED) — l’“app” Mac di test è nel README.

🔗 Risorse