Skip to content

drivers: stepper: Stepper driver architectural refactoring #90748

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

andre-stefanov
Copy link

Introduction

Problem description

The current stepper motor driver implementation lacks a standardized and flexible API architecture that can accommodate different stepper motor types, control methods, and motion profiles. This makes it difficult to implement advanced features like ramping (acceleration/deceleration profiles) and to cleanly separate the hardware abstraction from the motion control logic.

Proposed change

Refactor the stepper driver API to create a modular, extensible architecture that separates core functionality from implementation details. This includes creating a clear hierarchy of components: generic stepper interface, timing source, motion controller, and ramp profile abstractions. The architecture will allow for plug-and-play ramp profiles and consistent interfaces across different stepper driver implementations.

Detailed RFC

Proposed change (Detailed)

The refactored stepper API architecture introduces a layered design with three key architectural elements:

  1. Timing Source Layer

    • Provides precise timing for step generation
    • Abstracts hardware-specific timing mechanisms (counters, timers, PWM)
    • Enables consistent timing control across different hardware platforms
  2. Motion Controller Layer

    • Acts as a bridge between the high-level stepper API and low-level hardware control
    • Manages motion profiles and coordinates with the timing source
    • Handles positioning, direction control, and step generation
    • Provides event handling and notification for motion completion and errors
    • Implements common motion control functions like move_by, move_to, and run
  3. Ramp Profile Layer

    • Defines acceleration and deceleration profiles (linear, s-curve, etc.)
    • Pluggable design allows different ramp implementations to be used with any stepper driver
    • Calculates step intervals based on current position and target position
    • Enables smooth motion with controlled acceleration and deceleration
  4. Hardware access Layer

    • Provides common hardware access utilities for common stepper interfaces (e.g. step/dir, h-bridge, SPI, UART or even a composition of those depending on device driver needs and configuration)
    • Acts as an abstraction to be used by device driver, stepper_common or other internal components
    • Reduces boilerplate for device drivers having similar interfaces
graph LR

    subgraph Zephyr
    
    subgraph API
        StepperAPI[Stepper API]
    end
    
    subgraph Device drivers
        TMC22xx[TMC22xx]
        
        StepperAPI --> TMC22xx
    end
    
    subgraph Motion Controller
        MotionController[Motion Controller]
        
        TMC22xx --> MotionController
    end
    
    subgraph Ramp
        RampBase[Ramp Base]
        ConstantRamp[Constant Velocity Ramp]
        TrapezoidalRamp[Trapezoidal Ramp]
        
        TrapezoidalRamp -->|Implements| RampBase
        MotionController --> RampBase
        ConstantRamp -->|Implements| RampBase
    end
    
    subgraph Timing Source
        TimingSourceAPI[Timing Source API]
        Counter[Counter]

        MotionController --> TimingSourceAPI
        Counter -->|Implements| TimingSourceAPI
    end
    
    subgraph Hardware Access
        interface[Stepper interface]

        stepdir[Step/Dir/En]
        gpio[GPIO]

        TMC22xx --> stepdir
        stepdir -->|Implements| interface
        gpio -->|Implements| interface
        MotionController --> interface
    end

    end
    subgraph Application
        CustomRamp
    
        CustomRamp -->|Implements| RampBase
    end

    Application --> StepperAPI
    Application --> TMC22xx
Loading

This architecture separates concerns clearly:

  • Hardware-specific implementations only need to handle device-specific features
  • Motion control logic is reusable across different stepper motor types
  • Timing mechanisms can be optimized for different platforms, MCU features or available hardware components
  • Ramp profiles can be developed and improved independently (e.g. defined in application code for special requirements)

Dependencies

This change affects:

  • Stepper motor driver implementations that need to adapt to the new API
  • Applications that utilize stepper motors and need to migrate to the new interface

The core Zephyr kernel and other subsystems are not affected as this is contained within the driver layer.

Concerns and Unresolved Questions

  1. Performance impact of the abstraction layers, especially for time-critical operations
  2. Ensuring efficient resource usage when multiple stepper motors share hardware resources
  3. Synchronization with vendor specific features provided in hardware (ramp generator, position etc)

The chosen layered approach provides a good balance of flexibility, code reuse, and standardization. By separating the timing source, motion control, and ramp profile concerns, we enable future extensions without major API changes, while providing a consistent experience for application developers across different stepper motor implementations.

