Porting to a new MCU family¶
To move Doppelstep to another MCU family, you write one power_stage backend and describe the
board. The motor driver, the X430 driver and the application do not change. Within a family that
already has a backend, only the devicetree and the board configuration change.
What a port needs¶
| Item | Where |
|---|---|
A backend of the power_stage class, with its binding |
drivers/power_stage/, dts/bindings/sfs/ |
| The board, unless Zephyr already has it | boards/ |
| The nodes of the stage, the motor and the servo | app/boards/<board>.overlay |
| Zephyr options of the board: FPU or not, console, flash writes | app/boards/<board>.conf |
Copy drivers/power_stage/power_stage_stm32.c as the starting point, and use the fake backend in
tests/drivers/common/ as the shortest example of the API.
Backend checklist¶
- [ ] The fast callback makes no kernel calls. It runs at the PWM rate in your interrupt. Choose the interrupt type in the backend: zero-latency where the core has it, otherwise the highest normal priority.
- [ ] Sampling instant. With low-side shunts, sample when the low-side switches conduct: at the center of a center-aligned period, triggered by the timer in hardware.
- [ ] Offset calibration runs with the outputs off and blocks only the caller.
- [ ] Polarity.
adc_i_spanfollows the gain sign;current-sense-invertcorrects the result of bring-up step 3. - [ ]
outputs_allowedis false until the dead time is configured, andoutput_enablethen returns-EPERM. - [ ] Outputs start off. Drive the idle levels before the pins connect to the timer.
- [ ]
aux_tripcovers a leg the sample does not show and stays false until calibration has succeeded: with an unknown offset a false trip would latch a fault at every start. Without such a measurement, leaveset_aux_tripout and removeaux-tripfrom the motor node, because the motor driver refuses to start when the node asks for a check the stage cannot do. - [ ]
get_statsis optional: without a cycle counter, leavefast_cycles_maxat 0. - [ ]
pwm-frequencyis an integer multiple ofslow-loop-hz. - [ ] Add the board build to
scripts/ci.shand extend the allowed file list ofscripts/check-layers.shwith the new backend.
What the code above the backend does not assume¶
| Feature | Rule |
|---|---|
| Zero-latency interrupts | The contract is "no kernel calls in the fast callback" |
| FPU | Without an FPU, Kconfig selects the Stepper-C fixed-point backend. CI runs the motion tests on it |
| Cycle counter | fast_cycles_max is optional |
| On-chip amplifiers | They belong to the backend and the board |
| Simulated motor on the board | The plant model uses floating point, so it needs an FPU or a PC |
Example: TI MSPM0G3519¶
This is the planned next family. The figures below come from the datasheet page and from Zephyr v4.5.0, not from a built port.
| Feature | STM32G431 | MSPM0G3519 | Consequence |
|---|---|---|---|
| Core | Cortex-M4F, 170 MHz | Cortex-M0+, 80 MHz | Half the cycles per PWM period |
| Zero-latency interrupts | Yes | No: Zephyr needs BASEPRI | A normal high-priority interrupt, subject to the kernel's interrupt locks |
| FPU | Yes | No | Fixed-point backend |
| Cycle counter (DWT) | Yes | No | No fast_cycles_max, or another timer |
| Motor timers | TIM1 | Two advanced timers with dead band and complementary outputs | New backend |
| ADC | ADC1, ADC2, injected | Two 12-bit ADCs, simultaneous sampling | New backend |
| On-chip amplifiers | OPAMP1..3 | Not listed by TI for this part | External amplifiers on the board |
Zephyr v4.5.0 already has mspm0g3519.dtsi and the board lp_mspm0g3519.
Time budget¶
The main risk is time. At 20 kHz and 80 MHz, one PWM period has 4000 cycles and one millisecond
has 80000. Stepper-C (commit 3ef0f7e, just before v1.2.0) was compiled for Cortex-M0+ with GCC
15.2, fixed-point backend, shared-leg topology, and run in a Cortex-M0 emulator with an M0+ cycle
model:
| Build | Image | Fast loop, max | CPU without stall detection | CPU with stall detection |
|---|---|---|---|---|
-Os |
12.6 KB | 2305 cycles | 64 % | 102 % |
-O2 |
16.5 KB | 1516 cycles | 44 % | 68 % |
CPU figures are the worst case: sustained voltage limiting and a status read every millisecond.
These are estimates
The model has no flash wait states, no Zephyr interrupt entry and no ADC register reads, so real load is higher. Measure on the part before you rely on these numbers.
What to do with them:
- Set
CONFIG_SSTEP_OPTIMIZE_SPEED=y, which builds Stepper-C with-O2. With 512 KB of flash, 4 KB is a small price. - With stall detection on,
sstep_get_status()costs about 9000 cycles. RaiseCONFIG_SFS_STATUS_PERIOD_MS: 10 ms saves about 10 percentage points. - If the budget is still short, lower the fast-loop rate, which Stepper-C accepts as an integer fraction of the PWM rate, or move the fast path to SRAM with Zephyr's code relocation.
The fast loop itself needs no 64-bit arithmetic: the fixed-point backend uses 32-bit multiplications there. 64-bit helpers appear in the slow loop.