harden sensor acquisition after audit

This commit is contained in:
Jay
2026-08-17 09:48:05 -04:00
parent f1ac20fb4f
commit b8fe233ba6
11 changed files with 376 additions and 50 deletions
+76
View File
@@ -0,0 +1,76 @@
# Audit Hardening — 2026-08-17
This pass addresses the findings from the independent prototype-v0 audit. It
does not add calibration, BLE, persistent storage, filtering beyond the selected
L3G4200D hardware filter, or sensor fusion.
## Git checkpoints
- `f1ac20f`: exact pre-hardening firmware and axis-validation baseline
- The verified hardening changes are committed separately after this report
No remote repository is configured; these are local history checkpoints.
## Changes
- A clean build now selects `esp32c3` from `sdkconfig.defaults`.
- ADXL345 `INT_SOURCE` and L3G4200D `STATUS_REG` are read immediately before
their corresponding six-byte XYZ reads.
- Raw status bytes and a cumulative loop-overrun count are appended to CSV.
- A delayed acquisition loop resynchronizes rather than issuing catch-up bursts.
- ADXL345 FIFO, interrupt enables, and hardware offset registers are explicitly
reset during initialization so warm MCU resets are deterministic.
- L3G4200D LPF2 is routed to the output with `CTRL_REG5=0x02`, making the
configured 25 Hz cutoff effective.
- Both sensor drivers remove their I2C device handles after an initialization
failure and expose deinitializers.
- Candidate-address loops use an element count rather than byte size.
- The capture utility auto-detects a single USB modem port, writes numeric CSV
only, and reports sequence gaps, resets, timestamp anomalies, malformed
records, and ignored non-record lines.
- Documentation now distinguishes the MCU poll timestamp and nominal scale from
sensor sample timing and measured per-axis scale.
## Build validation
- Normal incremental build: pass
- Clean temporary copy with no `sdkconfig` or `build/`: pass
- Clean configuration selected `CONFIG_IDF_TARGET="esp32c3"` from
`sdkconfig.defaults`
- Hardened binary size: `0x242d0` bytes; 86% of the application partition free
## Hardware validation
The hardened firmware was flashed to the assembled XIAO ESP32-C3 prototype.
Both devices initialized successfully after a USB-triggered warm reset, including
all new register writes and the L3G4200D CTRL5 readback.
The capture `captures/hardening_freshness.csv` contains:
- 3,796 consecutive records
- Sequence gaps: 0
- Sequence resets: 0
- Timestamp anomalies: 0
- Timestamp interval: 10,000 us for all 3,795 intervals
- Rejected records: 0
- Acquisition loop overruns: 0
- ADXL345 DATA_READY clear at status time: 192 records (5.058%)
- ADXL345 overrun set: 0 records
- L3G4200D ZYXDA clear: 0 records
- L3G4200D ZYXOR set: 112 records (2.950%)
The ADXL345 clear events have a coherent 27/28-poll pattern, including adjacent
clear events when a device update likely occurs between the separate status and
data transactions. A clear bit is therefore conservatively treated as
stale/untrusted; a set bit proves unread data existed before the read. The gyro
overrun pattern directly confirms that its internal output clock is faster than
the MCU poll on this unit.
These results validate the audit finding that exact 100 Hz MCU polling does not
mean either sensor is synchronized to that clock. Status labeling is the scoped
prototype fix. Interrupt/FIFO-driven acquisition remains a later buffering task.
A final post-build/post-flash smoke capture added another 1,634 consecutive
records with zero gaps, timestamp anomalies, rejected records, ADXL345 overruns,
or acquisition-loop overruns. It again exposed ADXL345 DATA_READY clear on 81
polls and L3G4200D overrun on 48 polls.
+10 -1
View File
@@ -4,10 +4,19 @@ The enclosure was tested with the battery end treated as the bottom of the
reference orientation. The shared enclosure frame is +X right, +Y toward the
top, and +Z toward the cover.
## Audit clarification
The timing results below validate the ESP32-C3 polling loop, not the independent
sensor sample clocks. A subsequent review of the capture found a coherent repeated
ADXL345 sample approximately every 27 polls, consistent with an actual device ODR
near 96.3 Hz. This does not affect the static six-position axis result. Firmware v2
adds ADXL345 and L3G4200D freshness/overrun status to every record so dynamic data
can be interpreted correctly.
## Capture integrity
- 50,001 consecutive samples over 500.000 seconds
- Effective sample rate: exactly 100 Hz
- Effective MCU polling rate: exactly 100 Hz
- Timestamp interval: 10,000 us for every sample
- Sequence gaps: 0
- Axis-mapping mismatches between mapped and native columns: 0