Skip to content

Latest commit

 

History

History
146 lines (124 loc) · 12.6 KB

File metadata and controls

146 lines (124 loc) · 12.6 KB

Order & Timing of Operations

Everything the device computes runs from one loop, on two clocks: an evaluation pass every 10 ms (100 Hz), and frame arrival, which triggers extra work the moment a configured message is received. This page discloses the exact order of both, and how often everything else on the unit runs — so when one channel reads another you can say precisely how old the value is, and when a message transmits you can say precisely when.

Nothing here is configurable; it is how the firmware is built. The numbers apply to the whole configuration regardless of size — the pass runs the full table of every calculation type, active rows in row order, on every pass.

The evaluation pass — every 10 ms

Each pass executes these stages, always in this order:

#StageWhat happens
1Device channelsDevice OnTime, the per-bus CAN diagnostics, Bus Load and the MCU health block are written first, so everything downstream reads this pass's values.
2Receive timeoutsAny receive message past its timeout has its channels set to their default values (where the section asks for it).
3ConstantsFixed values are written to their channels.
4Lookup tables2×16 tables, then 8×8 tables.
5Math channelsAll rows, in row order.
6Up/Down countersEdge detection and rate steps.
7TimersAdvance by the real elapsed time.
8IntegratorsAccumulate by the real elapsed time.
9User ConditionsAll comparisons, in row order — after everything above, so a condition on a math or table result sees the value computed this pass. Each condition's mode is applied here too: a Set/Reset latch is set, reset or held, and a Momentary's hold is spent against the elapsed time.
10Device scriptThe script's on_tick runs last of the calculation stages, within its per-pass budget, so it sees everything the pass produced and its outputs still reach the transmit stage below.
11TransmitEvery transmit message whose period has elapsed is composed from the channel values as they stand now — the freshest the pass can offer — and queued to its bus. Composition packs every transmitted channel (and a compound message's identifier selector) into the frame first; for a Transmit CRC8 message the checksum is then computed over its configured elements, stamped into its byte last — after every other byte of the frame is final — and published to its CRC channel.

Note: The condition stage is the one calculation stage whose output does not follow from this pass's channel values alone. A User Condition carries memory: its latched output, the previous pass's Set expression for edge detection, and a Momentary's remaining hold. It used to be pure — same inputs, same output, every pass — and that purity is what let it run from the receive path as freely as from the tick. It still runs from both, but the receive path is told that no time has passed, so a frame can move a latch and cannot shorten a hold. None of that state is persisted: a power cycle, and a configuration being sent, re-arm every condition.

Around the pass, on the same 100 Hz beat: the CAN error state of all three buses is sampled just before it (feeding the diagnostics the pass publishes in stage 1), and after it the Monitor Channels value stream sends its slice of the channel table (see the rate table below).

When a frame arrives

Received frames are not held for the next pass — each one is processed on arrival, in this order:

  1. Message relays — every relay rule is checked against every received frame, matched or not, and forwards immediately.
  2. Message match — the first active receive message on that bus with that CAN ID (and matching standard/extended type) wins; the message's timeout window restarts.
  3. Channel decode — the matched section's channels are extracted and scaled into their values.
  4. Recalculation — constants, lookup tables, math and User Conditions re-run (the same stages 3–5 and 9 above, in the same order), so anything derived from the received channels updates immediately rather than up to 10 ms later. A was received comparison naming this message is true on exactly this evaluation, which is why no received frame can be missed however fast they arrive.
  5. Routing — if the section routes to other buses, the frame is forwarded last, after the recalculation.

Counters, timers and integrators do not run here — they advance on the 10 ms clock only, because they measure time. A Momentary condition's hold measures time in the same way and is likewise spent on the pass alone: the recalculation above is told that no time has passed, so a burst of frames cannot cut a pulse short. The device script's on_tick does not run here either: it is a per-pass hook with a per-pass budget, not a per-frame one. Both pick up the received values on the next pass, at most 10 ms later.

Reading across the order: the one-pass lag

Within a pass, a reference to something computed at an earlier stage (or an earlier row of the same stage) reads the value from this pass. A reference to something computed later reads the value from the previous pass — 10 ms old. The order above is what "earlier" and "later" mean. The cases that matter in practice:

ReferenceWhat it reads
Math ← constant, tableThis pass
User Condition ← math, table, counter, timer, integrator This pass
Table axis ← math channelPrevious pass (tables run before math)
Math ← User ConditionPrevious pass
Counter / timer / integrator input ← User Condition Previous pass
Anything ← script-written channelPrevious pass (except the transmit stage, which runs after the script)
Transmit message ← anythingThis pass

Note: A chain that spans several "backwards" references accumulates one pass of lag per hop. A condition gating a counter whose output feeds a math row read by a table is correct — it just settles over a few passes rather than one. At 100 Hz that is tens of milliseconds, which rarely matters; it only surprises when you expect a multi-stage chain to react within a single pass.

Transmit timing

Each transmit message runs on its own period — the section's Transmit Rate, 1 to 200 Hz, so periods from 1000 ms down to 5 ms. The transmit scheduler runs on its own 5 ms slots, twice as fast as the evaluation pass, and that is the scheduling resolution: a period is always a whole number of slots. Transmit CRC8 messages schedule identically — the checksum is computed for every frame, whatever the rate.

Note: What a 5 ms message carries: received channels are updated the moment their frame arrives, so a fast gateway message forwards fresh data on every transmission. Calculated channels (math, counters, timers, tables, scripts) update on the 10 ms evaluation pass, so a 200 Hz message repeats each calculated value at most once — the calculation chain deliberately does not speed up with the scheduler.

  • Messages are phase-spread per bus. When a configuration is loaded, the transmit messages of each bus are offset within their periods so they come due spread across the period rather than all on the same pass. Ten 10 Hz messages on one bus transmit one per 10 ms across their 100 ms period, not ten back-to-back every 100 ms.
  • Section order is the tie-break. Messages sharing a bus and a rate are offset in list order, so they go out in the order the Communications list shows — list order = transmit order.
  • An oversubscribed bus degrades fairly. If more comes due than the bus can carry, the scan resumes each pass where the queue filled, so the shortfall is shared across the whole table instead of silencing the messages at the end of the list.
  • A missed cycle is dropped, not banked. When a transmission cannot be sent (bus off, queue full), the message does not accumulate a backlog; the next cycle sends the current channel values. Cyclic data carries the freshest value or nothing.
  • A transmission is recorded for the next pass. The 5 ms scheduler does not evaluate conditions, so a was transmitted comparison sees the frame on the following calculation pass — up to 10 ms later — and any transmissions of one message inside that window collapse into a single event. A 5 ms message manages two per window, and a Batch compound message emits every identifier in one service. Receive is not like this: a was received comparison is evaluated by the frame's own pass and sees every frame. See the message operators.
  • A Triggered message keeps its own phase. Its User Condition is tested in the 5 ms slot whatever the message's rate is, so the trigger is acted on within 5 ms — and the period is then counted from the moment the condition became true rather than from the phase the message was given at load. See Triggered transmit.

How often everything runs

OperationRate / latency
Evaluation pass (stages above)Every 10 ms (100 Hz)
Constants, tables, math, User ConditionsEvery pass, plus immediately on every matched received frame
Counters, timers, integratorsEvery pass only
A Momentary condition's holdSpent every pass only — a received frame does not advance it
Message events for a condition's was received / was transmittedA receive is seen by the evaluation the frame itself triggers; a transmit by the next pass, at most 10 ms later
Device script on_tickEvery pass, budgeted (see Device Scripts)
Message relays, routingImmediately, per received frame
Transmit schedulingChecked every 5 ms (its own 200 Hz clock); each message at its configured 1–200 Hz
Transmit CRC8 stamp & publishWith every transmission of its message, during composition — channels packed first, checksum stamped last
Receive timeout checkEvery pass
Device channels (OnTime, diagnostics, MCU health)Republished every pass
CAN error-state samplingEvery pass, just before it
Bus LoadRecomputed over a 1 s window
MCU health sampling (temperature, VDDA)Sampled at 10 Hz; each pass republishes the latest sample
Reset reasonRead once at boot and latched
Bus-off recoveryBus stopped on bus-off, restart attempted every 1 s until it stays up
Monitor Channels (value stream)Up to 160 channels per pass, round-robin — a full refresh of every channel takes one pass for up to 160 channels, and at most 70 ms at the device's 1000-channel limit
CAN Viewer (monitor stream)Per frame, as sent or received
Preserved values written to flashOnce a minute, only when changed (see Integrators)

Note: The pass is driven by real elapsed time, not by counting visits. If something stalls the loop — a flash erase during Save to Flash is the realistic case — the next pass is told how much time actually passed: timers and integrators advance by the true amount, and transmit periods stretch rather than burst-transmitting a backlog afterwards.

See also

Math Channels · User Conditions · Messages & Sections · Message Relays · Device Scripts · Monitoring Live Values · Channels