Neurobeat Zero documentation
Neurobeat Zero runs neurofeedback / EEG applications with low jitter and low latency on a single research-grade board, combining the ADS1299 analog front end with an ESP32-S3 application processor. It runs on battery and can be mounted in an EEG helmet or headset.
Overview
Zero is built around two parts: the ADS1299 (a 24-bit, low-noise EEG/biopotential ADC, 4 or 8 channels) and an ESP32-S3 application processor with Wi-Fi and Bluetooth LE. Because both live on the device, your processing loop doesn't have to round-trip to a computer. A single board does up to 8 channels; two boards chain or stack for 16, sharing a clock so samples stay aligned.
Getting started
- Connect a charged 2-cell (7.4 V) LiPo pack. Zero is not powered or charged over USB — charge the pack on its own charger, then plug it in.
- Attach electrodes (OpenBCI gold-cup with Ten20 paste, or active electrodes) to the channel header.
- Power on. The default application and settings ship with the device; the on-board LED indicates activity.
- Join the device to your network (below) to run the local app, push OTA updates, and read debug output without the USB cable.
Networking & the local app
The application runs on the ESP32-S3 and is served over HTTPS and secure WebSocket (WSS). After joining a network you can either run the app locally or provide SSID, password and an email. Registering your email gives you three things:
- You can find the device's local IP even after the DHCP lease changes.
- You can run OTA software updates — stock or your own apps — without the USB port.
- You can pull trace and log output for your app without the USB port.
The device uses the ESP32-S3's dual WIFI_AP_STA mode: it connects out to
the internet to fetch front-end libraries and proxies them to your browser, while also
serving the local app. Securely reaching a device on a private LAN from an HTTPS page
(without certificate warnings) is the classic "Plex method" — a publicly-trusted
wildcard certificate whose subdomain encodes the device's local IP. Note that some
routers' DNS-rebinding protection can block that pattern and may need an allow-list
entry.
OTA updates & anti-bricking
Updates use esp_https_ota over verified TLS with A/B partitions and
rollback. A new image only commits after a sustained health check — the
device must reach its cloud command channel and stay healthy — otherwise it rolls back
on the next reset. A watchdog converts a hang into a reset so rollback can trigger,
and a known-bad image is never re-downloaded.
The hardened design layers in a Secure Boot v2 + Flash Encryption story and an immutable recovery partition the bootloader falls back to if both OTA slots are unbootable, with a captive-portal recovery that opens only on a physical button held at boot. The guiding rule: ROM download mode is never disabled, so a device is always recoverable over USB as a last resort.
Stream & file format
Zero's native samples are 24-bit integers straight from the ADS1299. For storage and interchange, the recommended master format depends on a single requirement:
| Use case | Master format | Why |
|---|---|---|
| Single device | BDF | Stores raw 24-bit integers exactly, with a mandatory calibration/provenance header; near-universal reader support. |
| Multi-device live sync | XDF | The only format that represents sub-sample, cross-device clock synchronization (via Lab Streaming Layer). |
24-bit data fits losslessly in int32, so moving between BDF and XDF loses no signal —
the real difference is metadata enforcement and timing. The recommended architecture
is to write one master file on-device (BDF, or XDF via LSL when sync
is needed) and fan out to BrainVision / EEGLAB / EDF / CSV with established libraries
(MNE-Python, pyedflib) host-side, rather than hand-rolling serializers. When deriving
XDF from a BDF master, a small .bdf.meta sidecar carries exactly what BDF
can't: stream identity, the clock-offset table, and structured channel/hardware
metadata.
Power & deep sleep
Power comes from a 2-cell LiPo through an ideal diode and two low-dropout regulators — a 3.3 V digital rail and a 5 V analog rail — chosen so there's no switching noise on the analog supply. In deep sleep the board draws on the order of ~25 µA, which is roughly 1.5–2 years of standby on a charged pack. The ADS1299's PWDN pin is frozen with an RTC GPIO hold before sleep so the ADC doesn't float or wake when the main GPIO domain powers down.
Programming & pinout
Program over USB Micro B (data only). Zero is an ESP32-S3 target, so the usual Arduino-ESP32 / ESP-IDF / PlatformIO toolchains apply, and OTA works once the device is on your network. Both the ADS1299 and ESP32 expose SPI, I²C and GPIO on Feather-style headers. A typical SPI bring-up:
DRDY(data-ready) on a GPIO with a falling-edge interruptPWDNandSTARTas outputs, driven low at boot- Shared SPI bus with a chip-select per ADC; read with DMA on the data-ready interrupt
- Run the data-ready interrupt and DSP worker on a separate core from the web stack
Some sections above describe in-progress hardening and roadmap behavior; exact pins and defaults can vary by board revision — check the version notes that ship with your unit.