ADS1299 Register Configuration
PiEEG-server exposes real-time ADS1299 register configuration over WebSocket. Change channel input modes, run noise diagnostics, and apply presets — all live, without restarting the stream.
This feature works on PiEEG boards (SPI). IronBCI boards use Bluetooth LE and do not expose register writes.
Capabilities
- Switch input modes on the fly — normal electrodes, input shorted (noise floor test), test signal, temperature sensor
- Run noise diagnostics — built-in test with per-channel RMS and automated pass/fail verdict
- Apply named presets — one command to configure all 8 channels at once
- Automate from any language — plain WebSocket JSON commands
Configurable registers
Channel registers CH1SET–CH8SET (addresses 0x05–0x0C) can be written at runtime. Configuration registers (CONFIG1–CONFIG3) are protected to prevent accidental sample-rate or reference changes.
Input modes
| Value | Mode | Description |
|---|---|---|
0x00 | Normal electrode | Standard EEG measurement — default after startup |
0x01 | Input shorted | Both inputs tied together internally — measures baseline noise |
0x02 | Bias measurement | Routes bias signal to channel — verify bias drive circuit |
0x04 | Temperature sensor | On-chip temperature sensor — useful for thermal diagnostics |
0x05 | Test signal | Internal 1× amplitude square wave from CONFIG2 — verify signal chain |
WebSocket commands
Read current register state
{"cmd": "reg_read"}Response:
{"reg_config": {"regs": {"0x05": "0x0", "0x06": "0x0", ...}, "status": "ok"}}Write individual registers
{"cmd": "reg_write", "regs": {"0x05": "0x00", "0x06": "0x01", "0x07": "0x05"}}This sets CH1 to normal, CH2 to input shorted, and CH3 to test signal. Other channels remain unchanged.
Apply a preset
{"cmd": "reg_preset", "preset": "internal_short"}| Preset | Value | Use case |
|---|---|---|
normal | 0x00 all channels | Resume standard measurement |
internal_short | 0x01 all channels | Measure noise floor — no electrodes needed |
test_signal | 0x05 all channels | Verify full signal chain with known waveform |
temp_sensor | 0x04 all channels | Read on-chip temperature |
Run noise test
{"cmd": "noise_test", "duration": 3}Switches all channels to input-shorted mode, collects samples for the specified duration, computes per-channel RMS, then restores the previous configuration.
Response:
{
"noise_test_result": {
"rms": [2.5, 2.3, 3.1, 2.8, 2.6, 2.4, 2.9, 3.0],
"max_rms": 3.1,
"verdict": "good",
"recommendation": "Electrodes OK",
"duration": 3.0,
"samples_collected": 750
}
}| Verdict | Meaning |
|---|---|
good | All channels below 5 µV RMS — normal |
warning | Some channels 5–15 µV — check electrode contact |
bad | Channels above 15 µV — likely loose or disconnected electrodes |
Dashboard register panel
The dashboard includes a visual Register panel for register configuration without writing code:
- Per-channel input mode selector (dropdown)
- One-click presets (Normal, Shorted, Test Signal, Temperature)
- Noise test button with live progress and color-coded results
- Current register state display
How it works internally
- Dashboard or client sends a WebSocket command
- Server validates — only
CHnSETregisters (0x05–0x0C) are allowed - Acquisition thread pauses gracefully
- SPI sequence:
STOP→SDATAC→ register writes →RDATAC→START - First 25 frames (~100 ms) discarded for ADC settling
- Spike filter baseline resets to avoid false rejections
- Updated register state broadcast to all connected clients
Register writes temporarily pause data acquisition (~100 ms). This is normal and required by the ADS1299 datasheet.
Example: automated noise check in Python
import asyncio, json, websockets
async def noise_check():
async with websockets.connect("ws://raspberrypi.local:1616") as ws:
await ws.send(json.dumps({"cmd": "noise_test", "duration": 3}))
async for msg in ws:
data = json.loads(msg)
if "noise_test_result" in data:
result = data["noise_test_result"]
print(f"Verdict: {result['verdict']}")
for i, rms in enumerate(result["rms"]):
print(f" CH{i+1}: {rms:.1f} µV RMS")
break
asyncio.run(noise_check())