53 Commits

Author SHA1 Message Date
onur cayan 677c2917c0 docs: clarify GPS SoC build and diagnostics 2026-08-13 11:32:14 +03:00
onur cayan 8850ece2a4 fix(efinity): stream build progress without buffering 2026-08-13 02:26:42 +03:00
onur cayan 3cc609a350 fix(efinity): discover installed tools and serialize builds 2026-08-13 02:15:20 +03:00
onur cayan 584a69302a fix(efinity): fail early when toolchain is missing 2026-08-13 01:47:09 +03:00
onur 1dbd1b5151 Merge tdk_new and Ti375 Efinity support
Keep the current GPS software and Genesys2/VCU118 flows while integrating Ti375C529 Efinity, flash, programming, and debug support. Add board-specific SPI NOR profiles and persistent GPS flash layouts across all three boards.
2026-08-13 01:28:46 +03:00
onur a25a1a61d0 fix(gps): make ephemeris flash persistence hardware-safe
Add freestanding S25FL256S read/program/erase/verify support and seed a newly formatted ephemeris store with stale records. Age-gate navigation readiness, persist the continuous Toe week, and regenerate the Genesys2 MAX2771 integration and flash image.
2026-08-13 00:50:57 +03:00
onur 97e3a71ab9 chore(repo): stop tracking transient Vivado outputs 2026-08-13 00:49:27 +03:00
onur f59d6ebb43 fix(gps): correct week-number handling across almanac, ephemeris and flash
Persisting navigation data changed its lifetime from one power cycle to
weeks, and every piece of arithmetic that had only ever run over the
shorter lifetime turned out to be wrong. Each fix below reproduces in a
host test that fails against the previous behaviour.

Almanac (gps_almanac.c, gps_lnav_parser.c)

WNa was lifted against gps_ephems.toe.week, a field nothing ever writes,
so any WNa above 128 underflowed to ~4.29e9. The propagation then reduced
tk with a while-loop, turning one visibility refresh into 4.29e9
iterations - hours on the target, inside a 10 s periodic call. WNa is the
week modulo 256, so this armed at GPS week 2433 and then for 127 weeks in
every 256. Now lifted against tow.week in signed arithmetic, refused if
impossible, and the propagation is closed form.

The IS-GPS-200 20.3.3.5.2.3 half-week wrap was also applied to tk
unconditionally. It is a week-crossover correction, not a general
reduction: a GPS week is 14.0384 orbital periods, so aliasing one week
moves a satellite 5161 km, enough to report one 5.1 degrees below the
horizon as 5.7 above. The crossover guess now lives in
gps_almanac_assumed_week(), used only before page 25 arrives, and an
almanac too old to propagate yields no prediction rather than a wrong one.

Ephemeris age (gps_ephemeris_validity.c, gps_lnav_parser.c)

The curve-fit check compared two second-of-week values and never read a
week at all, so a record exactly N weeks old read as current. Harmless
while ephemeris lived in RAM; directly reachable once persisted across a
power-off. gps_resolve_toe_week() now reconstructs Toe's week at commit
time from the subframe 1 week number and the handover word; an
unresolvable week yields no age, which reads as a rejection.

A restored record could also outrank the live broadcast, because the Toe
ordering inverts past half a week. Flash records are now marked restored
and are candidates, never incumbents.

Flash wear (gps_nav_context_store.c, gps_interrupt_handlers.c)

The CRC wear policy never engaged: the payload carried the live WLS
position and a receiver timestamp nothing on the restore path read, so
every 60 s save was an erase - about 139 days to wear-out. The seed is
now held and refreshed only on 5 km of movement, at most hourly: one
erase per day instead of 1440.

Measurement model (NavEquations.c)

The elevation weighting was floored at 10 degrees, capping its term at
17.3 m where the model's own answer is 34.4 m at 5 degrees and 86 m at 2,
so a low satellite was trusted several times more than the model allowed.
Floor lowered to 3 degrees, which is where 1/sin must still be bounded
because a zero weight fails the whole epoch. Measured on a six-satellite
geometry, 30 m of uncorrected delay now moves the fix 4.18 m through a
4-degree satellite against 48.50 m through a 72-degree one.

Both atmospheric corrections switched off below the horizon, so a
satellite crossing it lost 78.8 m of tropospheric delay in one step.
Elevation is now clamped at the horizon for the models, and the
extrapolation is paid for in variance.

Also: gps_pps_select_reference() returned early on the preferred PRN,
leaving later non-finite capture times unscreened.

Checked and found correct, with regressions added: the epoch assembly
under satellite connect/disconnect and reassignment, coalesced captures,
the 32-bit RF sample counter wrap (pseudoranges agree to 3.3 um across
it), the refusal to publish a solvable subset of an incoherent epoch, and
the Klobuchar model against IS-GPS-200 20.3.3.5.2.5.

Tests: 22 host suites, 5 RTL testbenches, sanitizer clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 01:45:35 +03:00
onur cayan 471ff12e70 test(fusion): guard the deadlock and calibration regressions, add noise tool
The existing suite passed both before and after the fusion fixes, so it
never covered either failure. Two tests close that gap; both were checked
against the pre-fix sources and fail there.

