Skip to content

MCU Firmware

The rpi-seism firmware runs on the sensor PCB microcontroller. Its sole job is to drive the ADS1256 24-bit ADC, multiplex three geophone channels, and stream validated binary packets to the daemon over RS-422 at 250 kbps.


TargetBoardNotes
STM32Generic STM32 seriesPrimary production target
RP2040Raspberry Pi Pico / Pico 2Excellent PIO-based SPI
ESP32ESP32 / ESP32-S3Wi-Fi can be used for OTA updates
AVRArduino Uno / NanoLimited RAM; use for prototyping only
TeensyTeensy 4.0/4.1Highest throughput; ideal for >200 SPS

24-bit ADC Sampling

Drives the ADS1256 with hardware SPI. Three differential channels are multiplexed in a fixed Z → N → E → (discard) sequence using cycleDifferential().

CRC-32 Integrity

Every 18-byte packet carries a CRC-32 checksum over the header and three channel values. The daemon discards packets with mismatches and re-aligns to the next 0xAA 0xBB header.

Runtime Configuration

Sample rate, ADC gain, and data rate are set at runtime via the Settings Handshake — no reflashing required. The MCU echoes the settings packet back for verification.

Dead-client Detection

A consecutive-TX-failure counter triggers HAL_NVIC_SystemReset() if the daemon stops reading, preventing silent buffer overflow.


GD-4.5 Geophone (×3)
LT1167 Instrumentation Amplifier (~×5.5 gain)
ADS1256 24-bit ADC (differential, 3-channel MUX)
│ SPI
MCU ──────► MAX490E RS-422 Transceiver ──► Cat5/6 ──► Host PCB ──► Raspberry Pi

The firmware runs a tight superloop (no RTOS). Each iteration:

  1. Checks whether a settings packet (0xCC 0xDD) is waiting in the UART RX buffer and applies it.
  2. Calls cycleDifferential() four times — Z, N, E, then a fourth discarded cycle to re-sync the ADS1256 MUX (the ADC latches the next channel selection on the previous conversion’s completion, so the fourth call advances back to channel 0 cleanly).
  3. Packs the three int32 values + CRC-32 into an 18-byte frame and writes it to the RS-422 UART.
  4. Checks the heartbeat watchdog — if no 0x01 byte arrives within ~1 s, streaming is paused.