First doc writeup
This commit is contained in:
@@ -1,34 +1,124 @@
|
|||||||
# NeoECU Firmware Architecture
|
# NeoECU Target Architecture
|
||||||
|
|
||||||
## AMP
|
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.
|
||||||
NeoECU features an AMP (Asymmetric Multi Processing) architecture making use of both the `CM7` and `CM4` core of the STM32H747 MCU powering NeoECU
|
|
||||||
|
|
||||||
### CM7
|
This document describes the target `CM7` architecture. Current development-board details and temporary implementation notes live in [`DEVELOPMENT_SETUP.md`](./DEVELOPMENT_SETUP.md).
|
||||||
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
|
|
||||||
|
|
||||||
### CM4
|
## CM7 Role
|
||||||
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.
|
|
||||||
|
|
||||||
## Engine Control
|
`CM7` is responsible for:
|
||||||
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.
|
|
||||||
|
|
||||||
### Input Signals
|
- capturing crank and cam timing edges with low jitter
|
||||||
The engine provides two key input signals:
|
- maintaining engine phase synchronization
|
||||||
- Crank pulse, triggered every 180 deg
|
- deriving the current four-stroke cycle position
|
||||||
- Cam pulse, triggered every 720 deg and slightly dephased
|
- scheduling time-critical spark and injection transitions
|
||||||
These are both registered using a hardware interrupt using `TIM2` as a low jitter time source.
|
- keeping interrupt paths short and deterministic
|
||||||
These signals can have missing pulses or extra triggers which need to be accounted for.
|
|
||||||
|
|
||||||
### Time Base
|
The engine-control path should stay small, explicit, and timer-driven.
|
||||||
`TIM2` is the main timebase used to control the engine, it provides 4 channels that are used as follows:
|
|
||||||
- CH_1: Crank input compare
|
## Runtime Flow
|
||||||
- CH_2: Cam input compare
|
|
||||||
- CH_3: Undefined
|
The target runtime model is:
|
||||||
- CH_4: Undefined
|
|
||||||
|
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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 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
|
||||||
|
|||||||
@@ -1,20 +1,27 @@
|
|||||||
# NeoECU Firmware Coding Guidelines
|
# NeoECU Firmware Coding Guidelines
|
||||||
|
|
||||||
## Naming Conventions
|
These rules apply to the `CM7` engine-control firmware.
|
||||||
Functions : camelCase
|
|
||||||
Variables : python_case
|
|
||||||
Constants : UPPER_CASE
|
|
||||||
Macros : UPPER_CASE
|
|
||||||
Types : python_case_t
|
|
||||||
|
|
||||||
## Performance Standard
|
## Style
|
||||||
Don't use heap at all if possible avoid mallocs at all cost.
|
|
||||||
Don't make heavy computation in ISR delegate everything to a task that you'll wake.
|
|
||||||
Don't copy big chunks of memory, use pointers if you need to read a buffer, even if simply passing the buffer as a parameter compiles it will have huge overhead.
|
|
||||||
|
|
||||||
## Readability Standard
|
- Functions: `camelCase`
|
||||||
Avoid more than one layer of pointer indirection if possible.
|
- Variables: `python_case`
|
||||||
Don't use void* they are unclear and make mistakes more likely.
|
- Constants and macros: `UPPER_CASE`
|
||||||
Avoid magic numbers and indexes, use macros and constants to define them clearly.
|
- Types: `python_case_t`
|
||||||
Define all macros in macros.h and all global variables and constants in glocal_state.h.
|
|
||||||
Use one c file per feature, avoid big monoliths that become hard to jump around.
|
## Real-Time Code
|
||||||
|
|
||||||
|
- Do not allocate from the heap in the engine-control path.
|
||||||
|
- Prefer static task, buffer, and control-structure allocation.
|
||||||
|
- Keep ISRs short: capture data, update the minimum state, wake a task, return.
|
||||||
|
- Keep heavy validation, filtering, and scheduling logic in task context.
|
||||||
|
- Avoid avoidable copies, indirection, and generic `void *` plumbing.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
- Keep one source file per feature or subsystem where practical.
|
||||||
|
- Put shared engine state in `global_state.h`.
|
||||||
|
- Put shared helper macros in `macros.h`.
|
||||||
|
- Prefer explicit state machines over implicit control flow.
|
||||||
|
- Make ISR-to-task ownership obvious from names and file placement.
|
||||||
|
- Use named constants and enums instead of magic numbers.
|
||||||
|
|||||||
49
docs/DEVELOPMENT_SETUP.md
Normal file
49
docs/DEVELOPMENT_SETUP.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# Current Development Setup
|
||||||
|
|
||||||
|
This file holds the current `CM7` development setup and implementation specificities. The target architecture is documented in [`ARCHITECTURE.md`](./ARCHITECTURE.md).
|
||||||
|
|
||||||
|
## Platform
|
||||||
|
|
||||||
|
Current bench development targets the STM32H747 on the Arduino Giga platform.
|
||||||
|
|
||||||
|
The present `CM7` code uses:
|
||||||
|
|
||||||
|
- STM32 HAL
|
||||||
|
- FreeRTOS
|
||||||
|
- CMSIS-RTOS v2
|
||||||
|
- `TIM2` as the main engine-control timer
|
||||||
|
|
||||||
|
The current pin mapping is provisional:
|
||||||
|
|
||||||
|
- `TIM2_CH1` / `PA0`: crank input capture
|
||||||
|
- `TIM2_CH2` / `PA1`: cam input capture
|
||||||
|
- `TIM2_CH3` / `PA2`: scheduled spark output compare
|
||||||
|
|
||||||
|
## Implementation Specificities
|
||||||
|
|
||||||
|
### Spark Charge Step
|
||||||
|
|
||||||
|
The current spark path forces a charge transition before scheduling the release transition. This is temporary and belongs to the development setup, not the target architecture.
|
||||||
|
|
||||||
|
The final design should handle dwell time explicitly:
|
||||||
|
|
||||||
|
- compute when charging must begin
|
||||||
|
- compute when spark must release
|
||||||
|
- schedule both as normal output-compare transitions
|
||||||
|
|
||||||
|
### Injection Placeholder
|
||||||
|
|
||||||
|
Injection scheduling is not complete. `tasks/crank.c` contains an early placeholder based on `INJECTION_PHASE`, but there is no finished actuator path yet.
|
||||||
|
|
||||||
|
### Sync Filtering
|
||||||
|
|
||||||
|
The broad sync model is implemented, but thresholds and recovery behavior still need hardware validation. Current behavior includes:
|
||||||
|
|
||||||
|
- `SYNC_NOT_OK`, `SYNC_PENDING`, and `SYNC_OK`
|
||||||
|
- limited cam miss tolerance through `MAX_CAM_MISS`
|
||||||
|
- crank interval filtering while synchronized
|
||||||
|
- sync loss when cam timing is inconsistent with the expected crank state
|
||||||
|
|
||||||
|
### Timer and Pin Routing
|
||||||
|
|
||||||
|
`TIM2` and the current Arduino Giga pins are useful for bench work. They should not be treated as final ECU hardware routing.
|
||||||
BIN
docs/img/arch.png
Normal file
BIN
docs/img/arch.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 166 KiB |
Reference in New Issue
Block a user