calibration_offset_test reproduces the bench part's +28 mg zero-g offset
and requires startup to complete, while still refusing a sustained 3 m/s2
acceleration. It also asserts the blind spot rather than leaving it
implicit: horizontal acceleration adds to gravity in quadrature, so
1.5 m/s2 moves the magnitude by only 0.11 m/s2 and is not separable from
offset by any accelerometer gate. Separating it needs GNSS velocity.

long_outage_trajectory_test drives pedestrian, gentle-car (0-100 km/h in
30 s), slow-city and isolated-mount profiles across 1 and 5 minute
outages, using the production rest supervisor rather than a hand-set
flag. Only the isolated-mount slow-city case reproduces the field bug:
GNSS motion evidence compares displacement against covariance, so 4 m/s
under 6 m sigma scores a displacement NIS of 0.22 against a 9.21 gate and
reads as stationary, whereas highway speed scores 42.9 and is correctly
called moving. Pre-fix that case produces 608 zero-velocity updates while
driving, matching the 609 in the board logs.

Drift is judged against the filter's own covariance rather than a fixed
distance. Five minutes unaided legitimately reaches kilometres on this
hardware; what must not happen is the error outrunning the covariance,
which is divergence rather than honest coasting.

tdk_noise_test characterises the sensor at rest through the production
driver, so ODR, full scale, UI filter and LSB scaling match the flight
build, and reports the norms fusion_motion_update() actually gates on.
It also carries an INT1-to-PLIC continuity test that drives the pin to a
static level and reads the PLIC pending bit directly, separating a broken
line from a source that never fires.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 22:06:24 +03:00
onur cayan 80ef92ba01 feat(telemetry): report Doppler velocity beside the ESKF velocity state
Tuning the velocity covariance floors and the zero-velocity veto
threshold needs the receiver's velocity noise, which cannot be recovered
from the existing records: the raw observation and the filter state were
logged in different lines at different rates, so they could not be
differenced.

Hold the converted ENU Doppler velocity from the last fix and publish it
alongside the filter state in one line at one instant, with their
difference (the velocity innovation) and the at-rest flag. With the
platform still, the raw reading is the noise itself.

An IMU does not measure speed; the eskf_* fields are the integrated
result after GNSS correction, and are the only inertial speed available.

First capture, stationary: per-axis sigma 0.12 E, 0.25 N, 0.59 U m/s.
The vertical channel carries most of it, which the previous scalar speed
field could not show.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 22:06:01 +03:00
onur cayan 18d338fe50 fix(imu): resynchronise the ICM-42688 before probing it
Halting the core with a debugger, or resetting it while a transaction is
in flight, leaves the sensor's SPI shift register part-way through a
word. Every later access is misaligned, WHO_AM_I reads back 0x00 and
initialisation fails, which is the `sensor=none who=0x00` case in the
field logs.

Toggle chip select around idle bytes to return the device to command
state, then soft reset so the register file starts from defaults
regardless of what the previous image was doing.

This covers the sensor-side wedge. It does not recover a wedged fabric
SPI controller, which a CPU-only debugger reset does not touch and which
was observed to need a board power cycle.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 22:05:50 +03:00
onur cayan 8349f32df1 fix(fusion): break the zero-velocity/innovation-gate deadlock
A cruising vehicle produces almost no specific force and almost no
angular rate, so an inertial rest supervisor declares rest while moving.
The engine trusted that flag, and three circular dependencies then locked
the filter out of GNSS entirely:

  - GNSS motion evidence was derived only from accepted fixes, so it
    froze exactly when a rejection storm made it the one signal able to
    veto a false zero-velocity update.
  - The zero-velocity update pinned filter velocity near zero, which kept
    eskf_speed_mps() below the rest-detector speed limit and latched the
    mistake, and clamped the position covariance to metres while the true
    error grew to hundreds.
  - Position recovery, the intended escape, was gated on being at rest --
    unreachable during the moving divergence that needs it.

Field logs show the result: 91 m from GNSS with a 5 m sigma, every fix
failing the NIS gate, gps_age_ms climbing past 40 s and recoveries=0.

Motion evidence now comes from every fix on its own displacement
baseline; accepted Doppler speed vetoes the zero-velocity update and is
taken from the measurement rather than the update outcome, since a filter
that has drifted far enough to reject it is the case that matters; and
that veto latches until a later fix shows low speed, because an unaided
platform gives no evidence that it has stopped.

Startup calibration is fixed alongside it. One tolerance served both as
the sensor zero-g offset allowance and as the motion gate, so the bench
part's in-spec +28 mg offset consumed 93% of it and left no headroom:
calibration_samples thrashed 0,3,0,4,2,1 and never reached the minimum,
so the engine never left CALIBRATING and no fused location was published
at all. The offset allowance is now applied to the calibration window
mean, where a fixed bias actually shows up, leaving the full tolerance to
reject sustained acceleration.

