kernel.pic-soc-load drill; the PIC worked backward from its firmware

The PIC16F1713 converts its inputs in a free-running loop (10 channels,
about 0.30 ms a loop) and a read returns the last conversion of that
channel; the count follows the SoC's load at conversion time (idle 659,
busy 665 on the coolant thermistors, both tight; every channel shifts in
proportion to its count; the step lands within one PIC loop of the CPU
changing state, with a regulator's overshoot in each direction). The
kernel.pic-soc-load drill replaces kernel.pic-pacing: 200 reads after 3 ms
of sleep and 200 after 3 ms of spinning, with the module's settle off
(the control, reported) and on (the claim: the two agree). The catalog
counts 56 tests, 0 uncovered.

BRINGUP item 10 and the facts bullet describe the mechanism and the fix;
the CAMPAIGN-LOG entries record the first pass of the campaign, the PIC
study, and the mechanism's proof.
This commit is contained in:
ScottW514
2026-09-02 21:15:34 -04:00
parent 7c45642f05
commit 92c69f23fa
3 changed files with 193 additions and 65 deletions
+33 -20
View File
@@ -1004,18 +1004,27 @@ is committed.
share off. With the pump on, a heater slug reaches the upstream sensor
within seconds and inflates the instant reading by a degree; the warm-up
release therefore judges a one-minute rolling minimum of that reading.
- **Coolant-ADC readings depend on the read pattern.** What the PIC returns
for a thermistor depends on how soon the read follows the previous PIC
transaction (measured 2026-09-02 on the two coolant channels): the second
of a pair issued within 0.1 ms comes back 6 to 8 counts high with a wide
spread, either sensor, either order; a pair 0.5 to 10 ms apart reads tight
and a steady 3 counts (about 0.2 C) above sparse reads. The module paces
every PIC transaction (`pic_gap_us`, 1000 by default, a runtime-writable
parameter), so no reader lands a disturbed pair whatever the others do;
the `aa-offset-calibrate` diagnostic still reads its two sensors 31 ms
apart and reduces each window to an interquartile mean, which takes the
steady bias out of its edges. `kernel.pic-pacing` measures the pairs with
the pacing off and on.
- **Coolant-ADC readings depend on the SoC's load at conversion time.** The
sensor PIC (a PIC16F1713, its firmware read from the part) converts its
inputs in a free-running loop, about 25 µs a channel (10 µs acquisition,
11.5 µs conversion at FOSC/32, the ADC switched off between), and a read
returns the last conversion of that channel, at most one loop (about
0.35 ms) old; a read never starts a conversion and the SPI interrupt
never touches the ADC. The ADC references the PIC's own supply (ADPREF
at reset) while the sensor dividers hang on the board's reference, so the
count follows the SoC's load at the moment of conversion: on the coolant
thermistors a value converted while the CPU idled reads 6 counts (about
0.35 C) below one converted under load, both regimes tight
(interquartile 2 over 200 reads; measured 2026-09-03, sleep 3 ms then
read against spin 3 ms then read). A reader that wakes and reads at once
gets the idle value and its next read, a fraction of a millisecond later,
the busy one, which is the pair bias the diagnostic saw on 2026-09-02.
The module keeps the CPU busy for `pic_settle_us` (500 by default, a
runtime-writable parameter) before every transaction, longer than one PIC
loop, so every reader gets the busy-regime value whatever it was doing.
Rare excursions of 10 to 20 counts appear in every regime at a few
samples per hundred; the diagnostic's interquartile means drop them.
`kernel.pic-soc-load` measures both regimes with the settle off and on.
- **Coolant-ADC offsets around a lit tube.** The air-assist fan's return
current rides a ground path the thermistor reference shares, so both coolant
sensors read about 1.2 C low at the run duty (proportional to the fan's
@@ -1391,14 +1400,18 @@ feature requests, enhancements) will eventually be tracked as GitHub issues.
live-fire drill is gone; a coolant sensor unreadable for two ticks is the
SENSOR verdict.
10. **PIC read pacing, done and waiting for the image.** The module paces
every PIC transaction at least `pic_gap_us` (1000, a runtime-writable
parameter) after the last one ended, so every reader, the engine,
`/status`, the diagnostics and a bench sampler, sees the same value
whatever the others do (facts bank, "Coolant-ADC readings depend on the
read pattern"). Host-proven by the module's -Werror cross-build; on the
bench, the new `kernel.pic-pacing` drill (300 back-to-back pairs with the
pacing off, then on) and the coolant-reading tests
10. **PIC readings under one SoC load, done and waiting for the image.** The
module keeps the CPU busy for `pic_settle_us` (500, a runtime-writable
parameter) before every PIC transaction, longer than one loop of the
PIC's free-running sampler, so the value a reader gets was converted
under the same load whoever reads and whatever it was doing (facts bank,
"Coolant-ADC readings depend on the SoC's load at conversion time"): the
engine, `/status`, the diagnostics and a bench sampler read the same
value, the busy-regime one, about 0.35 C above the idle one. Host-proven
by the module's -Werror cross-build and, for the mechanism, by the
userspace measurement; on the bench, the new `kernel.pic-soc-load` drill
(200 reads after 3 ms of sleep and after 3 ms of spinning, with the
settle off and on) and the coolant-reading tests
(`cooling.aa-offset-calibrate`, `cooling.flow-verify`). Rides item 9's
image; the item closes with the campaign.