The SNUADC firmware¶
The public SNUADC firmware explains the board's timing: it sends no time stamps, samples on its 16 MHz crystal, loses time rather than bunching samples after a stall, reads its channels one after another, and truncates its values. A predicted fault at the microsecond counter's wrap was not found in the data.
| Date | 2026-10-13 |
| Status | current |
| Methods | Reading the source, Clocks carried in the signal |
| Techniques | Predict, then test |
| Clocks | SNUADC sample clock, Monitor analogue output clock |
| Devices | SNUADC, Vital Recorder |
| Variables | ECG lead II (SNUADC), Arterial pressure (SNUADC), Plethysmogram (SNUADC) |
Background¶
Several measured behaviours (the stamp sawtooth, the signal lost at resets, a sub-millisecond skew between channels) needed a mechanism. The board's firmware is public.
Data¶
Source: github.com/vitaldb/snuadc, firmware/SNUADC/SNUADC.ino (an Arduino sketch for an ATmega32U4). The wrap prediction was tested on 6 files with the 240 Hz monitor line (17 October).
Method¶
The sampling, transmission and calibration code was read for what it predicts about timing and values, and each prediction was checked against the measurements in the atlas. One prediction (extra samples at each wrap of the microsecond counter, every 2³² µs = 4,295 s of uptime) was tested directly: a fine step search on the sample-count timeline of the 240 Hz monitor line (standard error 0.04–0.1 ms) for steps 4,295 s apart.
Results¶
- No time stamps in the stream. Each sample is 4 × 3 bytes (two 10-bit channels per 3 bytes) over USB serial. The board sends no time, so the recorder stamps by sample count: the reason the SNUADC sawtooth and the stamp model exist.
- Crystal clock. Sampling is timed by micros() on the 16 MHz crystal, so the long-term rate is the crystal's; crystal tolerance gives the tens of ppm measured against the recorder.
- No catch-up after an overrun. The schedule is us_next = max(us_next + us_wait, now): a late sample resets the schedule instead of sending extra samples, so a stall of more than 2 ms loses time rather than bunching samples. The rate is set by the recorder (500 Hz = 2,000 µs exactly; up to 1,000 Hz).
- Channel skew. The 8 channels (pins A11, A6, A0–A5, in that order) are read one after another, about 0.1 ms each, so the last is read up to about 0.8 ms after the first. Which track each pin carries is not stated.
- Value scale. A 10-bit converter on the internal 2.56 V reference; a two-point calibration in EEPROM maps −4 V and +4 V to counts 102.4 and 921.6; the result is truncated (not rounded) and clamped to 0–1023. Truncation biases values down by half a count (about 0.5 mmHg for arterial pressure). The arterial ceiling near count 917 is the monitor's +4 V output (about 400 mmHg); the ECG clips at 0 and 1023.
- Event inputs. Two event jacks are sent as flag bits with each sample: a possible same-clock marker, if any case used them.
- The predicted wrap fault is not seen: no steps 4,295 s apart, and half the files have no step shared by PLETH and ART in the window where one was due. A few isolated shared steps of 0.2–1.9 ms remain unexplained.
Discussion¶
The stall rule explains the signal lost at each reset (Records out of order at SNUADC resets, and where the lost time goes): the acquisition pauses about 20 ms and the time is never sampled. The channel skew fits the 0.31–0.39 ms ART–PLETH phase difference at 240 Hz (Monitor clocks in the waveforms' spectral lines). The wrap result means either the per-sample processing time is close to 2 ms, or the deployed firmware differs from the public one.
Observations it supports¶
| Observation | Status | Summary |
|---|---|---|
| About 20 ms of signal lost at every SNUADC reset | established | At each step-mode reset the acquisition pauses for about 20 ms inside the last record before the new timing, and that time is never sampled: 17.7 ms on the sample count (Signal lost at a SNUADC step-mode correction), once the filler sample is counted. Every record still holds 100 samples, so nothing in the file shows it. |
| SNUADC sends no time; the recorder stamps by count | established | The SNUADC board streams samples with no time stamps. Every SNUADC time in VitalDB is the recorder's model of the board's clock: the sample count at the nominal rate, pulled back when it drifts too far. |
| SNUADC channels are read one after another | likely | The SNUADC firmware reads its 8 channels in turn, about 0.1 ms each, so within one sample the last channel is read up to about 0.8 ms after the first. The channel order is not known. |
| SNUADC values are truncated to the count below | likely | The SNUADC firmware truncates each calibrated value instead of rounding it, so every value sits half a count low on average (about 0.5 mmHg for arterial pressure). Values clamp at counts 0 and 1023. |
| SNUADC has two event inputs | open | The firmware sends two event-jack flags with every sample. If any case used them, they would be markers on the SNUADC's own clock. |
Limitations¶
Read, not tested on the device. The deployed firmware version is unknown; the channel-to-track mapping is unknown.
Open questions¶
- Which firmware ran (unexplained phenomenon). The deployed version, and which converter channel feeds which track, are not known.
References¶
- VitalDB. SNUADC: firmware and hardware of the VitalDB analogue-to-digital converter. GitHub. ↗