Rest-detector thresholds move into the per-sensor quality profile and are
sized from a stationary bench capture rather than datasheet noise
densities, which describe the bare part and not this board or bandwidth.

Verified on hardware: calibration completes in ~2 s, 1980 fixes accepted
with 1 rejection, sub-metre sigma, gps_age_ms mean 223 ms.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 22:05:40 +03:00
onur b4920d31e3 max2771 spi liens has been added. 2026-08-06 22:14:52 +03:00
onur 847523078b irq remove of spi 2026-08-06 21:25:59 +03:00
onur dc5796e2fc docs: add Ti375C529 Efinity pin and flow details 2026-07-31 23:57:16 +03:00
onur 50454f8c23 feat(fpga): add Ti375 Efinity flow 2026-07-30 03:11:05 +03:00
onur 347e1c671d feat(pps): preserve loop dynamics across nav periods 2026-07-29 00:45:16 +03:00
onur a6bb080270 fix: select medany toolchain and available GDB 2026-07-29 00:16:57 +03:00
onur 9b0828dbaa feat: replay live PPS telemetry in fixed-point model 2026-07-29 00:16:43 +03:00
onur a697284bff fix(pps): align firmware TOW with current RTL 2026-07-28 21:53:33 +03:00
onur 988f9686e7 test(pps): analyze loop stability and telemetry 2026-07-28 21:41:41 +03:00
onur 73db2a8355 test(pps): add end-to-end timing validation 2026-07-28 21:13:10 +03:00
onur 156cfc8b77 fix(gps): adapt Doppler bandwidth from board validation 2026-07-26 03:15:52 +03:00
onur 23650be635 feat(gps): split Doppler paths for ESKF and PPS 2026-07-26 01:59:08 +03:00
onur 49b8609bb4 feat(gps): expose ESKF build profiles and 460800 UART 2026-07-25 19:39:36 +03:00
onur ecbb8d0b68 feat(pps): add adaptive disciplined timing loop 2026-07-25 17:56:41 +03:00
onur 0f6b3482c5 docs(pps): record live lock diagnosis 2026-07-25 13:32:24 +03:00
onur 971be036a0 feat(fusion): fuse Doppler velocity in ESKF 2026-07-25 13:11:33 +03:00
onur 2da5fb7153 docs(gps): document tracking quality and Doppler pipeline 2026-07-25 12:16:59 +03:00
onur 5b8cd8560f fix(gps): smooth Doppler measurements before velocity WLS 2026-07-25 12:09:02 +03:00
onur b2ca7db633 feat(gps): expose Doppler and signal quality measurements 2026-07-25 11:30:38 +03:00
onur 64860d1ced fix(gps): recover when tracking loss IRQ is missed 2026-07-24 20:33:45 +03:00
onur 86dfbeafac fix(gps): make acquisition and reacquisition deterministic 2026-07-24 20:13:33 +03:00
onur e57b19b4ee fix(gps): synchronize complete raw navigation epochs 2026-07-24 15:00:40 +03:00
onur fe0eb19dc5 fix(gps): harden navigation epoch recovery 2026-07-24 14:01:58 +03:00
onur ea055a36d2 fix(fusion): harden ESKF GPS failure handling 2026-07-24 12:33:26 +03:00
onur 93766b007f Clarify zero-based tracking PRN indices 2026-07-24 12:06:06 +03:00
onur bdce4a3046 Rate limit corrected UART telemetry 2026-07-23 23:55:33 +03:00
onur 9ff895600b Keep fused location streaming through GPS rejects 2026-07-23 23:29:08 +03:00
onur fc242b2883 Fix GPS nav epoch recovery and document debug levels 2026-07-23 20:48:42 +03:00
onur 516016efb9 Make GPS navigation epochs interrupt-coherent
Wait for every navigation-ready tracking channel in a GPS epoch, remove unlocked channels without a timeout, and keep late joins for the next epoch. Reset PLIC ownership during warm initialization and extend Linux synthetic, integrity, and fake-MMIO regression coverage.
2026-07-23 19:20:06 +03:00
onur 7cc3eb2a54 Integrate asynchronous GPS IMU fusion 2026-07-16 23:49:43 +03:00
onur 38a96dd88f Document STEVAL INT1 hardware verification 2026-07-16 17:51:43 +03:00
onur 927f6e2858 Document fusion handoff and PPS lock diagnosis 2026-07-16 13:47:05 +03:00
onur dd6569c025 Add generic IMU fusion and PMOD IRQ verification 2026-07-16 13:47:02 +03:00
onur e77651dac3 Make SoC tool setup reproducible and portable 2026-07-16 02:42:21 +03:00
onur df563aa207 Add STEVAL-MKI217V1 SPI logger and replay 2026-07-13 22:16:51 +03:00
onur f16ac8aa80 Add bare-metal TDK IMU ESKF fusion 2026-07-13 18:26:06 +03:00
onur 4edb665d52 Add GPS integrity checks and GPS IMU ESKF fusion tools 2026-07-13 11:08:12 +03:00
onur 8260862854 redundant files 2026-07-12 13:01:29 +03:00