First doc writeup

This commit is contained in:
2026-06-05 00:11:55 +02:00
parent 6f0009cfbb
commit 0ea7b83bea
4 changed files with 190 additions and 44 deletions

View File

@@ -1,34 +1,124 @@
# NeoECU Firmware Architecture
# NeoECU Target Architecture
## AMP
NeoECU features an AMP (Asymmetric Multi Processing) architecture making use of both the `CM7` and `CM4` core of the STM32H747 MCU powering NeoECU
NeoECU uses an AMP layout. The `CM7` side owns deterministic engine control; the secondary core is reserved for non-critical work and is outside the scope of this document.
### CM7
The Cortex M7 is in charge of initial boot and more importantly all of the engine control. The core uses the following software stack:
- STM32_HAL
- FreeRTOS
- CMSISv2
This fairly low-level software stack, paired with strict coding rules, allows for stable and deterministic engine control. The key coding rules are:
- No heap allocation
- Pointer indirection limited to one level
Further coding rules, guidelines and conventions can be found in CODING.md
This document describes the target `CM7` architecture. Current development-board details and temporary implementation notes live in [`DEVELOPMENT_SETUP.md`](./DEVELOPMENT_SETUP.md).
### CM4
The Cortex M4 handles all of the telemetry, and other vehicle functions. It will be build around ZephyrRTOS to allow for a higher level of abstraction and a complete I/O stack out of the box. The code written for this core will not follow the same rules as for the CM7 as anything run on the CM4 should be non critical to core engine function.
## CM7 Role
## Engine Control
As mentioned previously, all core engine control is handled on the Cortex M7, this is to isolate critical engine control from heavier telemetry operations that are non critical to core engine function.
`CM7` is responsible for:
### Input Signals
The engine provides two key input signals:
- Crank pulse, triggered every 180 deg
- Cam pulse, triggered every 720 deg and slightly dephased
These are both registered using a hardware interrupt using `TIM2` as a low jitter time source.
These signals can have missing pulses or extra triggers which need to be accounted for.
- capturing crank and cam timing edges with low jitter
- maintaining engine phase synchronization
- deriving the current four-stroke cycle position
- scheduling time-critical spark and injection transitions
- keeping interrupt paths short and deterministic
### Time Base
`TIM2` is the main timebase used to control the engine, it provides 4 channels that are used as follows:
- CH_1: Crank input compare
- CH_2: Cam input compare
- CH_3: Undefined
- CH_4: Undefined
The engine-control path should stay small, explicit, and timer-driven.
## Runtime Flow
The target runtime model is:
1. A hardware timer captures crank and cam edges.
2. The input-capture callback stores each timestamp.
3. The callback wakes the task that owns that signal.
4. The task validates the event, updates engine state, and computes future actions.
5. Output-compare events apply scheduled actuator transitions.
Interrupt context owns timestamp capture and exact compare-time transitions. Task context owns filtering, state progression, synchronization, and scheduling decisions.
![CM7 control-flow graph](./img/arch.png)
## Sensors
### Crank
The crank signal is the primary timing source.
- One crank pulse represents `180` engine degrees.
- Consecutive crank intervals estimate current engine speed.
- Crank timing drives phase progression and scheduled outputs.
### Cam
The cam signal is the phase reference.
- One cam pulse represents the `720` degree four-stroke cycle.
- Cam timing is used to establish and recover cycle synchronization.
- Unexpected or missing cam events reduce or clear phase confidence.
## Shared State
The target model uses one compact shared engine state object. It contains:
- synchronization state
- crank cycle state
- cam event state
- cam miss tolerance
- recent crank and cam timestamp history
- scheduled spark state
State shared between ISR and task context must be explicit. If a value crosses that boundary, its ownership and meaning should be clear from the surrounding code.
## Synchronization
Synchronization has three states:
- `SYNC_NOT_OK`: phase is not trusted
- `SYNC_PENDING`: cam has been observed, but phase is not confirmed
- `SYNC_OK`: crank/cam relationship is trusted
Target progression:
1. Boot starts unsynchronized.
2. A cam event moves the system to pending sync.
3. The expected crank/cam phase relationship promotes sync to OK.
4. Missing or unexpected cam behavior drops sync back toward unknown phase.
When synchronized, crank pulses advance through:
1. `CYCLE_COMBUSTION`
2. `CYCLE_EXHAUST`
3. `CYCLE_INTAKE`
4. `CYCLE_COMPRESSION`
When unsynchronized, the crank state remains unknown until cam-assisted phase alignment restores confidence.
## Timing and Scheduling
Scheduled outputs are derived from recent crank timing.
The target scheduler should:
- compute future compare times from measured crank intervals
- arm hardware compare events instead of busy waiting
- keep actuator transitions in compare callbacks short and deterministic
- keep scheduling decisions near the sensor logic that drives them
Spark and injection should both follow this pattern:
1. The crank task computes the next transition time.
2. The timer compare channel is armed.
3. The compare callback applies the transition.
4. Follow-up transitions are scheduled by task logic.
## Core Modules
The intended `CM7` module boundaries are:
- `main.c`: boot, peripheral initialization, HAL callbacks, task creation
- `tasks/crank.c`: crank validation, cycle progression, output scheduling
- `tasks/cam.c`: cam validation and sync promotion
- `global_state.h`: shared state, enums, timing constants
- `ring_buffer.*`: timestamp history
## Open Target Work
The current target architecture still needs final decisions or validation for:
- complete injection scheduling
- final spark dwell-time handling
- production crank/cam phase validation
- sync-loss and recovery thresholds
- final hardware pin and timer routing