Currentl PoC was tested with samples/drivers/stepper/generic by using TMC2209 and a nucleo_f446re.

Copy link
Member

@jilaypandya jilaypandya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool :)

LOG_ERR("Failed to start timing source: %d", ret);
}
}
} else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reduce the nesting with early return :)

return (uint32_t)x;
}

static uint64_t avr446_start_interval(const uint32_t acceleration)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for these functions to have the avr446 prefix?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's an internal function which is implementing part of the AVR446 algorithm.


# zephyr-keep-sorted-start
add_subdirectory(motion_controller)
add_subdirectory(interface)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
add_subdirectory(interface)
add_subdirectory(step_dir_interface)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually i thought this folder could later include multiple different stepper interfaces (like e.g. h-bridge etc). Do we want to have each one in its own folder?

*/
typedef int (*stepper_set_microstep_interval_t)(const struct device *dev,
const uint64_t microstep_interval_ns);
typedef int (*stepper_set_ramp_t)(const struct device *dev, struct stepper_ramp_base *ramp);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this scale up for setting ramp for tmc drivers?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could yes but i am not sure if we really want to handle hardware ramp of trinamic under stepper.h API or deal with it like with any other vendor specific API over e.g. stepper_trinamic.h. this is definitely something to be discussed

*/
stepper_enable_t enable;
/**
* @brief Represents a point in a 2D Cartesian coordinate system.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation is off

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will rewrite it. thx

STEPPER_MOTION_CONTROLLER_DT_INST_DEFINE(inst, &motion_controller_callbacks) \
STEPPER_INTERFACE_STEP_DIR_DT_INST_DEFINE(inst) \
static const struct stepper_common_config common_cfg_##inst = { \
.motion_controller = STEPPER_MOTION_CONTROLLER_DT_INST_GET(inst), \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you have a look at the compliance checks over here, Lot of noise is being created from the GitHub actions

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah compliance checks are my next goal

@andre-stefanov andre-stefanov force-pushed the feature/stepper-refactoring branch 4 times, most recently from cd2e18e to fba3e91 Compare May 28, 2025 22:11
static const struct gpio_dt_spec tmc22xx_stepper_msx_pins_##inst[] = { \
DT_INST_FOREACH_PROP_ELEM_SEP( \
inst, msx_gpios, GPIO_DT_SPEC_GET_BY_IDX, (,) \
), \
Copy link
Member

@jilaypandya jilaypandya May 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to reduce some noise in this File, could we revert the changes related to msx_gpios, so that it's directly visible that motion_controller and interface are getting added. I see the IF_ENABLED and BUILD_ASSERT macros in relation to msx_gpios have been shifted around, but keeping them where they where would make the git diff a bit more pleasant :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ramp_constant is a bit ambiguous i think. Alternative name might be stepper_constant_speed.c .

Copy link
Member

@jilaypandya jilaypandya May 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like personally like how the various phases of a ramp are based on the steps in a particular ramp phase.

*/
int stepper_motion_controller_is_moving(const struct device *dev, bool *is_moving);

int stepper_motion_controller_set_ramp(const struct device *dev, struct stepper_ramp_base *ramp);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing documentation

@@ -0,0 +1,129 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2024 Fabian Blatz <fabianblatz@gmail.com>
* Copyright (c) 2025 Andre Stefanov <mail@andrestefanov.de>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Copyright (c) 2025 Andre Stefanov <mail@andrestefanov.de>
* SPDX-FileCopyrightText: Copyright (c) 2025 Andre Stefanov <mail@andrestefanov.de>

@@ -0,0 +1,104 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2024 Fabian Blatz <fabianblatz@gmail.com>
* 2025 Andre Stefanov <mail@andrestefanov.de>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* 2025 Andre Stefanov <mail@andrestefanov.de>
* SPDX-FileCopyrightText: 2025 Andre Stefanov <mail@andrestefanov.de>

@andre-stefanov andre-stefanov force-pushed the feature/stepper-refactoring branch 6 times, most recently from 23dbd4a to 9b4aebc Compare May 29, 2025 22:03
Introduced modular architecture to the stepper driver to allow
usage of different software and hardware components during
stepper motion.

Signed-off-by: Andre Stefanov <mail@andrestefanov.de>
@andre-stefanov andre-stefanov force-pushed the feature/stepper-refactoring branch from 9b4aebc to b1e1959 Compare May 29, 2025 22:28
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants