mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-29 01:21:16 -07:00
BRINGUP: merge the head crash detector and head IRQ into one item
A firmware decode of the head MCU (recorded in CAMPAIGN-LOG) shows the factory head crash detector and the head IRQ accel_irq source are one mechanism: the head accelerometer (LIS2HH12) has an on-chip interrupt generator the factory arms per job from the HA* header tags (bit-exact onto its registers) and reads by polling IG_SRC1; its INT wires to the head MCU and surfaces as reg 0x05 b1 behind HEAD_IRQ, which is level-driven off the MCU's latched reg 0x02 and dormant until the SoC arms an edge in reg 0x03/0x04. Facts bank: add "The head MCU flag register and HEAD_IRQ", "The head accelerometer", "Beam detect in the head MCU" (correcting the thinner entry: reg 0x05 has a fourth input and a b7 processed verdict we do not expose; beam_detect_digital is the raw comparator, not the verdict). Next work: merge items 6 and 8, renumber 12 to 11, repoint the trailer. CAMPAIGN-LOG: dated entry recording the decode. Docs only.
This commit is contained in:
+85
-37
@@ -1006,21 +1006,56 @@ is committed.
|
|||||||
firing) and is the only live HV telemetry on this PSU (`hv_voltage` is
|
firing) and is the only live HV telemetry on this PSU (`hv_voltage` is
|
||||||
grounded). `cnc/laser_pgood_sampled` stays 0 through real cutting: not usable
|
grounded). `cnc/laser_pgood_sampled` stays 0 through real cutting: not usable
|
||||||
here.
|
here.
|
||||||
- **The head IRQ and beam detect.** The EV_SW `head` bit (GPIO3_22, factory
|
- **The head MCU flag register and HEAD_IRQ.** The head MCU (a KL17 at
|
||||||
pad HEAD_IRQ; the panel's "Head sense" row) is the head MCU's attention
|
i2c-3 @0x47, I²C-slave-only to the SoC) samples four head-local GPIO input
|
||||||
line: idle LOW with a healthy head, pulsing on a head reboot (hence the
|
levels once per main loop into the read-only flag register 0x05: b0
|
||||||
60 ms DT debounce), floating to the SoC pull-up with no head. The raw level
|
`hall_sensor` (Z home), b1 `accel_irq` (the head accelerometer's INT pin, a
|
||||||
is not a presence signal; presence is the head answering at I²C 0x47. The
|
bare level), b2 `beam_detect_digital` (the raw beam comparator), and a
|
||||||
factory app answers the IRQ by reading the head's flag register (reg 0x05:
|
fourth, unidentified input the driver does not expose (candidate second
|
||||||
b0 hall_sensor, b1 accel_irq, b2 beam_detect_digital), so there are exactly
|
hall or head-present). A fifth flag, b7, is the processed beam-detect
|
||||||
three candidate sources. The beam detector reads back as the digital flag
|
verdict (below). The EV_SW `head` bit (GPIO3_22, factory pad HEAD_IRQ; the
|
||||||
plus an analog level (reg 0x16), both head sysfs attrs: `beam_detect_analog`
|
panel's "Head sense" row) is the MCU's PTC2 output driven back to the SoC:
|
||||||
sits near 1834 dark and reads 2600 to 2890 during S300/S400 fire (the
|
it is level-driven and mirrors reg 0x02 (the latched IRQ status) being
|
||||||
acceptance suite's mark witness), unmeasured at low fire energies. The
|
nonzero. reg 0x02 latches edges on the reg-0x05 bits, but only those the
|
||||||
tunable detection model (regs 0x22 to 0x2a) is written with fixed values at
|
SoC arms through reg 0x03 (rising) and reg 0x04 (falling) edge-enable masks,
|
||||||
probe and not exposed as attrs. Whether the factory enables beam detect in
|
and it is read-to-clear. So the SoC chooses which head events raise the IRQ,
|
||||||
production is unknown: the v2.6.0 app carries a complete but config-gated
|
answers it by reading reg 0x02 to identify and clear, and reads reg 0x05 for
|
||||||
subsystem.
|
live levels. ForgeFIRM writes none of 0x03/0x04 and reads neither 0x02 nor
|
||||||
|
the fourth-input and b7 flags, so the head IRQ is dormant by construction:
|
||||||
|
GPIO3_22 sits idle low with a healthy head, pulses on a head reboot (hence
|
||||||
|
the 60 ms DT debounce), and floats to the SoC pull-up with no head. The raw
|
||||||
|
level is not a presence signal; presence is the head answering at I²C 0x47.
|
||||||
|
- **The head accelerometer** is an ST LIS2HH12 (i2c-3 @0x1e; the board and
|
||||||
|
lid accels are the same part at i2c-3 @0x1d and i2c-0 @0x1e), read raw by
|
||||||
|
the mainline `st,lis2hh12` driver for motion liveness. The part has a full
|
||||||
|
on-chip interrupt generator: per-axis 8-bit thresholds (IG_THS_X1/Y1/Z1,
|
||||||
|
regs 0x32/0x33/0x34), a duration counter (IG_DUR1 0x35), a per-axis event
|
||||||
|
register (IG_SRC1 0x31), full scale ±2/4/8 g (CTRL4 FS), two independent
|
||||||
|
generators (IG1/IG2). The factory arms this generator per job from the
|
||||||
|
pulse header's HA* accel tags, which map bit-exactly onto its registers
|
||||||
|
(per-axis threshold → IG_THS, duration → IG_DUR1, full scale → CTRL4,
|
||||||
|
period/decimator → CTRL5/ODR), and reads trips by polling IG_SRC1 over the
|
||||||
|
accel's own bus (per-axis x/y/z alerts), running two tiers. So the factory
|
||||||
|
head crash detector is the sensor's own interrupt generator, and the HA*
|
||||||
|
thresholds are LIS2HH12 register values at the full scale the HAsr tag sets,
|
||||||
|
not values in an unknown unit. The INT pin does not reach the SoC as a host
|
||||||
|
interrupt: it wires to the head MCU's GPIO and surfaces only as reg 0x05 b1,
|
||||||
|
and neither the factory DTS (head I²C `status = "disabled"`, the accel
|
||||||
|
driven from userspace) nor ForgeFIRM's DTS gives the accel an `interrupts`
|
||||||
|
property. ForgeFIRM neither arms the generator nor reads b1; it only polls
|
||||||
|
raw samples.
|
||||||
|
- **Beam detect in the head MCU.** PTE16 into ADC0 gives reg 0x16, the raw
|
||||||
|
analog level (`beam_detect_analog`, a head sysfs attr): near 1834 dark, 2600
|
||||||
|
to 2890 during S300/S400 fire (the acceptance suite's mark witness),
|
||||||
|
unmeasured at low fire energies. A float EWMA/CUSUM over the coefficients
|
||||||
|
`LAMBDA_K` (0x07ae), `LAMBDA_T` (0x1999 = 0.1), `THETA_R` (0x20), `THETA_T`
|
||||||
|
(0x28), `E_T` (0x60) feeds an N-of-M sliding-window verdict in reg 0x05 b7;
|
||||||
|
a DAC (reg 0x1e, default 0x3ff) sets a comparator threshold whose raw output
|
||||||
|
is reg 0x05 b2 (`beam_detect_digital`). The head probe writes the five
|
||||||
|
coefficients, but they are the firmware's own power-on defaults. The driver
|
||||||
|
exposes b2 (raw comparator) and reg 0x16 (raw analog), not b7 (the processed
|
||||||
|
verdict). Whether the factory enables beam detect in production is unknown:
|
||||||
|
the v2.6.0 app carries a complete but config-gated subsystem.
|
||||||
- **Switches**: truthy = closed/OK for lid/doors/button. **SW_INTERLOCK is
|
- **Switches**: truthy = closed/OK for lid/doors/button. **SW_INTERLOCK is
|
||||||
INVERTED**: the remote interlock (the regulatory 2-pin lockout connector)
|
INVERTED**: the remote interlock (the regulatory 2-pin lockout connector)
|
||||||
reads ACTIVE only when the loop is OPEN. Basic/Plus — including the bench
|
reads ACTIVE only when the loop is OPEN. Basic/Plus — including the bench
|
||||||
@@ -1173,14 +1208,36 @@ Open items only. Anything closed is in `CAMPAIGN-LOG.md`.
|
|||||||
5. **Update system Phase 5 — recovery refresh.** The remaining phase of
|
5. **Update system Phase 5 — recovery refresh.** The remaining phase of
|
||||||
`docs/UPDATE-SYSTEM.md` (a refreshed recovery image in boot0); Phases 0–4
|
`docs/UPDATE-SYSTEM.md` (a refreshed recovery image in boot0); Phases 0–4
|
||||||
are done.
|
are done.
|
||||||
6. **Head-IRQ source validation (exploratory, not gating).** Which of the
|
6. **Head accelerometer crash detector, and the head IRQ (planned;
|
||||||
three head flag sources drives the EV_SW `head` bit during a cut is
|
exploratory).** The factory's head crash detector is the head
|
||||||
unknown; the working hypothesis is the beam-emission detector (the facts
|
accelerometer's own on-chip interrupt generator, armed per job from the
|
||||||
bank, "The head IRQ and beam detect"). Owed, cheap and opportunistic
|
HA* header thresholds and read by polling the sensor; the head IRQ is the
|
||||||
during live fire: log EV_SW head-bit edges plus
|
coarse aggregate path to that event and the others (hall, beam). Both are
|
||||||
`head/beam_detect_digital|_analog` while firing, low fire energies
|
one mechanism (the facts bank, "The head MCU flag register and HEAD_IRQ"
|
||||||
included. If the beam flag level-holds the IRQ, the panel row asserts
|
and "The head accelerometer"), which is why these two items are one. The
|
||||||
during sustained emission.
|
detector is adopted, not measured from scratch: the earlier plan to
|
||||||
|
bench-measure a filter is moot now that the HA* thresholds are known to be
|
||||||
|
LIS2HH12 register values at a known full scale.
|
||||||
|
|
||||||
|
Owed for the detector: program the LIS2HH12 interrupt generator over
|
||||||
|
i2c-3 (per-axis threshold, duration, full scale) and poll IG_SRC1 for a
|
||||||
|
latched per-axis trip, on the factory's two-tier shape (an alert that
|
||||||
|
pauses, an abort that fails). The rail-contact signature in the facts
|
||||||
|
bank sets the first threshold in register units; a pause on contact is
|
||||||
|
the first use. ForgeFIRM already reads the head accel raw for liveness,
|
||||||
|
so this shares the bus, not new hardware; the one wrinkle is reaching the
|
||||||
|
interrupt-generator registers past the bound `st_accel` driver (IIO
|
||||||
|
events if the driver exposes them, else a direct-register path as the
|
||||||
|
retired homing spike used).
|
||||||
|
|
||||||
|
Owed for the head IRQ, only if a coarse hardware interrupt is wanted
|
||||||
|
instead of the poll: arm the accel bit in the head MCU (reg 0x03/0x04),
|
||||||
|
watch GPIO3_22, and read reg 0x02 to identify and clear. The beam-detect
|
||||||
|
verdict (reg 0x05 b7, not currently exposed) is the same mechanism for the
|
||||||
|
emission question and stays exploratory: whether the factory enables beam
|
||||||
|
detect is unknown, and detection at low fire energies is unverified. A
|
||||||
|
cheap opportunistic check during live fire still stands: log GPIO3_22
|
||||||
|
edges plus `head/beam_detect_digital|_analog` while firing.
|
||||||
|
|
||||||
7. **Gapless pause and resume in GRBL mode (planned).** A pause leaves a mark
|
7. **Gapless pause and resume in GRBL mode (planned).** A pause leaves a mark
|
||||||
in the cut. With laser mode on, the core stops the beam at the start of the
|
in the cut. With laser mode on, the core stops the beam at the start of the
|
||||||
@@ -1213,16 +1270,7 @@ Open items only. Anything closed is in `CAMPAIGN-LOG.md`.
|
|||||||
raster line does to it, and how it composes with the armed window's disarm
|
raster line does to it, and how it composes with the armed window's disarm
|
||||||
grace across a long hold.
|
grace across a long hold.
|
||||||
|
|
||||||
8. **Head crash and rail-contact detector (planned).** Bench-measured from
|
8. **A sender change while a job runs: discussion.** Today a sender that
|
||||||
scratch, not adopted from the pulse header: the factory's per-axis
|
|
||||||
alert/abort thresholds arrive in every header in a unit and behind a
|
|
||||||
filter that are not known, so the rail-contact signature in the facts
|
|
||||||
bank is the starting point and the header values are only a cross-check
|
|
||||||
once the units are established. A pause on contact, on the factory's
|
|
||||||
shape (an alert tier that pauses, an abort tier), would be the first
|
|
||||||
use.
|
|
||||||
|
|
||||||
9. **A sender change while a job runs: discussion.** Today a sender that
|
|
||||||
disconnects mid-job leaves the motion running to the end of what the
|
disconnects mid-job leaves the motion running to the end of what the
|
||||||
controller holds, with the window closed and fire suppressed (the
|
controller holds, with the window closed and fire suppressed (the
|
||||||
consent belonged to the displaced session), so the job finishes dark
|
consent belonged to the displaced session), so the job finishes dark
|
||||||
@@ -1238,7 +1286,7 @@ Open items only. Anything closed is in `CAMPAIGN-LOG.md`.
|
|||||||
running on leaves a clean stop position but wastes the piece. Decide
|
running on leaves a clean stop position but wastes the piece. Decide
|
||||||
with the gapless pause and resume item (7), which owns the resume
|
with the gapless pause and resume item (7), which owns the resume
|
||||||
mechanics.
|
mechanics.
|
||||||
10. **The flow check on a second machine.** The lit-tube flow check is in
|
9. **The flow check on a second machine.** The lit-tube flow check is in
|
||||||
place: the engine reads means, takes its baseline under the run
|
place: the engine reads means, takes its baseline under the run
|
||||||
profile, and takes the tube's share off (`cool_laser_heat_cw`,
|
profile, and takes the tube's share off (`cool_laser_heat_cw`,
|
||||||
`cool_laser_heat_density`); `cooling.flow-under-load` is the catalog's
|
`cool_laser_heat_density`); `cooling.flow-under-load` is the catalog's
|
||||||
@@ -1248,7 +1296,7 @@ Open items only. Anything closed is in `CAMPAIGN-LOG.md`.
|
|||||||
far): re-measure the two heat coefficients and the machine's
|
far): re-measure the two heat coefficients and the machine's
|
||||||
air-assist offset; and if a lit check still trips, the
|
air-assist offset; and if a lit check still trips, the
|
||||||
void-on-emission design with the tube as its own flow tracer.
|
void-on-emission design with the tube as its own flow tracer.
|
||||||
11. **Laser power-good: what the line means.** `cnc/laser_pgood` and its
|
10. **Laser power-good: what the line means.** `cnc/laser_pgood` and its
|
||||||
sampled count are defined in the UAPI (active low, one sample every
|
sampled count are defined in the UAPI (active low, one sample every
|
||||||
~3.9 ms), the facts bank records that the sampled count reads 0 through
|
~3.9 ms), the facts bank records that the sampled count reads 0 through
|
||||||
real cutting, and the cooling engine warns
|
real cutting, and the cooling engine warns
|
||||||
@@ -1260,7 +1308,7 @@ Open items only. Anything closed is in `CAMPAIGN-LOG.md`.
|
|||||||
scope against `hv_current` through an armed cut, its meaning written
|
scope against `hv_current` through an armed cut, its meaning written
|
||||||
into the facts bank and the UAPI, and then either a warning that means
|
into the facts bank and the UAPI, and then either a warning that means
|
||||||
something or no warning.
|
something or no warning.
|
||||||
12. **Initial commissioning: measure and set the machine's own numbers
|
11. **Initial commissioning: measure and set the machine's own numbers
|
||||||
methodically.** Every tunable that was measured on the bench machine
|
methodically.** Every tunable that was measured on the bench machine
|
||||||
and shipped as a default varies from machine to machine: the flow
|
and shipped as a default varies from machine to machine: the flow
|
||||||
check's bands and `cool_flow_rise`, the tube's heat coefficients
|
check's bands and `cool_flow_rise`, the tube's heat coefficients
|
||||||
@@ -1296,7 +1344,7 @@ covers the warm-up hold), the supply temperature window (the service sends
|
|||||||
the whole ADC range and the factory binds it to nothing; the supply is
|
the whole ADC range and the factory binds it to nothing; the supply is
|
||||||
watched per job instead), the head, lid, interconnect and fused temperature
|
watched per job instead), the head, lid, interconnect and fused temperature
|
||||||
ceilings (no sensor at those locations; the chassis is watched per job), the
|
ceilings (no sensor at those locations; the chassis is watched per job), the
|
||||||
head accelerometer thresholds (item 8), the lid IR thresholds (the fire
|
head accelerometer thresholds (item 6), the lid IR thresholds (the fire
|
||||||
watch runs on local knobs; the header values stay ignored), the
|
watch runs on local knobs; the header values stay ignored), the
|
||||||
HV current caps (the sampled emission witness covers the idle case, and HV
|
HV current caps (the sampled emission witness covers the idle case, and HV
|
||||||
current is ranged per job), the thermal report upload conditions and the
|
current is ranged per job), the thermal report upload conditions and the
|
||||||
|
|||||||
@@ -6722,6 +6722,79 @@ down one.
|
|||||||
defer needs the 40 V regulator unbound under the probe. It is a bench slot
|
defer needs the 40 V regulator unbound under the probe. It is a bench slot
|
||||||
with the rail-cycle gamble accepted, and it rides the closing burn.
|
with the rail-cycle gamble accepted, and it rides the closing burn.
|
||||||
|
|
||||||
|
## 2026-08-31: head MCU firmware decode - the accel IRQ, HEAD_IRQ arming, and the beam-detect chain
|
||||||
|
|
||||||
|
A read of the head MCU firmware (the KL17 at i2c-3 @0x47; disassembly
|
||||||
|
in `GF_Reverse/HEAD_PY`, cross-checked against the factory pinout
|
||||||
|
tables, the factory `head-board.sh`, and this project's DTS and head
|
||||||
|
driver) settles what drives the head IRQ and how the factory's head
|
||||||
|
crash detector works. It ties the two open next-work items together:
|
||||||
|
the accelerometer crash detector and the head IRQ source are two views
|
||||||
|
of one mechanism. The durable result is distilled into the BRINGUP
|
||||||
|
facts bank ("The head MCU flag register and HEAD_IRQ", "The head
|
||||||
|
accelerometer", "Beam detect in the head MCU"); the decode itself is
|
||||||
|
recorded here.
|
||||||
|
|
||||||
|
**How the KL17 assembles reg 0x05 and drives the head IRQ.** The MCU
|
||||||
|
is I2C-slave-only to the SoC (no I2C-master path is linked, so it never
|
||||||
|
touches the accelerometer). Once per main-loop pass it samples four
|
||||||
|
head-local GPIO input levels into the read-only flag register 0x05: b0
|
||||||
|
hall (pad PTE19), b1 the accelerometer INT pin (PTA1, a bare level, not
|
||||||
|
an I2C read and not computed), b2 the beam-detect comparator output
|
||||||
|
(PTE18), b3 a fourth, unidentified input (PTA19, pulled down; candidate
|
||||||
|
second hall or head-present). A fifth flag, b7, is the processed
|
||||||
|
beam-detect verdict (below). No GPIO pin interrupts are configured
|
||||||
|
anywhere in the firmware (`PORTA`/`PORTC_PORTD` vectors are the default
|
||||||
|
infinite loop); every input is level-polled. The outgoing head IRQ line
|
||||||
|
is the MCU's PTC2 output (our EV_SW head bit, GPIO3_22, an active-high
|
||||||
|
input at the SoC): it is level-driven and mirrors reg 0x02 (the latched
|
||||||
|
IRQ status) being nonzero. reg 0x02 latches edges on the reg-0x05 bits,
|
||||||
|
but only those the SoC arms through reg 0x03 (rising) and reg 0x04
|
||||||
|
(falling) edge-enable masks; reg 0x02 is read-to-clear. So the SoC
|
||||||
|
chooses which head events raise the IRQ, answers it by reading reg 0x02
|
||||||
|
to identify and clear, and reads reg 0x05 for live levels. ForgeFIRM
|
||||||
|
writes neither 0x03/0x04 nor reads 0x02, so the head IRQ is dormant by
|
||||||
|
construction, which is why the bench sees GPIO3_22 idle low with a
|
||||||
|
healthy head. (This corrects nothing measured earlier; it explains it.)
|
||||||
|
|
||||||
|
**The head accelerometer is a LIS2HH12 with a full on-chip interrupt
|
||||||
|
generator, and the factory arms it.** The part (i2c-3 @0x1e; the board
|
||||||
|
and lid accels are the same part at @0x1d and i2c-0 @0x1e) carries
|
||||||
|
per-axis 8-bit thresholds (IG_THS_X1/Y1/Z1, regs 0x32/0x33/0x34), a
|
||||||
|
duration counter (IG_DUR1 0x35), a per-axis event register
|
||||||
|
(IG_SRC1 0x31), full-scale +/-2/4/8 g (CTRL4 FS), and two independent
|
||||||
|
generators (IG1/IG2). The factory arms this generator from the pulse
|
||||||
|
header's HA* accel tags, which map bit-exactly onto its registers
|
||||||
|
(per-axis threshold to IG_THS, duration to IG_DUR1, decimator/ODR to
|
||||||
|
CTRL5, FIFO to CTRL3/FIFO_CTRL, full scale to CTRL4), and reads trips by
|
||||||
|
polling IG_SRC1 over the accel's own bus (the `head_accel_x/y/z_alert`
|
||||||
|
sources, from an 8-bit I2C register), running two tiers (alert pauses,
|
||||||
|
abort fails). The accel INT pin also wires to the KL17's PTA1, so the
|
||||||
|
same event surfaces coarsely as reg 0x05 b1. So the factory head crash
|
||||||
|
detector is the sensor's own interrupt generator, and the HA*
|
||||||
|
thresholds are LIS2HH12 register values at the full scale the HAsr tag
|
||||||
|
sets, not values in an unknown unit or behind an unknown filter. The
|
||||||
|
factory DTS does not declare the accel at all (its head I2C controller
|
||||||
|
is `status = "disabled"` with no children; the factory drove the accel,
|
||||||
|
the head MCU, and the LM75 from userspace over `/dev/i2c-2`), so the
|
||||||
|
factory too reaches the accel only over the bus, never as a host
|
||||||
|
interrupt.
|
||||||
|
|
||||||
|
**Beam detect, fully decoded (contrast, for the emission question).**
|
||||||
|
In the MCU: PTE16 to ADC0 gives reg 0x16 (raw analog level); a float
|
||||||
|
EWMA/CUSUM over the coefficients LAMBDA_K (0x07ae), LAMBDA_T
|
||||||
|
(0x1999 = 0.1), THETA_R (0x20), THETA_T (0x28) and E_T (0x60) feeds an
|
||||||
|
N-of-M sliding-window verdict in reg 0x05 b7. A DAC (reg 0x1e, default
|
||||||
|
0x3ff) sets an analog comparator threshold whose raw digital output is
|
||||||
|
reg 0x05 b2. Our head probe writes those five coefficients, but they are
|
||||||
|
the firmware's own power-on defaults. Our head driver exposes b2 (the
|
||||||
|
raw comparator) and reg 0x16 (the raw analog), but not b7 (the processed
|
||||||
|
verdict) - a gap if the emission question is ever pursued. `0xc9 <- 0x5a`
|
||||||
|
is a system reset; `0xc9 <- 0x5b` forces the ROM bootloader; `reg 0x0f`
|
||||||
|
enables SEGGER RTT telemetry; regs 0x3c-0x3f read a debug capture ring
|
||||||
|
(the previously-unexplained `i2cget 0x47 0x02`, `0x0f`, `0x3c`
|
||||||
|
commands).
|
||||||
|
|
||||||
## Reference notes
|
## Reference notes
|
||||||
|
|
||||||
### Head-IRQ source validation — the beam-emission hypothesis
|
### Head-IRQ source validation — the beam-emission hypothesis
|
||||||
|
|||||||
Reference in New Issue
Block a user