From 864723bdd789a28a1879effd42821a188c605c45 Mon Sep 17 00:00:00 2001 From: Jilay Pandya Date: Sat, 21 Jun 2025 14:25:59 +0200 Subject: [PATCH 1/3] drivers: stepper: introduce stepper_drv api introducing stepper_drv api which is to be implemented by the stepper drivers Add fault handling in drv84xx using a fault cb mechanism With the introduction of the stepper_drv api, the goal is to achieve better separation of concerns where motion controllers are responsible for generating step pulses whereaas stepper drivers do are responsible for stepping, enabling, setting microstep resolution Signed-off-by: Jilay Pandya --- drivers/stepper/CMakeLists.txt | 7 +- drivers/stepper/Kconfig | 7 +- .../{Kconfig.gpio => Kconfig.h_bridge} | 4 +- .../stepper/Kconfig.stepper_event_template | 18 - .../Kconfig.zephyr_stepper_motion_controller | 24 ++ drivers/stepper/adi_tmc/tmc22xx.c | 17 +- drivers/stepper/allegro/a4979.c | 17 +- drivers/stepper/gpio_stepper_controller.c | 408 ------------------ drivers/stepper/h_bridge_stepper_driver.c | 230 ++++++++++ drivers/stepper/step_dir/CMakeLists.txt | 2 - drivers/stepper/step_dir/Kconfig | 16 +- .../step_dir/step_dir_stepper_common.c | 304 +------------ .../step_dir/step_dir_stepper_common.h | 165 +------ drivers/stepper/stepper_shell.c | 3 - .../stepper_timing_sources/CMakeLists.txt | 7 + .../stepper/stepper_timing_sources/Kconfig | 18 + .../stepper_counter_timing.c} | 38 +- .../stepper_timing_source.h} | 51 ++- .../stepper_work_timing.c} | 45 +- drivers/stepper/ti/Kconfig.drv84xx | 1 - drivers/stepper/ti/drv84xx.c | 37 +- .../zephyr_stepper_motion_controller.c | 406 +++++++++++++++++ dts/bindings/stepper/adi/adi,tmc2209.yaml | 2 +- dts/bindings/stepper/adi/adi,tmc50xx.yaml | 2 +- .../stepper/adi/adi,tmc51xx-base.yaml | 2 +- .../stepper/allegro/allegro,a4979.yaml | 2 +- .../{stepper-controller.yaml => stepper.yaml} | 4 - dts/bindings/stepper/ti/ti,drv84xx.yaml | 2 +- dts/bindings/stepper/zephyr,fake-stepper.yaml | 2 +- ...pper.yaml => zephyr,h-bridge-stepper.yaml} | 8 +- .../zephyr,stepper-motion-control.yaml | 26 ++ include/zephyr/drivers/stepper.h | 261 ++++++++++- .../generic/boards/nucleo_g071rb.overlay | 21 +- samples/drivers/stepper/generic/prj.conf | 1 + samples/drivers/stepper/generic/src/main.c | 37 +- tests/drivers/build_all/stepper/app.overlay | 13 + tests/drivers/build_all/stepper/gpio.dtsi | 7 +- .../drv84xx/api/boards/native_sim.overlay | 9 +- tests/drivers/stepper/drv84xx/api/prj.conf | 1 + tests/drivers/stepper/drv84xx/api/src/main.c | 2 +- .../drv84xx/emul/boards/native_sim.overlay | 1 - tests/drivers/stepper/drv84xx/emul/src/main.c | 11 +- .../stepper/stepper_api/CMakeLists.txt | 2 +- .../boards/native_sim_adi_tmc2209.overlay | 9 +- .../native_sim_adi_tmc2209_work_q.overlay | 9 +- .../boards/native_sim_allegro_a4979.overlay | 7 + .../native_sim_allegro_a4979_work_q.overlay | 7 + .../boards/native_sim_ti_drv84xx.overlay | 7 + .../native_sim_ti_drv84xx_work_q.overlay | 7 + .../native_sim_zephyr_gpio_stepper.overlay | 14 +- .../qemu_x86_64_zephyr_gpio_stepper.overlay | 19 +- tests/drivers/stepper/stepper_api/src/main.c | 18 +- .../drivers/stepper/stepper_api/testcase.yaml | 12 +- 53 files changed, 1296 insertions(+), 1054 deletions(-) rename drivers/stepper/{Kconfig.gpio => Kconfig.h_bridge} (75%) delete mode 100644 drivers/stepper/Kconfig.stepper_event_template create mode 100644 drivers/stepper/Kconfig.zephyr_stepper_motion_controller delete mode 100644 drivers/stepper/gpio_stepper_controller.c create mode 100644 drivers/stepper/h_bridge_stepper_driver.c create mode 100644 drivers/stepper/stepper_timing_sources/CMakeLists.txt create mode 100644 drivers/stepper/stepper_timing_sources/Kconfig rename drivers/stepper/{step_dir/step_dir_stepper_counter_timing.c => stepper_timing_sources/stepper_counter_timing.c} (63%) rename drivers/stepper/{step_dir/step_dir_stepper_timing_source.h => stepper_timing_sources/stepper_timing_source.h} (50%) rename drivers/stepper/{step_dir/step_dir_stepper_work_timing.c => stepper_timing_sources/stepper_work_timing.c} (53%) create mode 100644 drivers/stepper/zephyr_stepper_motion_controller.c rename dts/bindings/stepper/{stepper-controller.yaml => stepper.yaml} (90%) rename dts/bindings/stepper/{zephyr,gpio-stepper.yaml => zephyr,h-bridge-stepper.yaml} (79%) create mode 100644 dts/bindings/stepper/zephyr,stepper-motion-control.yaml diff --git a/drivers/stepper/CMakeLists.txt b/drivers/stepper/CMakeLists.txt index 1cda468fac48..954c34cd21ae 100644 --- a/drivers/stepper/CMakeLists.txt +++ b/drivers/stepper/CMakeLists.txt @@ -7,6 +7,10 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/stepper.h) add_subdirectory_ifdef(CONFIG_STEPPER_ADI_TMC adi_tmc) add_subdirectory_ifdef(CONFIG_STEPPER_ALLEGRO allegro) add_subdirectory_ifdef(CONFIG_STEPPER_TI ti) +# zephyr-keep-sorted-stop + +# zephyr-keep-sorted-start +add_subdirectory_ifdef(CONFIG_STEPPER_TIMING_SOURCES stepper_timing_sources) add_subdirectory_ifdef(CONFIG_STEP_DIR_STEPPER step_dir) # zephyr-keep-sorted-stop @@ -14,5 +18,6 @@ zephyr_library() zephyr_library_property(ALLOW_EMPTY TRUE) zephyr_library_sources_ifdef(CONFIG_FAKE_STEPPER fake_stepper_controller.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_STEPPER gpio_stepper_controller.c) +zephyr_library_sources_ifdef(CONFIG_H_BRIDGE_STEPPER h_bridge_stepper_driver.c) zephyr_library_sources_ifdef(CONFIG_STEPPER_SHELL stepper_shell.c) +zephyr_library_sources_ifdef(CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL zephyr_stepper_motion_controller.c) diff --git a/drivers/stepper/Kconfig b/drivers/stepper/Kconfig index 075c9130e33f..1bd5ee6ca6d2 100644 --- a/drivers/stepper/Kconfig +++ b/drivers/stepper/Kconfig @@ -27,12 +27,17 @@ config STEPPER_SHELL comment "Stepper Driver Common" rsource "step_dir/Kconfig" +rsource "stepper_timing_sources/Kconfig" comment "Stepper Drivers" # zephyr-keep-sorted-start rsource "Kconfig.fake" -rsource "Kconfig.gpio" +rsource "Kconfig.h_bridge" +rsource "Kconfig.zephyr_stepper_motion_controller" +# zephyr-keep-sorted-stop + +# zephyr-keep-sorted-start rsource "adi_tmc/Kconfig" rsource "allegro/Kconfig" rsource "ti/Kconfig" diff --git a/drivers/stepper/Kconfig.gpio b/drivers/stepper/Kconfig.h_bridge similarity index 75% rename from drivers/stepper/Kconfig.gpio rename to drivers/stepper/Kconfig.h_bridge index 4b43140cd281..cff552908c51 100644 --- a/drivers/stepper/Kconfig.gpio +++ b/drivers/stepper/Kconfig.h_bridge @@ -2,7 +2,7 @@ # SPDX-FileCopyrightText: Copyright (c) 2024 Jilay Sandeep Pandya # SPDX-License-Identifier: Apache-2.0 -config GPIO_STEPPER +config H_BRIDGE_STEPPER bool "Activate driver for gpio stepper control" - depends on DT_HAS_ZEPHYR_GPIO_STEPPER_ENABLED + depends on DT_HAS_ZEPHYR_H_BRIDGE_STEPPER_ENABLED default y diff --git a/drivers/stepper/Kconfig.stepper_event_template b/drivers/stepper/Kconfig.stepper_event_template deleted file mode 100644 index fb29a1e91e0e..000000000000 --- a/drivers/stepper/Kconfig.stepper_event_template +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2024 Fabian Blatz -# SPDX-License-Identifier: Apache-2.0 - -config STEPPER_$(module)_GENERATE_ISR_SAFE_EVENTS - bool "$(module-str) guarantee non ISR callbacks upon stepper events" - help - Enable the dispatch of stepper generated events via - a message queue to guarantee that the event handler - code is not run inside of an ISR. Can be disabled, but - then registered stepper event callback must be ISR safe. - -config STEPPER_$(module)_EVENT_QUEUE_LEN - int "$(module-str) maximum number of pending stepper events" - default 4 - depends on STEPPER_$(module)_GENERATE_ISR_SAFE_EVENTS - help - The maximum number of stepper events that can be pending before new events - are dropped. diff --git a/drivers/stepper/Kconfig.zephyr_stepper_motion_controller b/drivers/stepper/Kconfig.zephyr_stepper_motion_controller new file mode 100644 index 000000000000..4f0666f00174 --- /dev/null +++ b/drivers/stepper/Kconfig.zephyr_stepper_motion_controller @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Jilay Sandeep Pandya +# SPDX-License-Identifier: Apache-2.0 + +config ZEPHYR_STEPPER_MOTION_CONTROL + bool "Zephyr CPU based Stepper motion control" + depends on DT_HAS_ZEPHYR_STEPPER_MOTION_CONTROL_ENABLED + select STEPPER_TIMING_SOURCES + default y + +config ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS + bool "Guarantee non ISR callbacks upon stepper events" + help + Enable the dispatch of stepper generated events via + a message queue to guarantee that the event handler + code is not run inside of an ISR. Can be disabled, but + then registered stepper event callback must be ISR safe. + +config ZEPHYR_STEPPER_MOTION_CONTROL_EVENT_QUEUE_LEN + int "Maximum number of pending stepper events" + default 4 + depends on ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS + help + The maximum number of stepper events that can be pending before new events + are dropped. diff --git a/drivers/stepper/adi_tmc/tmc22xx.c b/drivers/stepper/adi_tmc/tmc22xx.c index fb73dc35fc28..4283516e7f0b 100644 --- a/drivers/stepper/adi_tmc/tmc22xx.c +++ b/drivers/stepper/adi_tmc/tmc22xx.c @@ -19,11 +19,10 @@ struct tmc22xx_config { }; struct tmc22xx_data { - struct step_dir_stepper_common_data common; enum stepper_micro_step_resolution resolution; }; -STEP_DIR_STEPPER_STRUCT_CHECK(struct tmc22xx_config, struct tmc22xx_data); +STEP_DIR_STEPPER_STRUCT_CHECK(struct tmc22xx_config); static int tmc22xx_stepper_enable(const struct device *dev) { @@ -147,18 +146,11 @@ static int tmc22xx_stepper_init(const struct device *dev) return 0; } -static DEVICE_API(stepper, tmc22xx_stepper_api) = { +static DEVICE_API(stepper_drv, tmc22xx_stepper_api) = { .enable = tmc22xx_stepper_enable, .disable = tmc22xx_stepper_disable, - .move_by = step_dir_stepper_common_move_by, - .is_moving = step_dir_stepper_common_is_moving, - .set_reference_position = step_dir_stepper_common_set_reference_position, - .get_actual_position = step_dir_stepper_common_get_actual_position, - .move_to = step_dir_stepper_common_move_to, - .set_microstep_interval = step_dir_stepper_common_set_microstep_interval, - .run = step_dir_stepper_common_run, - .stop = step_dir_stepper_common_stop, - .set_event_callback = step_dir_stepper_common_set_event_callback, + .step = step_dir_stepper_common_step, + .set_direction = step_dir_stepper_common_set_direction, .set_micro_step_res = tmc22xx_stepper_set_micro_step_res, .get_micro_step_res = tmc22xx_stepper_get_micro_step_res, }; @@ -183,7 +175,6 @@ static DEVICE_API(stepper, tmc22xx_stepper_api) = { (.msx_pins = tmc22xx_stepper_msx_pins_##inst)) \ }; \ static struct tmc22xx_data tmc22xx_data_##inst = { \ - .common = STEP_DIR_STEPPER_DT_INST_COMMON_DATA_INIT(inst), \ .resolution = DT_INST_PROP(inst, micro_step_res), \ }; \ DEVICE_DT_INST_DEFINE(inst, tmc22xx_stepper_init, NULL, &tmc22xx_data_##inst, \ diff --git a/drivers/stepper/allegro/a4979.c b/drivers/stepper/allegro/a4979.c index 45f062270c1e..5b8bac4d4629 100644 --- a/drivers/stepper/allegro/a4979.c +++ b/drivers/stepper/allegro/a4979.c @@ -22,11 +22,10 @@ struct a4979_config { }; struct a4979_data { - const struct step_dir_stepper_common_data common; enum stepper_micro_step_resolution micro_step_res; }; -STEP_DIR_STEPPER_STRUCT_CHECK(struct a4979_config, struct a4979_data); +STEP_DIR_STEPPER_STRUCT_CHECK(struct a4979_config); static int a4979_set_microstep_pin(const struct device *dev, const struct gpio_dt_spec *pin, int value) @@ -222,20 +221,13 @@ static int a4979_init(const struct device *dev) return 0; } -static DEVICE_API(stepper, a4979_stepper_api) = { +static DEVICE_API(stepper_drv, a4979_stepper_api) = { .enable = a4979_stepper_enable, .disable = a4979_stepper_disable, - .move_by = step_dir_stepper_common_move_by, - .move_to = step_dir_stepper_common_move_to, - .is_moving = step_dir_stepper_common_is_moving, - .set_reference_position = step_dir_stepper_common_set_reference_position, - .get_actual_position = step_dir_stepper_common_get_actual_position, - .set_microstep_interval = step_dir_stepper_common_set_microstep_interval, - .run = step_dir_stepper_common_run, - .stop = step_dir_stepper_common_stop, .set_micro_step_res = a4979_stepper_set_micro_step_res, .get_micro_step_res = a4979_stepper_get_micro_step_res, - .set_event_callback = step_dir_stepper_common_set_event_callback, + .step = step_dir_stepper_common_step, + .set_direction = step_dir_stepper_common_set_direction, }; #define A4979_DEVICE(inst) \ @@ -249,7 +241,6 @@ static DEVICE_API(stepper, a4979_stepper_api) = { }; \ \ static struct a4979_data a4979_data_##inst = { \ - .common = STEP_DIR_STEPPER_DT_INST_COMMON_DATA_INIT(inst), \ .micro_step_res = DT_INST_PROP(inst, micro_step_res), \ }; \ \ diff --git a/drivers/stepper/gpio_stepper_controller.c b/drivers/stepper/gpio_stepper_controller.c deleted file mode 100644 index 560b8cd54beb..000000000000 --- a/drivers/stepper/gpio_stepper_controller.c +++ /dev/null @@ -1,408 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2024 Carl Zeiss Meditec AG - * SPDX-FileCopyrightText: Copyright (c) 2024 Jilay Sandeep Pandya - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT zephyr_gpio_stepper - -#include -#include -#include -#include -#include - -#include -LOG_MODULE_REGISTER(gpio_stepper_motor_controller, CONFIG_STEPPER_LOG_LEVEL); - -#define MAX_MICRO_STEP_RES STEPPER_MICRO_STEP_2 -#define NUM_CONTROL_PINS 4 - -static const uint8_t - half_step_lookup_table[NUM_CONTROL_PINS * MAX_MICRO_STEP_RES][NUM_CONTROL_PINS] = { - {1u, 1u, 0u, 0u}, {0u, 1u, 0u, 0u}, {0u, 1u, 1u, 0u}, {0u, 0u, 1u, 0u}, - {0u, 0u, 1u, 1u}, {0u, 0u, 0u, 1u}, {1u, 0u, 0u, 1u}, {1u, 0u, 0u, 0u}}; - -struct gpio_stepper_config { - const struct gpio_dt_spec en_pin; - const struct gpio_dt_spec *control_pins; - bool invert_direction; -}; - -struct gpio_stepper_data { - const struct device *dev; - struct k_spinlock lock; - enum stepper_direction direction; - enum stepper_run_mode run_mode; - uint8_t step_gap; - uint8_t coil_charge; - struct k_work_delayable stepper_dwork; - int32_t actual_position; - uint64_t delay_in_ns; - int32_t step_count; - stepper_event_callback_t callback; - void *event_cb_user_data; -}; - -static int stepper_motor_set_coil_charge(const struct device *dev) -{ - struct gpio_stepper_data *data = dev->data; - const struct gpio_stepper_config *config = dev->config; - - for (int i = 0; i < NUM_CONTROL_PINS; i++) { - (void)gpio_pin_set_dt(&config->control_pins[i], - half_step_lookup_table[data->coil_charge][i]); - } - return 0; -} - -static void increment_coil_charge(const struct device *dev) -{ - struct gpio_stepper_data *data = dev->data; - - if (data->coil_charge == NUM_CONTROL_PINS * MAX_MICRO_STEP_RES - data->step_gap) { - data->coil_charge = 0; - } else { - data->coil_charge = data->coil_charge + data->step_gap; - } -} - -static void decrement_coil_charge(const struct device *dev) -{ - struct gpio_stepper_data *data = dev->data; - - if (data->coil_charge == 0) { - data->coil_charge = NUM_CONTROL_PINS * MAX_MICRO_STEP_RES - data->step_gap; - } else { - data->coil_charge = data->coil_charge - data->step_gap; - } -} - -static int energize_coils(const struct device *dev, const bool energized) -{ - const struct gpio_stepper_config *config = dev->config; - - for (int i = 0; i < NUM_CONTROL_PINS; i++) { - const int err = gpio_pin_set_dt(&config->control_pins[i], energized); - - if (err != 0) { - LOG_ERR("Failed to power down coil %d", i); - return err; - } - } - return 0; -} - -static void update_coil_charge(const struct device *dev) -{ - const struct gpio_stepper_config *config = dev->config; - struct gpio_stepper_data *data = dev->data; - - if (data->direction == STEPPER_DIRECTION_POSITIVE) { - config->invert_direction ? decrement_coil_charge(dev) : increment_coil_charge(dev); - data->actual_position++; - } else if (data->direction == STEPPER_DIRECTION_NEGATIVE) { - config->invert_direction ? increment_coil_charge(dev) : decrement_coil_charge(dev); - data->actual_position--; - } -} - -static void update_remaining_steps(const struct device *dev) -{ - struct gpio_stepper_data *data = dev->data; - - if (data->step_count > 0) { - data->step_count--; - } else if (data->step_count < 0) { - data->step_count++; - } -} - -static void update_direction_from_step_count(const struct device *dev) -{ - struct gpio_stepper_data *data = dev->data; - - if (data->step_count > 0) { - data->direction = STEPPER_DIRECTION_POSITIVE; - } else if (data->step_count < 0) { - data->direction = STEPPER_DIRECTION_NEGATIVE; - } else { - LOG_ERR("Step count is zero"); - } -} - -static void position_mode_task(const struct device *dev) -{ - struct gpio_stepper_data *data = dev->data; - - update_remaining_steps(dev); - (void)stepper_motor_set_coil_charge(dev); - update_coil_charge(dev); - if (data->step_count) { - (void)k_work_reschedule(&data->stepper_dwork, K_NSEC(data->delay_in_ns)); - } else { - if (data->callback) { - data->callback(data->dev, STEPPER_EVENT_STEPS_COMPLETED, - data->event_cb_user_data); - } - (void)k_work_cancel_delayable(&data->stepper_dwork); - } -} - -static void velocity_mode_task(const struct device *dev) -{ - struct gpio_stepper_data *data = dev->data; - - (void)stepper_motor_set_coil_charge(dev); - update_coil_charge(dev); - (void)k_work_reschedule(&data->stepper_dwork, K_NSEC(data->delay_in_ns)); -} - -static void stepper_work_step_handler(struct k_work *work) -{ - struct k_work_delayable *dwork = k_work_delayable_from_work(work); - struct gpio_stepper_data *data = - CONTAINER_OF(dwork, struct gpio_stepper_data, stepper_dwork); - - K_SPINLOCK(&data->lock) { - switch (data->run_mode) { - case STEPPER_RUN_MODE_POSITION: - position_mode_task(data->dev); - break; - case STEPPER_RUN_MODE_VELOCITY: - velocity_mode_task(data->dev); - break; - default: - LOG_WRN("Unsupported run mode %d", data->run_mode); - break; - } - } -} - -static int gpio_stepper_move_by(const struct device *dev, int32_t micro_steps) -{ - struct gpio_stepper_data *data = dev->data; - - if (data->delay_in_ns == 0) { - LOG_ERR("Step interval not set or invalid step interval set"); - return -EINVAL; - } - K_SPINLOCK(&data->lock) { - data->run_mode = STEPPER_RUN_MODE_POSITION; - data->step_count = micro_steps; - update_direction_from_step_count(dev); - (void)k_work_reschedule(&data->stepper_dwork, K_NO_WAIT); - } - return 0; -} - -static int gpio_stepper_set_reference_position(const struct device *dev, int32_t position) -{ - struct gpio_stepper_data *data = dev->data; - - K_SPINLOCK(&data->lock) { - data->actual_position = position; - } - return 0; -} - -static int gpio_stepper_get_actual_position(const struct device *dev, int32_t *position) -{ - struct gpio_stepper_data *data = dev->data; - - K_SPINLOCK(&data->lock) { - *position = data->actual_position; - } - return 0; -} - -static int gpio_stepper_move_to(const struct device *dev, int32_t micro_steps) -{ - struct gpio_stepper_data *data = dev->data; - int32_t steps_to_move; - - K_SPINLOCK(&data->lock) { - steps_to_move = micro_steps - data->actual_position; - } - return gpio_stepper_move_by(dev, steps_to_move); -} - -static int gpio_stepper_is_moving(const struct device *dev, bool *is_moving) -{ - struct gpio_stepper_data *data = dev->data; - - *is_moving = k_work_delayable_is_pending(&data->stepper_dwork); - LOG_DBG("Motor is %s moving", *is_moving ? "" : "not"); - return 0; -} - -static int gpio_stepper_set_microstep_interval(const struct device *dev, - uint64_t microstep_interval_ns) -{ - struct gpio_stepper_data *data = dev->data; - - if (microstep_interval_ns == 0) { - LOG_ERR("Step interval is invalid."); - return -EINVAL; - } - - K_SPINLOCK(&data->lock) { - data->delay_in_ns = microstep_interval_ns; - } - LOG_DBG("Setting Motor step interval to %llu", microstep_interval_ns); - return 0; -} - -static int gpio_stepper_run(const struct device *dev, const enum stepper_direction direction) -{ - struct gpio_stepper_data *data = dev->data; - - K_SPINLOCK(&data->lock) { - data->run_mode = STEPPER_RUN_MODE_VELOCITY; - data->direction = direction; - (void)k_work_reschedule(&data->stepper_dwork, K_NO_WAIT); - } - return 0; -} - -static int gpio_stepper_set_micro_step_res(const struct device *dev, - enum stepper_micro_step_resolution micro_step_res) -{ - struct gpio_stepper_data *data = dev->data; - int err = 0; - - K_SPINLOCK(&data->lock) { - switch (micro_step_res) { - case STEPPER_MICRO_STEP_1: - case STEPPER_MICRO_STEP_2: - data->step_gap = MAX_MICRO_STEP_RES >> (micro_step_res - 1); - break; - default: - LOG_ERR("Unsupported micro step resolution %d", micro_step_res); - err = -ENOTSUP; - } - } - return err; -} - -static int gpio_stepper_get_micro_step_res(const struct device *dev, - enum stepper_micro_step_resolution *micro_step_res) -{ - struct gpio_stepper_data *data = dev->data; - *micro_step_res = MAX_MICRO_STEP_RES >> (data->step_gap - 1); - return 0; -} - -static int gpio_stepper_set_event_callback(const struct device *dev, - stepper_event_callback_t callback, void *user_data) -{ - struct gpio_stepper_data *data = dev->data; - - K_SPINLOCK(&data->lock) { - data->callback = callback; - } - data->event_cb_user_data = user_data; - return 0; -} - -static int gpio_stepper_enable(const struct device *dev) -{ - const struct gpio_stepper_config *config = dev->config; - struct gpio_stepper_data *data = dev->data; - int err; - - K_SPINLOCK(&data->lock) { - if (config->en_pin.port != NULL) { - err = gpio_pin_set_dt(&config->en_pin, 1); - } else { - LOG_DBG("No en_pin detected"); - err = -ENOTSUP; - } - } - return err; -} - -static int gpio_stepper_disable(const struct device *dev) -{ - const struct gpio_stepper_config *config = dev->config; - struct gpio_stepper_data *data = dev->data; - int err; - - K_SPINLOCK(&data->lock) { - (void)energize_coils(dev, false); - if (config->en_pin.port != NULL) { - err = gpio_pin_set_dt(&config->en_pin, 0); - } else { - LOG_DBG("No en_pin detected, power stages will not be turned off if " - "stepper is in motion"); - err = -ENOTSUP; - } - } - return err; -} - -static int gpio_stepper_stop(const struct device *dev) -{ - struct gpio_stepper_data *data = dev->data; - int err; - - K_SPINLOCK(&data->lock) { - (void)k_work_cancel_delayable(&data->stepper_dwork); - err = energize_coils(dev, true); - - if (data->callback && !err) { - data->callback(data->dev, STEPPER_EVENT_STOPPED, data->event_cb_user_data); - } - } - return err; -} - -static int gpio_stepper_init(const struct device *dev) -{ - struct gpio_stepper_data *data = dev->data; - const struct gpio_stepper_config *config = dev->config; - - data->dev = dev; - LOG_DBG("Initializing %s gpio_stepper with %d pin", dev->name, NUM_CONTROL_PINS); - for (uint8_t n_pin = 0; n_pin < NUM_CONTROL_PINS; n_pin++) { - (void)gpio_pin_configure_dt(&config->control_pins[n_pin], GPIO_OUTPUT_INACTIVE); - } - k_work_init_delayable(&data->stepper_dwork, stepper_work_step_handler); - return 0; -} - -static DEVICE_API(stepper, gpio_stepper_api) = { - .enable = gpio_stepper_enable, - .disable = gpio_stepper_disable, - .set_micro_step_res = gpio_stepper_set_micro_step_res, - .get_micro_step_res = gpio_stepper_get_micro_step_res, - .set_reference_position = gpio_stepper_set_reference_position, - .get_actual_position = gpio_stepper_get_actual_position, - .set_event_callback = gpio_stepper_set_event_callback, - .set_microstep_interval = gpio_stepper_set_microstep_interval, - .move_by = gpio_stepper_move_by, - .move_to = gpio_stepper_move_to, - .run = gpio_stepper_run, - .stop = gpio_stepper_stop, - .is_moving = gpio_stepper_is_moving, -}; - -#define GPIO_STEPPER_DEFINE(inst) \ - static const struct gpio_dt_spec gpio_stepper_motor_control_pins_##inst[] = { \ - DT_INST_FOREACH_PROP_ELEM_SEP(inst, gpios, GPIO_DT_SPEC_GET_BY_IDX, (,)), \ - }; \ - BUILD_ASSERT(ARRAY_SIZE(gpio_stepper_motor_control_pins_##inst) == 4, \ - "gpio_stepper_controller driver currently supports only 4 wire configuration"); \ - static const struct gpio_stepper_config gpio_stepper_config_##inst = { \ - .invert_direction = DT_INST_PROP(inst, invert_direction), \ - .control_pins = gpio_stepper_motor_control_pins_##inst}; \ - static struct gpio_stepper_data gpio_stepper_data_##inst = { \ - .step_gap = MAX_MICRO_STEP_RES >> (DT_INST_PROP(inst, micro_step_res) - 1), \ - }; \ - BUILD_ASSERT(DT_INST_PROP(inst, micro_step_res) <= STEPPER_MICRO_STEP_2, \ - "gpio_stepper_controller driver supports up to 2 micro steps"); \ - DEVICE_DT_INST_DEFINE(inst, gpio_stepper_init, NULL, &gpio_stepper_data_##inst, \ - &gpio_stepper_config_##inst, POST_KERNEL, \ - CONFIG_STEPPER_INIT_PRIORITY, &gpio_stepper_api); - -DT_INST_FOREACH_STATUS_OKAY(GPIO_STEPPER_DEFINE) diff --git a/drivers/stepper/h_bridge_stepper_driver.c b/drivers/stepper/h_bridge_stepper_driver.c new file mode 100644 index 000000000000..28ef8b1c2532 --- /dev/null +++ b/drivers/stepper/h_bridge_stepper_driver.c @@ -0,0 +1,230 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2025 Jilay Sandeep Pandya + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_h_bridge_stepper + +#include +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(h_bridge_driver, CONFIG_STEPPER_LOG_LEVEL); + +#define MAX_MICRO_STEP_RES STEPPER_MICRO_STEP_2 +#define NUM_CONTROL_PINS 4 + +static const uint8_t + half_step_lookup_table[NUM_CONTROL_PINS * MAX_MICRO_STEP_RES][NUM_CONTROL_PINS] = { + {1u, 1u, 0u, 0u}, {0u, 1u, 0u, 0u}, {0u, 1u, 1u, 0u}, {0u, 0u, 1u, 0u}, + {0u, 0u, 1u, 1u}, {0u, 0u, 0u, 1u}, {1u, 0u, 0u, 1u}, {1u, 0u, 0u, 0u}}; + +struct h_bridge_config { + const struct gpio_dt_spec en_pin; + const struct gpio_dt_spec *control_pins; + bool invert_direction; +}; + +struct h_bridge_data { + struct k_spinlock lock; + enum stepper_direction direction; + uint8_t step_gap; + uint8_t coil_charge; + void *event_cb_user_data; +}; + +static int stepper_motor_set_coil_charge(const struct device *dev) +{ + struct h_bridge_data *data = dev->data; + const struct h_bridge_config *config = dev->config; + + for (int i = 0; i < NUM_CONTROL_PINS; i++) { + (void)gpio_pin_set_dt(&config->control_pins[i], + half_step_lookup_table[data->coil_charge][i]); + } + return 0; +} + +static void increment_coil_charge(const struct device *dev) +{ + struct h_bridge_data *data = dev->data; + + if (data->coil_charge == NUM_CONTROL_PINS * MAX_MICRO_STEP_RES - data->step_gap) { + data->coil_charge = 0; + } else { + data->coil_charge = data->coil_charge + data->step_gap; + } +} + +static void decrement_coil_charge(const struct device *dev) +{ + struct h_bridge_data *data = dev->data; + + if (data->coil_charge == 0) { + data->coil_charge = NUM_CONTROL_PINS * MAX_MICRO_STEP_RES - data->step_gap; + } else { + data->coil_charge = data->coil_charge - data->step_gap; + } +} + +static int deenergize_coils(const struct device *dev) +{ + const struct h_bridge_config *config = dev->config; + + for (int i = 0; i < NUM_CONTROL_PINS; i++) { + const int err = gpio_pin_set_dt(&config->control_pins[i], 0); + + if (err != 0) { + LOG_ERR("Failed to power down coil %d", i); + return err; + } + } + return 0; +} + +static void update_coil_charge(const struct device *dev) +{ + const struct h_bridge_config *config = dev->config; + struct h_bridge_data *data = dev->data; + + if (data->direction == STEPPER_DIRECTION_POSITIVE) { + config->invert_direction ? decrement_coil_charge(dev) : increment_coil_charge(dev); + } else if (data->direction == STEPPER_DIRECTION_NEGATIVE) { + config->invert_direction ? increment_coil_charge(dev) : decrement_coil_charge(dev); + } +} + +static int h_bridge_set_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution micro_step_res) +{ + struct h_bridge_data *data = dev->data; + int err = 0; + + K_SPINLOCK(&data->lock) { + switch (micro_step_res) { + case STEPPER_MICRO_STEP_1: + case STEPPER_MICRO_STEP_2: + data->step_gap = MAX_MICRO_STEP_RES >> (micro_step_res - 1); + break; + default: + LOG_ERR("Unsupported micro step resolution %d", micro_step_res); + err = -ENOTSUP; + } + } + return err; +} + +static int h_bridge_get_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution *micro_step_res) +{ + struct h_bridge_data *data = dev->data; + *micro_step_res = MAX_MICRO_STEP_RES >> (data->step_gap - 1); + return 0; +} + +static int h_bridge_enable(const struct device *dev) +{ + const struct h_bridge_config *config = dev->config; + struct h_bridge_data *data = dev->data; + int err; + + K_SPINLOCK(&data->lock) { + if (config->en_pin.port != NULL) { + err = gpio_pin_set_dt(&config->en_pin, 1); + } else { + LOG_DBG("No en_pin detected"); + err = -ENOTSUP; + } + } + return err; +} + +static int h_bridge_disable(const struct device *dev) +{ + const struct h_bridge_config *config = dev->config; + struct h_bridge_data *data = dev->data; + int err; + + K_SPINLOCK(&data->lock) { + (void)deenergize_coils(dev); + if (config->en_pin.port != NULL) { + err = gpio_pin_set_dt(&config->en_pin, 0); + } else { + LOG_DBG("No en_pin detected, power stages will not be turned off if " + "stepper is in motion"); + err = -ENOTSUP; + } + } + return err; +} + +static int h_bridge_set_direction(const struct device *dev, const enum stepper_direction direction) +{ + struct h_bridge_data *data = dev->data; + + K_SPINLOCK(&data->lock) { + data->direction = direction; + } + + return 0; +} + +static int h_bridge_step(const struct device *dev) +{ + struct h_bridge_data *data = dev->data; + + K_SPINLOCK(&data->lock) { + stepper_motor_set_coil_charge(dev); + update_coil_charge(dev); + } + + return 0; +} + +static int h_bridge_init(const struct device *dev) +{ + const struct h_bridge_config *config = dev->config; + + LOG_DBG("Initializing %s h_bridge with %d pin", dev->name, NUM_CONTROL_PINS); + for (uint8_t n_pin = 0; n_pin < NUM_CONTROL_PINS; n_pin++) { + if (!gpio_is_ready_dt(&config->control_pins[n_pin])) { + LOG_ERR("Control pin %d is not ready", n_pin); + return -ENODEV; + } + (void)gpio_pin_configure_dt(&config->control_pins[n_pin], GPIO_OUTPUT_INACTIVE); + } + return 0; +} + +static DEVICE_API(stepper_drv, h_bridge_api) = { + .enable = h_bridge_enable, + .disable = h_bridge_disable, + .set_micro_step_res = h_bridge_set_micro_step_res, + .get_micro_step_res = h_bridge_get_micro_step_res, + .set_direction = h_bridge_set_direction, + .step = h_bridge_step, +}; + +#define H_BRIDGE_DEFINE(inst) \ + static const struct gpio_dt_spec h_bridge_motor_control_pins_##inst[] = { \ + DT_INST_FOREACH_PROP_ELEM_SEP(inst, gpios, GPIO_DT_SPEC_GET_BY_IDX, (,)), \ + }; \ + BUILD_ASSERT(ARRAY_SIZE(h_bridge_motor_control_pins_##inst) == 4, \ + "h_bridge stepper driver currently supports only 4 wire configuration"); \ + static const struct h_bridge_config h_bridge_config_##inst = { \ + .en_pin = GPIO_DT_SPEC_INST_GET_OR(inst, en_gpios, {0}), \ + .invert_direction = DT_INST_PROP(inst, invert_direction), \ + .control_pins = h_bridge_motor_control_pins_##inst}; \ + static struct h_bridge_data h_bridge_data_##inst = { \ + .step_gap = MAX_MICRO_STEP_RES >> (DT_INST_PROP(inst, micro_step_res) - 1), \ + }; \ + BUILD_ASSERT(DT_INST_PROP(inst, micro_step_res) <= STEPPER_MICRO_STEP_2, \ + "h_bridge stepper driver supports up to 2 micro steps"); \ + DEVICE_DT_INST_DEFINE(inst, h_bridge_init, NULL, &h_bridge_data_##inst, \ + &h_bridge_config_##inst, POST_KERNEL, CONFIG_STEPPER_INIT_PRIORITY, \ + &h_bridge_api); + +DT_INST_FOREACH_STATUS_OKAY(H_BRIDGE_DEFINE) diff --git a/drivers/stepper/step_dir/CMakeLists.txt b/drivers/stepper/step_dir/CMakeLists.txt index 7daa4cc04d5b..6bb451e00067 100644 --- a/drivers/stepper/step_dir/CMakeLists.txt +++ b/drivers/stepper/step_dir/CMakeLists.txt @@ -4,5 +4,3 @@ zephyr_library() zephyr_library_sources(step_dir_stepper_common.c) -zephyr_library_sources(step_dir_stepper_work_timing.c) -zephyr_library_sources_ifdef(CONFIG_STEP_DIR_STEPPER_COUNTER_TIMING step_dir_stepper_counter_timing.c) diff --git a/drivers/stepper/step_dir/Kconfig b/drivers/stepper/step_dir/Kconfig index d8629c649ffd..62d23cf516ff 100644 --- a/drivers/stepper/step_dir/Kconfig +++ b/drivers/stepper/step_dir/Kconfig @@ -3,20 +3,6 @@ config STEP_DIR_STEPPER bool + select GPIO help Enable library used for step direction stepper drivers. - -if STEP_DIR_STEPPER - -config STEP_DIR_STEPPER_COUNTER_TIMING - bool "Counter use for stepping" - select COUNTER - default y - help - Enable usage of a counter device for accurate stepping. - -module = STEP_DIR -module-str = step_dir -rsource "../Kconfig.stepper_event_template" - -endif # STEP_DIR_STEPPER diff --git a/drivers/stepper/step_dir/step_dir_stepper_common.c b/drivers/stepper/step_dir/step_dir_stepper_common.c index b6b7566f07fb..272361fa783c 100644 --- a/drivers/stepper/step_dir/step_dir_stepper_common.c +++ b/drivers/stepper/step_dir/step_dir_stepper_common.c @@ -8,29 +8,10 @@ #include LOG_MODULE_REGISTER(step_dir_stepper, CONFIG_STEPPER_LOG_LEVEL); -static inline int step_dir_stepper_perform_step(const struct device *dev) +int step_dir_stepper_common_step(const struct device *dev) { const struct step_dir_stepper_common_config *config = dev->config; - struct step_dir_stepper_common_data *data = dev->data; - int ret; - - switch (data->direction) { - case STEPPER_DIRECTION_POSITIVE: - ret = gpio_pin_set_dt(&config->dir_pin, 1 ^ config->invert_direction); - break; - case STEPPER_DIRECTION_NEGATIVE: - ret = gpio_pin_set_dt(&config->dir_pin, 0 ^ config->invert_direction); - break; - default: - LOG_ERR("Unsupported direction: %d", data->direction); - return -ENOTSUP; - } - if (ret < 0) { - LOG_ERR("Failed to set direction: %d", ret); - return ret; - } - - ret = gpio_pin_toggle_dt(&config->step_pin); + int ret = gpio_pin_toggle_dt(&config->step_pin); if (ret < 0) { LOG_ERR("Failed to toggle step pin: %d", ret); return ret; @@ -44,142 +25,28 @@ static inline int step_dir_stepper_perform_step(const struct device *dev) } } - if (data->direction == STEPPER_DIRECTION_POSITIVE) { - data->actual_position++; - } else { - data->actual_position--; - } - return 0; } -void stepper_trigger_callback(const struct device *dev, enum stepper_event event) -{ - struct step_dir_stepper_common_data *data = dev->data; - - if (!data->callback) { - LOG_WRN_ONCE("No callback set"); - return; - } - - if (!k_is_in_isr()) { - data->callback(dev, event, data->event_cb_user_data); - return; - } - -#ifdef CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS - /* Dispatch to msgq instead of raising directly */ - int ret = k_msgq_put(&data->event_msgq, &event, K_NO_WAIT); - - if (ret != 0) { - LOG_WRN("Failed to put event in msgq: %d", ret); - } - - ret = k_work_submit(&data->event_callback_work); - if (ret < 0) { - LOG_ERR("Failed to submit work item: %d", ret); - } -#else - LOG_WRN_ONCE("Event callback called from ISR context without ISR safe events enabled"); -#endif /* CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS */ -} - -#ifdef CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS -static void stepper_work_event_handler(struct k_work *work) +int step_dir_stepper_common_set_direction(const struct device *dev, + const enum stepper_direction dir) { - struct step_dir_stepper_common_data *data = - CONTAINER_OF(work, struct step_dir_stepper_common_data, event_callback_work); - enum stepper_event event; - int ret; - - ret = k_msgq_get(&data->event_msgq, &event, K_NO_WAIT); - if (ret != 0) { - return; - } - - /* Run the callback */ - if (data->callback != NULL) { - data->callback(data->dev, event, data->event_cb_user_data); - } - - /* If there are more pending events, resubmit this work item to handle them */ - if (k_msgq_num_used_get(&data->event_msgq) > 0) { - k_work_submit(work); - } -} -#endif /* CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS */ - -static void update_remaining_steps(struct step_dir_stepper_common_data *data) -{ - const struct step_dir_stepper_common_config *config = data->dev->config; - - if (data->step_count > 0) { - data->step_count--; - } else if (data->step_count < 0) { - data->step_count++; - } else { - stepper_trigger_callback(data->dev, STEPPER_EVENT_STEPS_COMPLETED); - config->timing_source->stop(data->dev); - } -} - -static void update_direction_from_step_count(const struct device *dev) -{ - struct step_dir_stepper_common_data *data = dev->data; - - if (data->step_count > 0) { - data->direction = STEPPER_DIRECTION_POSITIVE; - } else if (data->step_count < 0) { - data->direction = STEPPER_DIRECTION_NEGATIVE; - } else { - LOG_ERR("Step count is zero"); - } -} - -static void position_mode_task(const struct device *dev) -{ - struct step_dir_stepper_common_data *data = dev->data; const struct step_dir_stepper_common_config *config = dev->config; + int ret; - if (data->step_count) { - (void)step_dir_stepper_perform_step(dev); - } - - if (config->timing_source->needs_reschedule(dev) && data->step_count != 0) { - (void)config->timing_source->start(dev); - } - - update_remaining_steps(dev->data); -} - -static void velocity_mode_task(const struct device *dev) -{ - const struct step_dir_stepper_common_config *config = dev->config; - - (void)step_dir_stepper_perform_step(dev); - - if (config->timing_source->needs_reschedule(dev)) { - (void)config->timing_source->start(dev); + switch (dir) { + case STEPPER_DIRECTION_POSITIVE: + ret = gpio_pin_set_dt(&config->dir_pin, 1 ^ config->invert_direction); + break; + case STEPPER_DIRECTION_NEGATIVE: + ret = gpio_pin_set_dt(&config->dir_pin, 0 ^ config->invert_direction); + break; + default: + LOG_ERR("Unsupported direction: %d", dir); + return -ENOTSUP; } -} -void stepper_handle_timing_signal(const struct device *dev) -{ - struct step_dir_stepper_common_data *data = dev->data; - - K_SPINLOCK(&data->lock) { - switch (data->run_mode) { - case STEPPER_RUN_MODE_POSITION: - position_mode_task(dev); - break; - case STEPPER_RUN_MODE_VELOCITY: - velocity_mode_task(dev); - break; - default: - LOG_WRN("Unsupported run mode: %d", data->run_mode); - break; - } - } + return ret; } int step_dir_stepper_common_init(const struct device *dev) @@ -204,144 +71,5 @@ int step_dir_stepper_common_init(const struct device *dev) return ret; } - if (config->timing_source->init) { - ret = config->timing_source->init(dev); - if (ret < 0) { - LOG_ERR("Failed to initialize timing source: %d", ret); - return ret; - } - } - -#ifdef CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS - struct step_dir_stepper_common_data *data = dev->data; - - k_msgq_init(&data->event_msgq, data->event_msgq_buffer, sizeof(enum stepper_event), - CONFIG_STEPPER_STEP_DIR_EVENT_QUEUE_LEN); - k_work_init(&data->event_callback_work, stepper_work_event_handler); -#endif /* CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS */ - - return 0; -} - -int step_dir_stepper_common_move_by(const struct device *dev, const int32_t micro_steps) -{ - struct step_dir_stepper_common_data *data = dev->data; - const struct step_dir_stepper_common_config *config = dev->config; - - if (data->microstep_interval_ns == 0) { - LOG_ERR("Step interval not set or invalid step interval set"); - return -EINVAL; - } - - K_SPINLOCK(&data->lock) { - data->run_mode = STEPPER_RUN_MODE_POSITION; - data->step_count = micro_steps; - config->timing_source->update(dev, data->microstep_interval_ns); - update_direction_from_step_count(dev); - config->timing_source->start(dev); - } - - return 0; -} - -int step_dir_stepper_common_set_microstep_interval(const struct device *dev, - const uint64_t microstep_interval_ns) -{ - struct step_dir_stepper_common_data *data = dev->data; - const struct step_dir_stepper_common_config *config = dev->config; - - if (microstep_interval_ns == 0) { - LOG_ERR("Step interval cannot be zero"); - return -EINVAL; - } - - K_SPINLOCK(&data->lock) { - data->microstep_interval_ns = microstep_interval_ns; - config->timing_source->update(dev, microstep_interval_ns); - } - - return 0; -} - -int step_dir_stepper_common_set_reference_position(const struct device *dev, const int32_t value) -{ - struct step_dir_stepper_common_data *data = dev->data; - - K_SPINLOCK(&data->lock) { - data->actual_position = value; - } - - return 0; -} - -int step_dir_stepper_common_get_actual_position(const struct device *dev, int32_t *value) -{ - struct step_dir_stepper_common_data *data = dev->data; - - K_SPINLOCK(&data->lock) { - *value = data->actual_position; - } - - return 0; -} - -int step_dir_stepper_common_move_to(const struct device *dev, const int32_t value) -{ - struct step_dir_stepper_common_data *data = dev->data; - int32_t steps_to_move; - - /* Calculate the relative movement required */ - K_SPINLOCK(&data->lock) { - steps_to_move = value - data->actual_position; - } - - return step_dir_stepper_common_move_by(dev, steps_to_move); -} - -int step_dir_stepper_common_is_moving(const struct device *dev, bool *is_moving) -{ - const struct step_dir_stepper_common_config *config = dev->config; - - *is_moving = config->timing_source->is_running(dev); - return 0; -} - -int step_dir_stepper_common_run(const struct device *dev, const enum stepper_direction direction) -{ - struct step_dir_stepper_common_data *data = dev->data; - const struct step_dir_stepper_common_config *config = dev->config; - - K_SPINLOCK(&data->lock) { - data->run_mode = STEPPER_RUN_MODE_VELOCITY; - data->direction = direction; - config->timing_source->update(dev, data->microstep_interval_ns); - config->timing_source->start(dev); - } - - return 0; -} - -int step_dir_stepper_common_stop(const struct device *dev) -{ - const struct step_dir_stepper_common_config *config = dev->config; - int ret; - - ret = config->timing_source->stop(dev); - if (ret != 0) { - LOG_ERR("Failed to stop timing source: %d", ret); - return ret; - } - - stepper_trigger_callback(dev, STEPPER_EVENT_STOPPED); - return 0; -} - -int step_dir_stepper_common_set_event_callback(const struct device *dev, - stepper_event_callback_t callback, void *user_data) -{ - struct step_dir_stepper_common_data *data = dev->data; - - data->callback = callback; - data->event_cb_user_data = user_data; return 0; } diff --git a/drivers/stepper/step_dir/step_dir_stepper_common.h b/drivers/stepper/step_dir/step_dir_stepper_common.h index b345cf5d68a5..d134f8e70020 100644 --- a/drivers/stepper/step_dir/step_dir_stepper_common.h +++ b/drivers/stepper/step_dir/step_dir_stepper_common.h @@ -17,9 +17,6 @@ #include #include #include -#include - -#include "step_dir_stepper_timing_source.h" /** * @brief Common step direction stepper config. @@ -30,8 +27,6 @@ struct step_dir_stepper_common_config { const struct gpio_dt_spec step_pin; const struct gpio_dt_spec dir_pin; bool dual_edge; - const struct stepper_timing_source_api *timing_source; - const struct device *counter; bool invert_direction; }; @@ -47,11 +42,7 @@ struct step_dir_stepper_common_config { .step_pin = GPIO_DT_SPEC_GET(node_id, step_gpios), \ .dir_pin = GPIO_DT_SPEC_GET(node_id, dir_gpios), \ .dual_edge = DT_PROP_OR(node_id, dual_edge_step, false), \ - .counter = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(node_id, counter)), \ .invert_direction = DT_PROP(node_id, invert_direction), \ - .timing_source = COND_CODE_1(DT_NODE_HAS_PROP(node_id, counter), \ - (&step_counter_timing_source_api), \ - (&step_work_timing_source_api)), \ } /** @@ -61,65 +52,14 @@ struct step_dir_stepper_common_config { #define STEP_DIR_STEPPER_DT_INST_COMMON_CONFIG_INIT(inst) \ STEP_DIR_STEPPER_DT_COMMON_CONFIG_INIT(DT_DRV_INST(inst)) -/** - * @brief Common step direction stepper data. - * - * This structure **must** be placed first in the driver's data structure. - */ -struct step_dir_stepper_common_data { - const struct device *dev; - struct k_spinlock lock; - enum stepper_direction direction; - enum stepper_run_mode run_mode; - int32_t actual_position; - uint64_t microstep_interval_ns; - int32_t step_count; - stepper_event_callback_t callback; - void *event_cb_user_data; - - struct k_work_delayable stepper_dwork; - -#ifdef CONFIG_STEP_DIR_STEPPER_COUNTER_TIMING - struct counter_top_cfg counter_top_cfg; - bool counter_running; -#endif /* CONFIG_STEP_DIR_STEPPER_COUNTER_TIMING */ - -#ifdef CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS - struct k_work event_callback_work; - struct k_msgq event_msgq; - uint8_t event_msgq_buffer[CONFIG_STEPPER_STEP_DIR_EVENT_QUEUE_LEN * - sizeof(enum stepper_event)]; -#endif /* CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS */ -}; - -/** - * @brief Initialize common step direction stepper data from devicetree instance. - * - * @param node_id The devicetree node identifier. - */ -#define STEP_DIR_STEPPER_DT_COMMON_DATA_INIT(node_id) \ - { \ - .dev = DEVICE_DT_GET(node_id), \ - } - -/** - * @brief Initialize common step direction stepper data from devicetree instance. - * @param inst Instance. - */ -#define STEP_DIR_STEPPER_DT_INST_COMMON_DATA_INIT(inst) \ - STEP_DIR_STEPPER_DT_COMMON_DATA_INIT(DT_DRV_INST(inst)) - /** * @brief Validate the offset of the common data structures. * * @param config Name of the config structure. - * @param data Name of the data structure. */ -#define STEP_DIR_STEPPER_STRUCT_CHECK(config, data) \ +#define STEP_DIR_STEPPER_STRUCT_CHECK(config) \ BUILD_ASSERT(offsetof(config, common) == 0, \ - "struct step_dir_stepper_common_config must be placed first"); \ - BUILD_ASSERT(offsetof(data, common) == 0, \ - "struct step_dir_stepper_common_data must be placed first"); + "struct step_dir_stepper_common_config must be placed first"); /** * @brief Common function to initialize a step direction stepper device at init time. @@ -134,103 +74,26 @@ struct step_dir_stepper_common_data { int step_dir_stepper_common_init(const struct device *dev); /** - * @brief Move the stepper motor by a given number of micro_steps. - * - * @param dev Pointer to the device structure. - * @param micro_steps Number of micro_steps to move. Can be positive or negative. - * @return 0 on success, or a negative error code on failure. - */ -int step_dir_stepper_common_move_by(const struct device *dev, const int32_t micro_steps); - -/** - * @brief Set the step interval of the stepper motor. + * @brief Common function to perform a step on a step direction stepper device. * - * @param dev Pointer to the device structure. - * @param microstep_interval_ns The step interval in nanoseconds. - * @return 0 on success, or a negative error code on failure. - */ -int step_dir_stepper_common_set_microstep_interval(const struct device *dev, - const uint64_t microstep_interval_ns); - -/** - * @brief Set the reference position of the stepper motor. - * - * @param dev Pointer to the device structure. - * @param value The reference position value to set. - * @return 0 on success, or a negative error code on failure. - */ -int step_dir_stepper_common_set_reference_position(const struct device *dev, const int32_t value); - -/** - * @brief Get the actual (reference) position of the stepper motor. - * - * @param dev Pointer to the device structure. - * @param value Pointer to a variable where the position value will be stored. - * @return 0 on success, or a negative error code on failure. - */ -int step_dir_stepper_common_get_actual_position(const struct device *dev, int32_t *value); - -/** - * @brief Set the absolute target position of the stepper motor. - * - * @param dev Pointer to the device structure. - * @param value The target position to set. - * @return 0 on success, or a negative error code on failure. - */ -int step_dir_stepper_common_move_to(const struct device *dev, const int32_t value); - -/** - * @brief Check if the stepper motor is still moving. - * - * @param dev Pointer to the device structure. - * @param is_moving Pointer to a boolean where the movement status will be stored. - * @return 0 on success, or a negative error code on failure. - */ -int step_dir_stepper_common_is_moving(const struct device *dev, bool *is_moving); - -/** - * @brief Run the stepper with a given direction and step interval. - * - * @param dev Pointer to the device structure. - * @param direction The direction of movement (positive or negative). - * @return 0 on success, or a negative error code on failure. - */ -int step_dir_stepper_common_run(const struct device *dev, const enum stepper_direction direction); - -/** - * @brief Stop the stepper motor. + * @param dev Step direction stepper device instance. * - * @param dev Pointer to the device structure. - * @return 0 on success, or a negative error code on failure. + * @retval 0 If step performed successfully. + * @retval -errno Negative errno in case of failure. */ -int step_dir_stepper_common_stop(const struct device *dev); +int step_dir_stepper_common_step(const struct device *dev); /** - * @brief Set a callback function for stepper motor events. + * @brief Common function to set the direction of a step direction stepper device. * - * This function sets a user-defined callback that will be invoked when a stepper motor event - * occurs. + * @param dev Step direction stepper device instance. + * @param dir Direction to set. * - * @param dev Pointer to the device structure. - * @param callback The callback function to set. - * @param user_data Pointer to user-defined data that will be passed to the callback. - * @return 0 on success, or a negative error code on failure. - */ -int step_dir_stepper_common_set_event_callback(const struct device *dev, - stepper_event_callback_t callback, void *user_data); - -/** - * @brief Handle a timing signal and update the stepper position. - * @param dev Pointer to the device structure. - */ -void stepper_handle_timing_signal(const struct device *dev); - -/** - * @brief Trigger callback function for stepper motor events. - * @param dev Pointer to the device structure. - * @param event The stepper_event to rigger the callback for. + * @retval 0 If direction set successfully. + * @retval -errno Negative errno in case of failure. */ -void stepper_trigger_callback(const struct device *dev, enum stepper_event event); +int step_dir_stepper_common_set_direction(const struct device *dev, + const enum stepper_direction dir); /** @} */ diff --git a/drivers/stepper/stepper_shell.c b/drivers/stepper/stepper_shell.c index 1e96fb20c5f1..e18da9acb553 100644 --- a/drivers/stepper/stepper_shell.c +++ b/drivers/stepper/stepper_shell.c @@ -64,9 +64,6 @@ static void print_callback(const struct device *dev, const enum stepper_event ev case STEPPER_EVENT_STOPPED: shell_info(sh, "%s: Stepper stopped.", dev->name); break; - case STEPPER_EVENT_FAULT_DETECTED: - shell_info(sh, "%s: Fault detected.", dev->name); - break; default: shell_info(sh, "%s: Unknown signal received.", dev->name); break; diff --git a/drivers/stepper/stepper_timing_sources/CMakeLists.txt b/drivers/stepper/stepper_timing_sources/CMakeLists.txt new file mode 100644 index 000000000000..2b91d8e29d15 --- /dev/null +++ b/drivers/stepper/stepper_timing_sources/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Jilay Sandeep Pandya +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(stepper_work_timing.c) +zephyr_library_sources_ifdef(CONFIG_STEPPER_TIMING_SOURCES_COUNTER_TIMING stepper_counter_timing.c) diff --git a/drivers/stepper/stepper_timing_sources/Kconfig b/drivers/stepper/stepper_timing_sources/Kconfig new file mode 100644 index 000000000000..dd3c9c4f78e5 --- /dev/null +++ b/drivers/stepper/stepper_timing_sources/Kconfig @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Jilay Sandeep Pandya +# SPDX-License-Identifier: Apache-2.0 + +config STEPPER_TIMING_SOURCES + bool "Stepper Timing Sources" + help + Enable timing sources for stepper + +if STEPPER_TIMING_SOURCES + +config STEPPER_TIMING_SOURCES_COUNTER_TIMING + bool "Counter use for stepping" + select COUNTER + default y + help + Enable usage of a counter device for accurate stepping. + +endif diff --git a/drivers/stepper/step_dir/step_dir_stepper_counter_timing.c b/drivers/stepper/stepper_timing_sources/stepper_counter_timing.c similarity index 63% rename from drivers/stepper/step_dir/step_dir_stepper_counter_timing.c rename to drivers/stepper/stepper_timing_sources/stepper_counter_timing.c index bad216961e57..691c60840af4 100644 --- a/drivers/stepper/step_dir/step_dir_stepper_counter_timing.c +++ b/drivers/stepper/stepper_timing_sources/stepper_counter_timing.c @@ -3,25 +3,23 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include -#include "step_dir_stepper_common.h" +#include "stepper_timing_source.h" #include -LOG_MODULE_DECLARE(step_dir_stepper); +LOG_MODULE_REGISTER(stepper_counter_timing, CONFIG_STEPPER_LOG_LEVEL); static void step_counter_top_interrupt(const struct device *dev, void *user_data) { ARG_UNUSED(dev); - struct step_dir_stepper_common_data *data = user_data; + struct timing_source_data *data = user_data; - stepper_handle_timing_signal(data->dev); + data->stepper_handle_timing_signal_cb(data->motion_control_dev); } -int step_counter_timing_source_update(const struct device *dev, +int step_counter_timing_source_update(const struct timing_source_config *config, + struct timing_source_data *data, const uint64_t microstep_interval_ns) { - const struct step_dir_stepper_common_config *config = dev->config; - struct step_dir_stepper_common_data *data = dev->data; int ret; if (microstep_interval_ns == 0) { @@ -39,17 +37,17 @@ int step_counter_timing_source_update(const struct device *dev, irq_unlock(key); if (ret != 0) { - LOG_ERR("%s: Failed to set counter top value (error: %d)", dev->name, ret); + LOG_ERR("%s: Failed to set counter top value (error: %d)", + data->motion_control_dev->name, ret); return ret; } return 0; } -int step_counter_timing_source_start(const struct device *dev) +int step_counter_timing_source_start(const struct timing_source_config *config, + struct timing_source_data *data) { - const struct step_dir_stepper_common_config *config = dev->config; - struct step_dir_stepper_common_data *data = dev->data; int ret; ret = counter_start(config->counter); @@ -63,10 +61,9 @@ int step_counter_timing_source_start(const struct device *dev) return 0; } -int step_counter_timing_source_stop(const struct device *dev) +int step_counter_timing_source_stop(const struct timing_source_config *config, + struct timing_source_data *data) { - const struct step_dir_stepper_common_config *config = dev->config; - struct step_dir_stepper_common_data *data = dev->data; int ret; ret = counter_stop(config->counter); @@ -86,18 +83,15 @@ bool step_counter_timing_source_needs_reschedule(const struct device *dev) return false; } -bool step_counter_timing_source_is_running(const struct device *dev) +bool step_counter_timing_source_is_running(const struct timing_source_config *config, + struct timing_source_data *data) { - struct step_dir_stepper_common_data *data = dev->data; - return data->counter_running; } -int step_counter_timing_source_init(const struct device *dev) +int step_counter_timing_source_init(const struct timing_source_config *config, + struct timing_source_data *data) { - const struct step_dir_stepper_common_config *config = dev->config; - struct step_dir_stepper_common_data *data = dev->data; - if (!device_is_ready(config->counter)) { LOG_ERR("Counter device is not ready"); return -ENODEV; diff --git a/drivers/stepper/step_dir/step_dir_stepper_timing_source.h b/drivers/stepper/stepper_timing_sources/stepper_timing_source.h similarity index 50% rename from drivers/stepper/step_dir/step_dir_stepper_timing_source.h rename to drivers/stepper/stepper_timing_sources/stepper_timing_source.h index 4c77993614af..fc76303536b2 100644 --- a/drivers/stepper/step_dir/step_dir_stepper_timing_source.h +++ b/drivers/stepper/stepper_timing_sources/stepper_timing_source.h @@ -7,32 +7,56 @@ #define ZEPHYR_DRIVER_STEPPER_STEP_DIR_STEPPER_TIMING_SOURCE_H_ #include +#include +#include + +struct timing_source_config { + const struct device *counter; +}; + +struct timing_source_data { + const struct device *motion_control_dev; + uint64_t microstep_interval_ns; + struct k_work_delayable stepper_dwork; + void (*stepper_handle_timing_signal_cb)(const struct device *dev); + +#ifdef CONFIG_STEPPER_TIMING_SOURCES_COUNTER_TIMING + struct counter_top_cfg counter_top_cfg; + bool counter_running; +#endif /* CONFIG_STEPPER_TIMING_SOURCES_COUNTER_TIMING */ +}; /** * @brief Initialize the stepper timing source. * - * @param dev Pointer to the device structure. + * @param config Pointer to the timing source configuration structure. + * @param data Pointer to the timing source data structure. * @return 0 on success, or a negative error code on failure. */ -typedef int (*stepper_timing_source_init)(const struct device *dev); +typedef int (*stepper_timing_source_init)(const struct timing_source_config *config, + struct timing_source_data *data); /** * @brief Update the stepper timing source. * - * @param dev Pointer to the device structure. + * @param config Pointer to the timing source configuration structure. + * @param data Pointer to the timing source data structure. * @param microstep_interval_ns Step interval in nanoseconds. * @return 0 on success, or a negative error code on failure. */ -typedef int (*stepper_timing_source_update)(const struct device *dev, +typedef int (*stepper_timing_source_update)(const struct timing_source_config *config, + struct timing_source_data *data, uint64_t microstep_interval_ns); /** * @brief Start the stepper timing source. * - * @param dev Pointer to the device structure. + * @param config Pointer to the timing source configuration structure. + * @param data Pointer to the timing source data structure. * @return 0 on success, or a negative error code on failure. */ -typedef int (*stepper_timing_source_start)(const struct device *dev); +typedef int (*stepper_timing_source_start)(const struct timing_source_config *config, + struct timing_source_data *data); /** * @brief Whether the stepper timing source requires rescheduling (keeps running @@ -46,18 +70,21 @@ typedef bool (*stepper_timing_sources_requires_reschedule)(const struct device * /** * @brief Stop the stepper timing source. * - * @param dev Pointer to the device structure. + * @param config Pointer to the timing source configuration structure. + * @param data Pointer to the timing source data structure. * @return 0 on success, or a negative error code on failure. */ -typedef int (*stepper_timing_source_stop)(const struct device *dev); +typedef int (*stepper_timing_source_stop)(const struct timing_source_config *config, + struct timing_source_data *data); /** * @brief Check if the stepper timing source is running. * - * @param dev Pointer to the device structure. + * @param data Pointer to the timing source data structure. * @return true if the timing source is running, false otherwise. */ -typedef bool (*stepper_timing_source_is_running)(const struct device *dev); +typedef bool (*stepper_timing_source_is_running)(const struct timing_source_config *config, + struct timing_source_data *data); /** * @brief Stepper timing source API. @@ -72,8 +99,8 @@ struct stepper_timing_source_api { }; extern const struct stepper_timing_source_api step_work_timing_source_api; -#ifdef CONFIG_STEP_DIR_STEPPER_COUNTER_TIMING +#ifdef CONFIG_STEPPER_TIMING_SOURCES_COUNTER_TIMING extern const struct stepper_timing_source_api step_counter_timing_source_api; -#endif /* CONFIG_STEP_DIR_STEPPER_COUNTER_TIMING */ +#endif /* CONFIG_STEPPER_TIMING_SOURCES_COUNTER_TIMING */ #endif /* ZEPHYR_DRIVER_STEPPER_STEP_DIR_STEPPER_TIMING_SOURCE_H_ */ diff --git a/drivers/stepper/step_dir/step_dir_stepper_work_timing.c b/drivers/stepper/stepper_timing_sources/stepper_work_timing.c similarity index 53% rename from drivers/stepper/step_dir/step_dir_stepper_work_timing.c rename to drivers/stepper/stepper_timing_sources/stepper_work_timing.c index ac605f1f4972..917c8aeeacdf 100644 --- a/drivers/stepper/step_dir/step_dir_stepper_work_timing.c +++ b/drivers/stepper/stepper_timing_sources/stepper_work_timing.c @@ -3,13 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "step_dir_stepper_timing_source.h" -#include "step_dir_stepper_common.h" +#include -static k_timeout_t stepper_movement_delay(const struct device *dev) -{ - const struct step_dir_stepper_common_data *data = dev->data; +#include "stepper_timing_source.h" +static k_timeout_t stepper_movement_delay(const struct timing_source_data *data) +{ if (data->microstep_interval_ns == 0) { return K_FOREVER; } @@ -20,39 +19,40 @@ static k_timeout_t stepper_movement_delay(const struct device *dev) static void stepper_work_step_handler(struct k_work *work) { struct k_work_delayable *dwork = k_work_delayable_from_work(work); - struct step_dir_stepper_common_data *data = - CONTAINER_OF(dwork, struct step_dir_stepper_common_data, stepper_dwork); + struct timing_source_data *data = + CONTAINER_OF(dwork, struct timing_source_data, stepper_dwork); - stepper_handle_timing_signal(data->dev); + data->stepper_handle_timing_signal_cb(data->motion_control_dev); } -int step_work_timing_source_init(const struct device *dev) +int step_work_timing_source_init(const struct timing_source_config *config, + struct timing_source_data *data) { - struct step_dir_stepper_common_data *data = dev->data; - k_work_init_delayable(&data->stepper_dwork, stepper_work_step_handler); return 0; } -int step_work_timing_source_update(const struct device *dev, const uint64_t microstep_interval_ns) +int step_work_timing_source_update(const struct timing_source_config *config, + struct timing_source_data *data, + const uint64_t microstep_interval_ns) { - ARG_UNUSED(dev); + ARG_UNUSED(config); + ARG_UNUSED(data); ARG_UNUSED(microstep_interval_ns); return 0; } -int step_work_timing_source_start(const struct device *dev) +int step_work_timing_source_start(const struct timing_source_config *config, + struct timing_source_data *data) { - struct step_dir_stepper_common_data *data = dev->data; - - return k_work_reschedule(&data->stepper_dwork, stepper_movement_delay(dev)); + ARG_UNUSED(config); + return k_work_reschedule(&data->stepper_dwork, stepper_movement_delay(data)); } -int step_work_timing_source_stop(const struct device *dev) +int step_work_timing_source_stop(const struct timing_source_config *config, + struct timing_source_data *data) { - struct step_dir_stepper_common_data *data = dev->data; - return k_work_cancel_delayable(&data->stepper_dwork); } @@ -62,10 +62,9 @@ bool step_work_timing_source_needs_reschedule(const struct device *dev) return true; } -bool step_work_timing_source_is_running(const struct device *dev) +bool step_work_timing_source_is_running(const struct timing_source_config *config, + struct timing_source_data *data) { - struct step_dir_stepper_common_data *data = dev->data; - return k_work_delayable_is_pending(&data->stepper_dwork); } diff --git a/drivers/stepper/ti/Kconfig.drv84xx b/drivers/stepper/ti/Kconfig.drv84xx index e5466890c66d..10cdd06433ee 100644 --- a/drivers/stepper/ti/Kconfig.drv84xx +++ b/drivers/stepper/ti/Kconfig.drv84xx @@ -7,6 +7,5 @@ config DRV84XX depends on DT_HAS_TI_DRV84XX_ENABLED select STEPPER_TI select STEP_DIR_STEPPER - select STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS help Enable driver for TI DRV84XX stepper motor driver. diff --git a/drivers/stepper/ti/drv84xx.c b/drivers/stepper/ti/drv84xx.c index 5e99964abea6..5f3055db8b11 100644 --- a/drivers/stepper/ti/drv84xx.c +++ b/drivers/stepper/ti/drv84xx.c @@ -47,14 +47,15 @@ struct drv84xx_pin_states { * @brief DRV84XX stepper driver data. */ struct drv84xx_data { - const struct step_dir_stepper_common_data common; const struct device *dev; struct drv84xx_pin_states pin_states; enum stepper_micro_step_resolution ustep_res; struct gpio_callback fault_cb_data; + stepper_drv_fault_cb_t fault_cb; + void *fault_cb_user_data; }; -STEP_DIR_STEPPER_STRUCT_CHECK(struct drv84xx_config, struct drv84xx_data); +STEP_DIR_STEPPER_STRUCT_CHECK(struct drv84xx_config); static int drv84xx_set_microstep_pin(const struct device *dev, const struct gpio_dt_spec *pin, int value) @@ -255,6 +256,17 @@ static int drv84xx_disable(const struct device *dev) return ret; } +static int drv84xx_set_fault_cb(const struct device *dev, stepper_drv_fault_cb_t fault_cb, + void *user_data) +{ + struct drv84xx_data *data = dev->data; + + data->fault_cb = fault_cb; + data->fault_cb_user_data = user_data; + + return 0; +} + static int drv84xx_set_micro_step_res(const struct device *dev, enum stepper_micro_step_resolution micro_step_res) { @@ -348,7 +360,11 @@ void fault_event(const struct device *dev, struct gpio_callback *cb, uint32_t pi { struct drv84xx_data *data = CONTAINER_OF(cb, struct drv84xx_data, fault_cb_data); - stepper_trigger_callback(data->dev, STEPPER_EVENT_FAULT_DETECTED); + if (data->fault_cb != NULL) { + data->fault_cb(data->dev, data->fault_cb_user_data); + } else { + LOG_WRN_ONCE("%s: Fault pin triggered but no callback is set", dev->name); + } } static int drv84xx_init(const struct device *dev) @@ -432,20 +448,14 @@ static int drv84xx_init(const struct device *dev) return 0; } -static DEVICE_API(stepper, drv84xx_stepper_api) = { +static DEVICE_API(stepper_drv, drv84xx_stepper_api) = { .enable = drv84xx_enable, .disable = drv84xx_disable, - .move_by = step_dir_stepper_common_move_by, - .move_to = step_dir_stepper_common_move_to, - .is_moving = step_dir_stepper_common_is_moving, - .set_reference_position = step_dir_stepper_common_set_reference_position, - .get_actual_position = step_dir_stepper_common_get_actual_position, - .set_microstep_interval = step_dir_stepper_common_set_microstep_interval, - .run = step_dir_stepper_common_run, - .stop = step_dir_stepper_common_stop, + .set_fault_cb = drv84xx_set_fault_cb, .set_micro_step_res = drv84xx_set_micro_step_res, .get_micro_step_res = drv84xx_get_micro_step_res, - .set_event_callback = step_dir_stepper_common_set_event_callback, + .step = step_dir_stepper_common_step, + .set_direction = step_dir_stepper_common_set_direction, }; #define DRV84XX_DEVICE(inst) \ @@ -460,7 +470,6 @@ static DEVICE_API(stepper, drv84xx_stepper_api) = { }; \ \ static struct drv84xx_data drv84xx_data_##inst = { \ - .common = STEP_DIR_STEPPER_DT_INST_COMMON_DATA_INIT(inst), \ .ustep_res = DT_INST_PROP(inst, micro_step_res), \ .dev = DEVICE_DT_INST_GET(inst), \ }; \ diff --git a/drivers/stepper/zephyr_stepper_motion_controller.c b/drivers/stepper/zephyr_stepper_motion_controller.c new file mode 100644 index 000000000000..a6b65124c4ef --- /dev/null +++ b/drivers/stepper/zephyr_stepper_motion_controller.c @@ -0,0 +1,406 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2025 Jilay Sandeep Pandya + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_stepper_motion_control + +#include +#include +#include + +#include "stepper_timing_sources/stepper_timing_source.h" + +#include +LOG_MODULE_REGISTER(stepper_motion_control, CONFIG_STEPPER_LOG_LEVEL); + +struct stepper_motion_control_config { + const struct device *stepper; + const struct timing_source_config timing_config; + const struct stepper_timing_source_api *timing_source; +}; + +struct stepper_motion_control_data { + const struct device *dev; + struct k_spinlock lock; + int32_t step_count; + enum stepper_direction direction; + enum stepper_run_mode run_mode; + int32_t actual_position; + stepper_event_callback_t callback; + void *event_cb_user_data; + struct timing_source_data timing_data; +#ifdef CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS + struct k_work event_callback_work; + struct k_msgq event_msgq; + uint8_t event_msgq_buffer[CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_EVENT_QUEUE_LEN * + sizeof(enum stepper_event)]; +#endif /* CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS */ +}; + +void stepper_trigger_callback(const struct device *dev, enum stepper_event event) +{ + struct stepper_motion_control_data *data = dev->data; + + if (!data->callback) { + LOG_WRN_ONCE("No callback set"); + return; + } + + if (!k_is_in_isr()) { + data->callback(dev, event, data->event_cb_user_data); + return; + } + +#ifdef CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS + /* Dispatch to msgq instead of raising directly */ + int ret = k_msgq_put(&data->event_msgq, &event, K_NO_WAIT); + + if (ret != 0) { + LOG_WRN("Failed to put event in msgq: %d", ret); + } + + ret = k_work_submit(&data->event_callback_work); + if (ret < 0) { + LOG_ERR("Failed to submit work item: %d", ret); + } +#else + LOG_WRN_ONCE("Event callback called from ISR context without ISR safe events enabled"); +#endif /* CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS */ +} + +#ifdef CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS +static void stepper_work_event_handler(struct k_work *work) +{ + struct stepper_motion_control_data *data = + CONTAINER_OF(work, struct stepper_motion_control_data, event_callback_work); + enum stepper_event event; + int ret; + + ret = k_msgq_get(&data->event_msgq, &event, K_NO_WAIT); + if (ret != 0) { + return; + } + + /* Run the callback */ + if (data->callback != NULL) { + data->callback(data->dev, event, data->event_cb_user_data); + } + + /* If there are more pending events, resubmit this work item to handle them */ + if (k_msgq_num_used_get(&data->event_msgq) > 0) { + k_work_submit(work); + } +} +#endif /* CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS */ + +static void update_direction_from_step_count(const struct device *dev) +{ + struct stepper_motion_control_data *data = dev->data; + + if (data->step_count > 0) { + data->direction = STEPPER_DIRECTION_POSITIVE; + } else if (data->step_count < 0) { + data->direction = STEPPER_DIRECTION_NEGATIVE; + } else { + LOG_ERR("Step count is zero"); + } +} + +static int z_stepper_motion_control_move_by(const struct device *dev, int32_t micro_steps) +{ + const struct stepper_motion_control_config *config = dev->config; + struct stepper_motion_control_data *data = dev->data; + + if (data->timing_data.microstep_interval_ns == 0) { + LOG_ERR("Step interval not set or invalid step interval set"); + return -EINVAL; + } + + if (micro_steps == 0) { + stepper_trigger_callback(data->dev, STEPPER_EVENT_STEPS_COMPLETED); + config->timing_source->stop(&config->timing_config, &data->timing_data); + return 0; + } + + K_SPINLOCK(&data->lock) { + data->run_mode = STEPPER_RUN_MODE_POSITION; + data->step_count = micro_steps; + config->timing_source->update(&config->timing_config, &data->timing_data, + data->timing_data.microstep_interval_ns); + update_direction_from_step_count(dev); + stepper_drv_set_direction(config->stepper, data->direction); + config->timing_source->start(&config->timing_config, &data->timing_data); + } + return 0; +} + +static int z_stepper_motion_control_move_to(const struct device *dev, int32_t micro_steps) +{ + struct stepper_motion_control_data *data = dev->data; + int32_t steps_to_move; + + K_SPINLOCK(&data->lock) { + steps_to_move = micro_steps - data->actual_position; + } + return z_stepper_motion_control_move_by(dev, steps_to_move); +} + +static int z_stepper_motion_control_run(const struct device *dev, + const enum stepper_direction direction) +{ + const struct stepper_motion_control_config *config = dev->config; + struct stepper_motion_control_data *data = dev->data; + + K_SPINLOCK(&data->lock) { + data->run_mode = STEPPER_RUN_MODE_VELOCITY; + data->direction = direction; + config->timing_source->update(&config->timing_config, &data->timing_data, + data->timing_data.microstep_interval_ns); + stepper_drv_set_direction(config->stepper, direction); + config->timing_source->start(&config->timing_config, &data->timing_data); + } + return 0; +} + +static int z_stepper_motion_control_stop(const struct device *dev) +{ + const struct stepper_motion_control_config *config = dev->config; + struct stepper_motion_control_data *data = dev->data; + int ret; + + ret = config->timing_source->stop(&config->timing_config, &data->timing_data); + if (ret != 0) { + LOG_ERR("Failed to stop timing source: %d", ret); + return ret; + } + stepper_trigger_callback(dev, STEPPER_EVENT_STOPPED); + + return 0; +} + +static int z_stepper_motion_control_set_reference_position(const struct device *dev, + int32_t position) +{ + struct stepper_motion_control_data *data = dev->data; + + K_SPINLOCK(&data->lock) { + data->actual_position = position; + } + return 0; +} + +static int z_stepper_motion_control_get_actual_position(const struct device *dev, int32_t *position) +{ + struct stepper_motion_control_data *data = dev->data; + + K_SPINLOCK(&data->lock) { + *position = data->actual_position; + } + return 0; +} + +static int z_stepper_motion_control_set_step_interval(const struct device *dev, + uint64_t microstep_interval_ns) +{ + const struct stepper_motion_control_config *config = dev->config; + struct stepper_motion_control_data *data = dev->data; + + if (microstep_interval_ns == 0) { + LOG_ERR("Step interval is invalid."); + return -EINVAL; + } + + K_SPINLOCK(&data->lock) { + data->timing_data.microstep_interval_ns = microstep_interval_ns; + config->timing_source->update(&config->timing_config, &data->timing_data, + microstep_interval_ns); + } + LOG_DBG("Setting Motor step interval to %llu", microstep_interval_ns); + return 0; +} + +static int z_stepper_motion_control_is_moving(const struct device *dev, bool *is_moving) +{ + const struct stepper_motion_control_config *config = dev->config; + struct stepper_motion_control_data *data = dev->data; + + *is_moving = config->timing_source->is_running(&config->timing_config, &data->timing_data); + LOG_DBG("Motor is %s moving", *is_moving ? "" : "not"); + return 0; +} + +static void update_remaining_steps(const struct device *dev) +{ + struct stepper_motion_control_data *data = dev->data; + + if (data->step_count > 0) { + data->step_count--; + } else if (data->step_count < 0) { + data->step_count++; + } +} + +static void update_actual_position(const struct device *dev) +{ + struct stepper_motion_control_data *data = dev->data; + + if (data->direction == STEPPER_DIRECTION_POSITIVE) { + data->actual_position++; + } else { + data->actual_position--; + } +} + +static void position_mode_task(const struct device *dev) +{ + const struct stepper_motion_control_config *config = dev->config; + struct stepper_motion_control_data *data = dev->data; + + stepper_drv_step(config->stepper); + update_remaining_steps(dev); + update_actual_position(dev); + + if (config->timing_source->needs_reschedule(dev) && data->step_count != 0) { + config->timing_source->start(&config->timing_config, &data->timing_data); + } else if (data->step_count == 0) { + config->timing_source->stop(&config->timing_config, &data->timing_data); + stepper_trigger_callback(data->dev, STEPPER_EVENT_STEPS_COMPLETED); + } +} + +static void velocity_mode_task(const struct device *dev) +{ + const struct stepper_motion_control_config *config = dev->config; + struct stepper_motion_control_data *data = dev->data; + + stepper_drv_step(config->stepper); + update_actual_position(dev); + + if (config->timing_source->needs_reschedule(dev)) { + (void)config->timing_source->start(&config->timing_config, &data->timing_data); + } +} + +static int z_stepper_motion_control_set_event_callback(const struct device *dev, + stepper_event_callback_t cb, void *user_data) +{ + struct stepper_motion_control_data *data = dev->data; + + K_SPINLOCK(&data->lock) { + data->callback = cb; + data->event_cb_user_data = user_data; + } + return 0; +} + +void stepper_handle_timing_signal(const struct device *dev) +{ + struct stepper_motion_control_data *data = dev->data; + + K_SPINLOCK(&data->lock) { + switch (data->run_mode) { + case STEPPER_RUN_MODE_POSITION: + position_mode_task(dev); + break; + case STEPPER_RUN_MODE_VELOCITY: + velocity_mode_task(dev); + break; + default: + LOG_WRN("Unsupported run mode: %d", data->run_mode); + break; + } + } +} + +static int z_stepper_motion_control_enable(const struct device *dev) +{ + const struct stepper_motion_control_config *config = dev->config; + + return stepper_drv_enable(config->stepper); +} + +static int z_stepper_motion_control_disable(const struct device *dev) +{ + const struct stepper_motion_control_config *config = dev->config; + + return stepper_drv_disable(config->stepper); +} + +static int z_stepper_motion_control_set_micro_step_res(const struct device *dev, + const enum stepper_micro_step_resolution res) +{ + const struct stepper_motion_control_config *config = dev->config; + + return stepper_drv_set_micro_stepper_res(config->stepper, res); +} + +static int z_stepper_motion_control_get_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution *res) +{ + const struct stepper_motion_control_config *config = dev->config; + + return stepper_drv_get_micro_step_res(config->stepper, res); +} + +static int stepper_motion_control_init(const struct device *dev) +{ + const struct stepper_motion_control_config *config = dev->config; + struct stepper_motion_control_data *data = dev->data; + int ret; + + data->dev = dev; + + __ASSERT_NO_MSG(config->timing_source->init != NULL); + + ret = config->timing_source->init(&config->timing_config, &data->timing_data); + if (ret < 0) { + LOG_ERR("Failed to initialize timing source: %d", ret); + return ret; + } + +#ifdef CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS + + k_msgq_init(&data->event_msgq, data->event_msgq_buffer, sizeof(enum stepper_event), + CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_EVENT_QUEUE_LEN); + k_work_init(&data->event_callback_work, stepper_work_event_handler); +#endif /* CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS */ + + LOG_DBG("Stepper Control initialized for stepper driver %s", config->stepper->name); + return 0; +} + +static DEVICE_API(stepper, zephyr_stepper_motion_control_api) = { + .enable = z_stepper_motion_control_enable, + .disable = z_stepper_motion_control_disable, + .set_micro_step_res = z_stepper_motion_control_set_micro_step_res, + .get_micro_step_res = z_stepper_motion_control_get_micro_step_res, + .move_to = z_stepper_motion_control_move_to, + .move_by = z_stepper_motion_control_move_by, + .run = z_stepper_motion_control_run, + .set_microstep_interval = z_stepper_motion_control_set_step_interval, + .get_actual_position = z_stepper_motion_control_get_actual_position, + .set_reference_position = z_stepper_motion_control_set_reference_position, + .is_moving = z_stepper_motion_control_is_moving, + .stop = z_stepper_motion_control_stop, + .set_event_callback = z_stepper_motion_control_set_event_callback, +}; + +#define STEPPER_MOTION_CONTROL_DEFINE(inst) \ + static const struct stepper_motion_control_config stepper_motion_control_config_##inst = { \ + .stepper = DEVICE_DT_GET(DT_PHANDLE(DT_DRV_INST(inst), stepper)), \ + .timing_config.counter = \ + DEVICE_DT_GET_OR_NULL(DT_PHANDLE(DT_DRV_INST(inst), counter)), \ + .timing_source = COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, counter), \ + (&step_counter_timing_source_api), (&step_work_timing_source_api)), \ + }; \ + struct stepper_motion_control_data stepper_motion_control_data_##inst = { \ + .timing_data.motion_control_dev = DEVICE_DT_GET(DT_DRV_INST(inst)), \ + .timing_data.stepper_handle_timing_signal_cb = stepper_handle_timing_signal, \ + }; \ + DEVICE_DT_INST_DEFINE(inst, stepper_motion_control_init, NULL, \ + &stepper_motion_control_data_##inst, \ + &stepper_motion_control_config_##inst, POST_KERNEL, \ + CONFIG_STEPPER_INIT_PRIORITY, &zephyr_stepper_motion_control_api); + +DT_INST_FOREACH_STATUS_OKAY(STEPPER_MOTION_CONTROL_DEFINE) diff --git a/dts/bindings/stepper/adi/adi,tmc2209.yaml b/dts/bindings/stepper/adi/adi,tmc2209.yaml index 17e44b273082..f9e74c82cbe5 100644 --- a/dts/bindings/stepper/adi/adi,tmc2209.yaml +++ b/dts/bindings/stepper/adi/adi,tmc2209.yaml @@ -18,7 +18,7 @@ description: | compatible: "adi,tmc2209" include: - - name: stepper-controller.yaml + - name: stepper.yaml properties: msx-gpios: diff --git a/dts/bindings/stepper/adi/adi,tmc50xx.yaml b/dts/bindings/stepper/adi/adi,tmc50xx.yaml index eba9cd3f664c..c62915863593 100644 --- a/dts/bindings/stepper/adi/adi,tmc50xx.yaml +++ b/dts/bindings/stepper/adi/adi,tmc50xx.yaml @@ -85,7 +85,7 @@ properties: child-binding: include: - - name: stepper-controller.yaml + - name: stepper.yaml - name: base.yaml property-allowlist: - reg diff --git a/dts/bindings/stepper/adi/adi,tmc51xx-base.yaml b/dts/bindings/stepper/adi/adi,tmc51xx-base.yaml index dbdd40065c4a..62def383cbaf 100644 --- a/dts/bindings/stepper/adi/adi,tmc51xx-base.yaml +++ b/dts/bindings/stepper/adi/adi,tmc51xx-base.yaml @@ -9,7 +9,7 @@ include: property-allowlist: - en-pwm-mode - test-mode - - name: stepper-controller.yaml + - name: stepper.yaml - name: adi,trinamic-ramp-generator.yaml property-allowlist: - vstart diff --git a/dts/bindings/stepper/allegro/allegro,a4979.yaml b/dts/bindings/stepper/allegro/allegro,a4979.yaml index c9e53b7a066c..5ce264b50094 100644 --- a/dts/bindings/stepper/allegro/allegro,a4979.yaml +++ b/dts/bindings/stepper/allegro/allegro,a4979.yaml @@ -24,7 +24,7 @@ description: | compatible: "allegro,a4979" include: - - name: stepper-controller.yaml + - name: stepper.yaml properties: m0-gpios: diff --git a/dts/bindings/stepper/stepper-controller.yaml b/dts/bindings/stepper/stepper.yaml similarity index 90% rename from dts/bindings/stepper/stepper-controller.yaml rename to dts/bindings/stepper/stepper.yaml index a73037bb6b97..eae57a18a25c 100644 --- a/dts/bindings/stepper/stepper-controller.yaml +++ b/dts/bindings/stepper/stepper.yaml @@ -40,7 +40,3 @@ properties: description: | The GPIO pins used to send direction signals to the stepper motor. Pin will be driven high for forward direction and low for reverse direction. - - counter: - type: phandle - description: Counter used for generating step-accurate pulse signals. diff --git a/dts/bindings/stepper/ti/ti,drv84xx.yaml b/dts/bindings/stepper/ti/ti,drv84xx.yaml index 3b891d1d17c3..668c3d8861ef 100644 --- a/dts/bindings/stepper/ti/ti,drv84xx.yaml +++ b/dts/bindings/stepper/ti/ti,drv84xx.yaml @@ -30,7 +30,7 @@ description: | compatible: "ti,drv84xx" include: - - name: stepper-controller.yaml + - name: stepper.yaml properties: fault-gpios: diff --git a/dts/bindings/stepper/zephyr,fake-stepper.yaml b/dts/bindings/stepper/zephyr,fake-stepper.yaml index d286dfbfeb4c..3c6d01ff0859 100644 --- a/dts/bindings/stepper/zephyr,fake-stepper.yaml +++ b/dts/bindings/stepper/zephyr,fake-stepper.yaml @@ -7,4 +7,4 @@ description: | compatible: "zephyr,fake-stepper" -include: stepper-controller.yaml +include: stepper.yaml diff --git a/dts/bindings/stepper/zephyr,gpio-stepper.yaml b/dts/bindings/stepper/zephyr,h-bridge-stepper.yaml similarity index 79% rename from dts/bindings/stepper/zephyr,gpio-stepper.yaml rename to dts/bindings/stepper/zephyr,h-bridge-stepper.yaml index 95477d213998..77d928428295 100644 --- a/dts/bindings/stepper/zephyr,gpio-stepper.yaml +++ b/dts/bindings/stepper/zephyr,h-bridge-stepper.yaml @@ -3,21 +3,21 @@ # SPDX-License-Identifier: Apache-2.0 description: | - GPIO Stepper Controller for darlington transistor arrays or dual H-bridge + H-Bridge Stepper Driver Example: /* Lead A is connected Lead C and Lead B is connected to Lead D*/ stepper: stepper { - compatible = "zephyr,gpio-stepper"; + compatible = "zephyr,h-bridge-stepper"; gpios = <&gpioa 9 GPIO_ACTIVE_HIGH>, /* Lead A1/A */ <&gpioc 7 GPIO_ACTIVE_HIGH>, /* Lead B1/B */ <&gpiob 0 GPIO_ACTIVE_HIGH>, /* Lead A2/C */ <&gpioa 7 GPIO_ACTIVE_HIGH>; /* Lead B2/D */ }; -compatible: "zephyr,gpio-stepper" +compatible: "zephyr,h-bridge-stepper" -include: stepper-controller.yaml +include: stepper.yaml properties: gpios: diff --git a/dts/bindings/stepper/zephyr,stepper-motion-control.yaml b/dts/bindings/stepper/zephyr,stepper-motion-control.yaml new file mode 100644 index 000000000000..85146f4e2eb0 --- /dev/null +++ b/dts/bindings/stepper/zephyr,stepper-motion-control.yaml @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Jilay Sandeep Pandya +# SPDX-License-Identifier: Apache-2.0 + +description: | + CPU based Stepper Motion Controller for stepper motor drivers + This binding is used to configure the stepper controller in Zephyr. + It is used to control the stepper motor driver. + Example: + stepper_motion_control: stepper_motion_control { + compatible = "zephyr,stepper-motion-control"; + stepper = <&gpio_stepper>; + }; + +compatible: "zephyr,stepper-motion-control" + +properties: + counter: + type: phandle + description: Counter used for generating step-accurate pulse signals. + + stepper: + type: phandle + required: true + description: | + The stepper motor driver to be controlled by the stepper motion controller. + This should be a reference to a stepper motor driver node in the device tree. diff --git a/include/zephyr/drivers/stepper.h b/include/zephyr/drivers/stepper.h index 64cf23c94e91..f9cedaaed548 100644 --- a/include/zephyr/drivers/stepper.h +++ b/include/zephyr/drivers/stepper.h @@ -102,8 +102,6 @@ enum stepper_event { STEPPER_EVENT_RIGHT_END_STOP_DETECTED = 3, /** Stepper has stopped */ STEPPER_EVENT_STOPPED = 4, - /** Fault with the stepper controller detected */ - STEPPER_EVENT_FAULT_DETECTED = 5, }; /** @@ -142,6 +140,7 @@ typedef int (*stepper_set_micro_step_res_t)(const struct device *dev, */ typedef int (*stepper_get_micro_step_res_t)(const struct device *dev, enum stepper_micro_step_resolution *resolution); + /** * @brief Set the reference position of the stepper * @@ -169,6 +168,7 @@ typedef void (*stepper_event_callback_t)(const struct device *dev, const enum st */ typedef int (*stepper_set_event_callback_t)(const struct device *dev, stepper_event_callback_t callback, void *user_data); + /** * @brief Set the time interval between steps in nanoseconds. * @@ -545,6 +545,263 @@ static inline int z_impl_stepper_is_moving(const struct device *dev, bool *is_mo return api->is_moving(dev, is_moving); } +/** + * @} + */ + +/** + * @brief Stepper-Drv Driver Interface + * @defgroup stepper_drv_interface Stepper Drv Driver Interface + * @since 4.3 + * @version 0.1.0 + * @ingroup io_interfaces + * @{ + */ + +/** + * @cond INTERNAL_HIDDEN + * + * Stepper Drv driver API definition and system call entry points. + * + */ + +/** + * @brief Enable the stepper driver + * + * @see stepper_drv_enable() for details. + */ +typedef int (*stepper_drv_enable_t)(const struct device *dev); + +/** + * @brief Disable the stepper driver + * + * @see stepper_drv_disable() for details. + */ +typedef int (*stepper_drv_disable_t)(const struct device *dev); + +/** + * @brief Set the stepper direction + * + * @see stepper_drv_set_direction() for details. + */ +typedef int (*stepper_drv_direction_t)(const struct device *dev, + const enum stepper_direction direction); + +/** + * @brief Do a step + * + * @see stepper_drv_step() for details. + */ +typedef int (*stepper_drv_step_t)(const struct device *dev); + +/** + * @brief Set the stepper micro-step resolution + * + * @see stepper_drv_set_micro_step_res() for details. + */ +typedef int (*stepper_drv_set_micro_step_res_t)( + const struct device *dev, const enum stepper_micro_step_resolution resolution); + +/** + * @brief Get the stepper micro-step resolution + * + * @see stepper_drv_get_micro_step_res() for details. + */ +typedef int (*stepper_drv_get_micro_step_res_t)(const struct device *dev, + enum stepper_micro_step_resolution *resolution); + +/** + * @brief Callback function for stepper fault events + */ +typedef int (*stepper_drv_fault_cb_t)(const struct device *dev, void *user_data); + +/** + * @brief Set the callback function to be called when a stepper driver fault occurs + * + * @see stepper_drv_set_fault_callback() for details. + */ +typedef int (*stepper_drv_set_fault_callback_t)(const struct device *dev, + stepper_drv_fault_cb_t callback, void *user_data); + +/** + * @brief Stepper DRV Driver API + */ +__subsystem struct stepper_drv_driver_api { + stepper_drv_enable_t enable; + stepper_drv_disable_t disable; + stepper_drv_direction_t set_direction; + stepper_drv_step_t step; + stepper_drv_set_micro_step_res_t set_micro_step_res; + stepper_drv_get_micro_step_res_t get_micro_step_res; + stepper_drv_set_fault_callback_t set_fault_cb; +}; + +/** + * @endcond + */ + +/** + * @brief Enable stepper driver + * + * @details Enabling the driver shall switch on the power stage and energize the coils. + * + * @param dev pointer to the stepper_drv driver instance + * + * @retval -EIO Error during Enabling + * @retval 0 Success + */ +__syscall int stepper_drv_enable(const struct device *dev); + +static inline int z_impl_stepper_drv_enable(const struct device *dev) +{ + const struct stepper_drv_driver_api *api = (const struct stepper_drv_driver_api *)dev->api; + + return api->enable(dev); +} + +/** + * @brief Disable stepper driver + * + * @details Disabling the driver shall switch off the power stage and de-energize the coils. + * + * @param dev pointer to the stepper_drv driver instance + * + * @retval -ENOTSUP Disabling of driver is not supported. + * @retval -EIO Error during Disabling + * @retval 0 Success + */ +__syscall int stepper_drv_disable(const struct device *dev); + +static inline int z_impl_stepper_drv_disable(const struct device *dev) +{ + const struct stepper_drv_driver_api *api = (const struct stepper_drv_driver_api *)dev->api; + + return api->disable(dev); +} + +/** + * @brief Do a step. + * @details This function will cause the stepper to do one micro-step. + * This function is typically used in stepper_drv stepper drivers where + * an external stepper motion controller is used to control the stepper. + * This function will not increment/decrement any position related data. Doing so + * is responsibility of the caller (e.g. stepper motion controller). + * + * @param dev pointer to the stepper_drv driver instance + * + * @retval -EIO General input / output error + * @retval 0 Success + */ +__syscall int stepper_drv_step(const struct device *dev); + +static inline int z_impl_stepper_drv_step(const struct device *dev) +{ + const struct stepper_drv_driver_api *api = (const struct stepper_drv_driver_api *)dev->api; + + return api->step(dev); +} + +/** + * @brief Set the stepper direction + * @details This function sets the direction of the stepper motor. + * + * @param dev pointer to the stepper_drv driver instance + * @param direction The direction to set + * + * @retval -EINVAL If the requested direction is invalid + * @retval -EIO General input / output error + * @retval 0 Success + */ +__syscall int stepper_drv_set_direction(const struct device *dev, + const enum stepper_direction direction); + +static inline int z_impl_stepper_drv_set_direction(const struct device *dev, + const enum stepper_direction direction) +{ + const struct stepper_drv_driver_api *api = (const struct stepper_drv_driver_api *)dev->api; + + if ((direction != STEPPER_DIRECTION_POSITIVE) && + (direction != STEPPER_DIRECTION_NEGATIVE)) { + return -EINVAL; + } + + return api->set_direction(dev, direction); +} +/** + * @brief Set the micro-step resolution in stepper driver + * + * @param dev pointer to the step dir driver instance + * @param resolution micro-step resolution + * + * @retval -EIO General input / output error + * @retval -ENOSYS If not implemented by device driver + * @retval -EINVAL If the requested resolution is invalid + * @retval -ENOTSUP If the requested resolution is not supported + * @retval 0 Success + */ +__syscall int stepper_drv_set_micro_stepper_res(const struct device *dev, + enum stepper_micro_step_resolution resolution); + +static inline int +z_impl_stepper_drv_set_micro_stepper_res(const struct device *dev, + enum stepper_micro_step_resolution resolution) +{ + const struct stepper_drv_driver_api *api = (const struct stepper_drv_driver_api *)dev->api; + + if (!VALID_MICRO_STEP_RES(resolution)) { + return -EINVAL; + } + return api->set_micro_step_res(dev, resolution); +} + +/** + * @brief Get the micro-step resolution in stepper driver + * + * @param dev pointer to the stepper_drv driver instance + * @param resolution micro-step resolution + * + * @retval -EIO General input / output error + * @retval -ENOSYS If not implemented by device driver + * @retval 0 Success + */ +__syscall int stepper_drv_get_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution *resolution); + +static inline int +z_impl_stepper_drv_get_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution *resolution) +{ + const struct stepper_drv_driver_api *api = (const struct stepper_drv_driver_api *)dev->api; + + return api->get_micro_step_res(dev, resolution); +} + +/** + * @brief Set the callback function to be called when a stepper fault occurs + * + * @param dev pointer to the stepper_drv driver instance + * @param callback Callback function to be called when a stepper fault occurs + * passing NULL will disable the callback + * @param user_data User data to be passed to the callback function + * + * @retval -ENOSYS If not implemented by device driver + * @retval 0 Success + */ +__syscall int stepper_drv_set_fault_cb(const struct device *dev, stepper_drv_fault_cb_t callback, + void *user_data); + +static inline int z_impl_stepper_drv_set_fault_cb(const struct device *dev, + stepper_drv_fault_cb_t callback, void *user_data) +{ + const struct stepper_drv_driver_api *api = (const struct stepper_drv_driver_api *)dev->api; + + if (api->set_fault_cb == NULL) { + return -ENOSYS; + } + + return api->set_fault_cb(dev, callback, user_data); +} + /** * @} */ diff --git a/samples/drivers/stepper/generic/boards/nucleo_g071rb.overlay b/samples/drivers/stepper/generic/boards/nucleo_g071rb.overlay index e392a028cb32..fafb14e4efcc 100644 --- a/samples/drivers/stepper/generic/boards/nucleo_g071rb.overlay +++ b/samples/drivers/stepper/generic/boards/nucleo_g071rb.overlay @@ -1,12 +1,20 @@ / { aliases { - stepper = &gpio_stepper; + stepper = &h_bridge_stepper; + stepper-motion-control = &stepper_motion_control; + }; +}; + +&timers7 { + st,prescaler = <79>; + counter: counter { + status = "okay"; }; }; / { - gpio_stepper: gpio_stepper { - compatible = "zephyr,gpio-stepper"; + h_bridge_stepper: stepper { + compatible = "zephyr,h-bridge-stepper"; status = "okay"; micro-step-res = <2>; gpios = <&gpioa 9 GPIO_ACTIVE_HIGH>, /* D8 */ @@ -14,4 +22,11 @@ <&gpiob 0 GPIO_ACTIVE_HIGH>, /* D10 */ <&gpioa 7 GPIO_ACTIVE_HIGH>; /* D11 */ }; + + stepper_motion_control: stepper_motion_control { + compatible = "zephyr,stepper-motion-control"; + status = "okay"; + counter = <&counter>; + stepper = <&h_bridge_stepper>; + }; }; diff --git a/samples/drivers/stepper/generic/prj.conf b/samples/drivers/stepper/generic/prj.conf index 7b579deb99fb..b7d159296509 100644 --- a/samples/drivers/stepper/generic/prj.conf +++ b/samples/drivers/stepper/generic/prj.conf @@ -1,3 +1,4 @@ +CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS=y CONFIG_STEPPER=y CONFIG_LOG=y CONFIG_INPUT=y diff --git a/samples/drivers/stepper/generic/src/main.c b/samples/drivers/stepper/generic/src/main.c index f1323e50850a..c81798fa8224 100644 --- a/samples/drivers/stepper/generic/src/main.c +++ b/samples/drivers/stepper/generic/src/main.c @@ -12,7 +12,8 @@ #include LOG_MODULE_REGISTER(stepper, CONFIG_STEPPER_LOG_LEVEL); -static const struct device *stepper = DEVICE_DT_GET(DT_ALIAS(stepper)); +static const struct device *stepper_motion_controller = + DEVICE_DT_GET(DT_ALIAS(stepper_motion_control)); enum stepper_mode { STEPPER_MODE_ENABLE, @@ -65,47 +66,53 @@ INPUT_CALLBACK_DEFINE(NULL, button_pressed, NULL); int main(void) { LOG_INF("Starting generic stepper sample\n"); - if (!device_is_ready(stepper)) { - LOG_ERR("Device %s is not ready\n", stepper->name); + if (!device_is_ready(stepper_motion_controller)) { + LOG_ERR("Device %s is not ready\n", stepper_motion_controller->name); return -ENODEV; } - LOG_DBG("stepper is %p, name is %s\n", stepper, stepper->name); + LOG_DBG("stepper is %p, name is %s\n", stepper_motion_controller, + stepper_motion_controller->name); - stepper_set_event_callback(stepper, stepper_callback, NULL); - stepper_set_reference_position(stepper, 0); - stepper_set_microstep_interval(stepper, CONFIG_STEP_INTERVAL_NS); + if (!device_is_ready(stepper_motion_controller)) { + LOG_ERR("Device %s is not ready\n", stepper_motion_controller->name); + return -ENODEV; + } + + stepper_set_event_callback(stepper_motion_controller, stepper_callback, NULL); + stepper_set_reference_position(stepper_motion_controller, 0); + stepper_set_microstep_interval(stepper_motion_controller, CONFIG_STEP_INTERVAL_NS); for (;;) { k_sem_take(&stepper_generic_sem, K_FOREVER); switch (atomic_get(&stepper_mode)) { case STEPPER_MODE_ENABLE: - stepper_enable(stepper); + stepper_enable(stepper_motion_controller); LOG_INF("mode: enable\n"); break; case STEPPER_MODE_STOP: - stepper_stop(stepper); + stepper_stop(stepper_motion_controller); LOG_INF("mode: stop\n"); break; case STEPPER_MODE_ROTATE_CW: - stepper_run(stepper, STEPPER_DIRECTION_POSITIVE); + stepper_run(stepper_motion_controller, STEPPER_DIRECTION_POSITIVE); LOG_INF("mode: rotate cw\n"); break; case STEPPER_MODE_ROTATE_CCW: - stepper_run(stepper, STEPPER_DIRECTION_NEGATIVE); + stepper_run(stepper_motion_controller, STEPPER_DIRECTION_NEGATIVE); LOG_INF("mode: rotate ccw\n"); break; case STEPPER_MODE_PING_PONG_RELATIVE: ping_pong_target_position *= -1; - stepper_move_by(stepper, ping_pong_target_position); + stepper_move_by(stepper_motion_controller, ping_pong_target_position); LOG_INF("mode: ping pong relative\n"); break; case STEPPER_MODE_PING_PONG_ABSOLUTE: ping_pong_target_position *= -1; - stepper_move_to(stepper, ping_pong_target_position); + stepper_move_to(stepper_motion_controller, ping_pong_target_position); LOG_INF("mode: ping pong absolute\n"); break; case STEPPER_MODE_DISABLE: - stepper_disable(stepper); + stepper_disable(stepper_motion_controller); LOG_INF("mode: disable\n"); break; } @@ -118,7 +125,7 @@ static void monitor_thread(void) for (;;) { int32_t actual_position; - stepper_get_actual_position(stepper, &actual_position); + stepper_get_actual_position(stepper_motion_controller, &actual_position); LOG_DBG("Actual position: %d\n", actual_position); k_sleep(K_MSEC(CONFIG_MONITOR_THREAD_TIMEOUT_MS)); } diff --git a/tests/drivers/build_all/stepper/app.overlay b/tests/drivers/build_all/stepper/app.overlay index 177d15926bcd..33dfe04d09bc 100644 --- a/tests/drivers/build_all/stepper/app.overlay +++ b/tests/drivers/build_all/stepper/app.overlay @@ -39,5 +39,18 @@ #include "uart.dtsi" }; + + zephyr_stepper_motion_control_counter: zephyr_stepper_motion_control_counter { + compatible = "zephyr,stepper-motion-control"; + status = "okay"; + counter = <&counter0>; + stepper = <&zephyr_h_bridge_stepper>; + }; + + zephyr_stepper_motion_control_workq: zephyr_stepper_motion_control_workq { + compatible = "zephyr,stepper-motion-control"; + status = "okay"; + stepper = <&zephyr_h_bridge_stepper>; + }; }; }; diff --git a/tests/drivers/build_all/stepper/gpio.dtsi b/tests/drivers/build_all/stepper/gpio.dtsi index b5151a3149cc..716a7a495ea2 100644 --- a/tests/drivers/build_all/stepper/gpio.dtsi +++ b/tests/drivers/build_all/stepper/gpio.dtsi @@ -16,7 +16,6 @@ adi_tmc2209: adi_tmc2209 { en-gpios = <&test_gpio 0 0>; step-gpios = <&test_gpio 0 0>; dir-gpios = <&test_gpio 0 0>; - counter = <&counter0>; }; allegro_a4979: allegro_a4979 { @@ -29,7 +28,6 @@ allegro_a4979: allegro_a4979 { en-gpios = <&test_gpio 0 0>; m0-gpios = <&test_gpio 0 0>; m1-gpios = <&test_gpio 0 0>; - counter = <&counter0>; }; ti_drv84xx: ti_drv84xx { @@ -42,11 +40,10 @@ ti_drv84xx: ti_drv84xx { en-gpios = <&test_gpio 0 0>; m0-gpios = <&test_gpio 0 0>; m1-gpios = <&test_gpio 0 0>; - counter = <&counter0>; }; -zephyr_gpio_stepper: zephyr_gpio_stepper { - compatible = "zephyr,gpio-stepper"; +zephyr_h_bridge_stepper: zephyr_h_bridge_stepper { + compatible = "zephyr,h-bridge-stepper"; status = "okay"; micro-step-res = <1>; gpios = <&test_gpio 0 0>, diff --git a/tests/drivers/stepper/drv84xx/api/boards/native_sim.overlay b/tests/drivers/stepper/drv84xx/api/boards/native_sim.overlay index ed869356721f..41aea39a2358 100644 --- a/tests/drivers/stepper/drv84xx/api/boards/native_sim.overlay +++ b/tests/drivers/stepper/drv84xx/api/boards/native_sim.overlay @@ -8,6 +8,7 @@ / { aliases { stepper = &drv8424; + stepper-motion-control = &stepper_motion_control; }; }; @@ -22,13 +23,19 @@ en-gpios = <&gpio2 1 0>; /* 5 */ m0-gpios = <&gpio3 0 0>; m1-gpios = <&gpio3 1 0>; - counter = <&counter0>; #address-cells = <1>; #size-cells = <0>; #stepper-motor-cells = <0>; }; + stepper_motion_control: stepper_motion_control { + compatible = "zephyr,stepper-motion-control"; + status = "okay"; + counter = <&counter0>; + stepper = <&drv8424>; + }; + gpio1: gpio1 { compatible = "zephyr,gpio-emul"; #gpio-cells = <0x2>; diff --git a/tests/drivers/stepper/drv84xx/api/prj.conf b/tests/drivers/stepper/drv84xx/api/prj.conf index e05e8cb5a880..b44dd95fdfd8 100644 --- a/tests/drivers/stepper/drv84xx/api/prj.conf +++ b/tests/drivers/stepper/drv84xx/api/prj.conf @@ -1,6 +1,7 @@ # Copyright (c) 2024 Navimatix GmbH # SPDX-License-Identifier: Apache-2.0 +CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS=y CONFIG_ZTEST=y CONFIG_TEST=y CONFIG_TEST_USERSPACE=y diff --git a/tests/drivers/stepper/drv84xx/api/src/main.c b/tests/drivers/stepper/drv84xx/api/src/main.c index 04fe097730db..d8f0aa69028e 100644 --- a/tests/drivers/stepper/drv84xx/api/src/main.c +++ b/tests/drivers/stepper/drv84xx/api/src/main.c @@ -44,7 +44,7 @@ static void drv84xx_api_print_event_callback(const struct device *dev, enum step static void *drv84xx_api_setup(void) { static struct drv84xx_api_fixture fixture = { - .dev = DEVICE_DT_GET(DT_ALIAS(stepper)), + .dev = DEVICE_DT_GET(DT_ALIAS(stepper_motion_control)), .callback = drv84xx_api_print_event_callback, }; diff --git a/tests/drivers/stepper/drv84xx/emul/boards/native_sim.overlay b/tests/drivers/stepper/drv84xx/emul/boards/native_sim.overlay index 0ad772892896..2a91ca474a3d 100644 --- a/tests/drivers/stepper/drv84xx/emul/boards/native_sim.overlay +++ b/tests/drivers/stepper/drv84xx/emul/boards/native_sim.overlay @@ -17,7 +17,6 @@ en-gpios = <&gpio2 1 0>; /* 5 */ m0-gpios = <&gpio3 0 0>; m1-gpios = <&gpio3 1 0>; - counter = <&counter0>; #address-cells = <1>; #size-cells = <0>; diff --git a/tests/drivers/stepper/drv84xx/emul/src/main.c b/tests/drivers/stepper/drv84xx/emul/src/main.c index c730bc457ce9..3fbb23b36746 100644 --- a/tests/drivers/stepper/drv84xx/emul/src/main.c +++ b/tests/drivers/stepper/drv84xx/emul/src/main.c @@ -33,20 +33,19 @@ static void *drv84xx_emul_setup(void) static void drv84xx_emul_before(void *f) { struct drv84xx_emul_fixture *fixture = f; - (void)stepper_set_reference_position(fixture->dev, 0); - (void)stepper_set_micro_step_res(fixture->dev, 1); + (void)stepper_drv_set_micro_stepper_res(fixture->dev, 1); } static void drv84xx_emul_after(void *f) { struct drv84xx_emul_fixture *fixture = f; - (void)stepper_disable(fixture->dev); + (void)stepper_drv_disable(fixture->dev); } ZTEST_F(drv84xx_emul, test_enable_on_gpio_pins) { int value = 0; - (void)stepper_enable(fixture->dev); + (void)stepper_drv_enable(fixture->dev); /* As sleep and enable pins are optional, check if they exist*/ if (en_pin.port != NULL) { value = gpio_emul_output_get(en_pin.port, en_pin.pin); @@ -64,8 +63,8 @@ ZTEST_F(drv84xx_emul, test_enable_off_gpio_pins) /* Enable first to ensure that disable works correctly and the check is not against values * from initialisation or from previous tests */ - (void)stepper_enable(fixture->dev); - (void)stepper_disable(fixture->dev); + (void)stepper_drv_enable(fixture->dev); + (void)stepper_drv_disable(fixture->dev); /* As sleep and enable pins are optional, check if they exist*/ if (en_pin.port != NULL) { value = gpio_emul_output_get(en_pin.port, en_pin.pin); diff --git a/tests/drivers/stepper/stepper_api/CMakeLists.txt b/tests/drivers/stepper/stepper_api/CMakeLists.txt index a1ebdab059bd..e1a62a23c19b 100644 --- a/tests/drivers/stepper/stepper_api/CMakeLists.txt +++ b/tests/drivers/stepper/stepper_api/CMakeLists.txt @@ -3,6 +3,6 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(stepper_api) +project(zephyr_stepper_motion_control) target_sources(app PRIVATE src/main.c) diff --git a/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209.overlay b/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209.overlay index caf4f3c5b3a7..b1aad6a6d407 100644 --- a/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209.overlay +++ b/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209.overlay @@ -7,7 +7,8 @@ / { aliases { - stepper = &adi_tmc2209; + stepper = &adi_tmc2209; + stepper-motion-control = &zephyr_stepper_motion_control; }; }; @@ -20,6 +21,12 @@ step-gpios = <&gpio1 1 0>; en-gpios = <&gpio2 1 0>; msx-gpios = <&gpio3 0 0>, <&gpio4 1 0>; + }; + + zephyr_stepper_motion_control: zephyr_stepper_motion_control { + compatible = "zephyr,stepper-motion-control"; + status = "okay"; counter = <&counter0>; + stepper = <&adi_tmc2209>; }; }; diff --git a/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209_work_q.overlay b/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209_work_q.overlay index a7756000d955..5b0b71ae6762 100644 --- a/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209_work_q.overlay +++ b/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209_work_q.overlay @@ -7,7 +7,8 @@ / { aliases { - stepper = &adi_tmc2209; + stepper = &adi_tmc2209; + stepper-motion-control = &zephyr_stepper_motion_control; }; }; @@ -21,4 +22,10 @@ en-gpios = <&gpio2 1 0>; msx-gpios = <&gpio3 0 0>, <&gpio4 1 0>; }; + + zephyr_stepper_motion_control: zephyr_stepper_motion_control { + compatible = "zephyr,stepper-motion-control"; + status = "okay"; + stepper = <&adi_tmc2209>; + }; }; diff --git a/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979.overlay b/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979.overlay index 3d1c69339dfa..2652c194f213 100644 --- a/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979.overlay +++ b/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979.overlay @@ -8,6 +8,7 @@ / { aliases { stepper = &allegro_a4979; + stepper-motion-control = &zephyr_stepper_motion_control; }; }; @@ -22,6 +23,12 @@ en-gpios = <&gpio2 1 0>; m0-gpios = <&gpio3 0 0>; m1-gpios = <&gpio3 1 0>; + }; + + zephyr_stepper_motion_control: zephyr_stepper_motion_control { + compatible = "zephyr,stepper-motion-control"; + status = "okay"; counter = <&counter0>; + stepper = <&allegro_a4979>; }; }; diff --git a/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979_work_q.overlay b/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979_work_q.overlay index fe4e02eb1f79..b2e477fbed3b 100644 --- a/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979_work_q.overlay +++ b/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979_work_q.overlay @@ -8,6 +8,7 @@ / { aliases { stepper = &allegro_a4979; + stepper-motion-control = &zephyr_stepper_motion_control; }; }; @@ -23,4 +24,10 @@ m0-gpios = <&gpio3 0 0>; m1-gpios = <&gpio3 1 0>; }; + + zephyr_stepper_motion_control: zephyr_stepper_motion_control { + compatible = "zephyr,stepper-motion-control"; + status = "okay"; + stepper = <&allegro_a4979>; + }; }; diff --git a/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx.overlay b/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx.overlay index 0763a19e393b..90b9fc584ece 100644 --- a/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx.overlay +++ b/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx.overlay @@ -8,6 +8,7 @@ / { aliases { stepper = &ti_drv84xx; + stepper-motion-control = &zephyr_stepper_motion_control; }; }; @@ -22,6 +23,12 @@ en-gpios = <&gpio2 1 0>; m0-gpios = <&gpio3 0 0>; m1-gpios = <&gpio3 1 0>; + }; + + zephyr_stepper_motion_control: zephyr_stepper_motion_control { + compatible = "zephyr,stepper-motion-control"; + status = "okay"; counter = <&counter0>; + stepper = <&ti_drv84xx>; }; }; diff --git a/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx_work_q.overlay b/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx_work_q.overlay index 2ca7a34d3888..55740f8576bd 100644 --- a/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx_work_q.overlay +++ b/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx_work_q.overlay @@ -8,6 +8,7 @@ / { aliases { stepper = &ti_drv84xx; + stepper-motion-control = &zephyr_stepper_motion_control; }; }; @@ -23,4 +24,10 @@ m0-gpios = <&gpio3 0 0>; m1-gpios = <&gpio3 1 0>; }; + + zephyr_stepper_motion_control: zephyr_stepper_motion_control { + compatible = "zephyr,stepper-motion-control"; + status = "okay"; + stepper = <&ti_drv84xx>; + }; }; diff --git a/tests/drivers/stepper/stepper_api/boards/native_sim_zephyr_gpio_stepper.overlay b/tests/drivers/stepper/stepper_api/boards/native_sim_zephyr_gpio_stepper.overlay index 3df8e647466e..935de0e7a1d2 100644 --- a/tests/drivers/stepper/stepper_api/boards/native_sim_zephyr_gpio_stepper.overlay +++ b/tests/drivers/stepper/stepper_api/boards/native_sim_zephyr_gpio_stepper.overlay @@ -7,13 +7,14 @@ / { aliases { - stepper = &zephyr_gpio_stepper; + stepper = &zephyr_h_bridge_stepper; + stepper-motion-control = &zephyr_stepper_motion_control; }; }; / { - zephyr_gpio_stepper: zephyr_gpio_stepper { - compatible = "zephyr,gpio-stepper"; + zephyr_h_bridge_stepper: zephyr_h_bridge_stepper { + compatible = "zephyr,h-bridge-stepper"; status = "okay"; micro-step-res = <1>; gpios = <&gpio1 0 0>, @@ -21,4 +22,11 @@ <&gpio3 0 0>, <&gpio4 0 0>; }; + + zephyr_stepper_motion_control: zephyr_stepper_motion_control { + compatible = "zephyr,stepper-motion-control"; + status = "okay"; + counter = <&counter0>; + stepper = <&zephyr_h_bridge_stepper>; + }; }; diff --git a/tests/drivers/stepper/stepper_api/boards/qemu_x86_64_zephyr_gpio_stepper.overlay b/tests/drivers/stepper/stepper_api/boards/qemu_x86_64_zephyr_gpio_stepper.overlay index bfc3161e3b17..5de7f9cf7048 100644 --- a/tests/drivers/stepper/stepper_api/boards/qemu_x86_64_zephyr_gpio_stepper.overlay +++ b/tests/drivers/stepper/stepper_api/boards/qemu_x86_64_zephyr_gpio_stepper.overlay @@ -7,7 +7,8 @@ / { aliases { - stepper = &zephyr_gpio_stepper; + stepper = &zephyr_h_bridge_stepper; + stepper-motion-control = &zephyr_stepper_motion_control; }; }; @@ -42,13 +43,19 @@ }; / { - zephyr_gpio_stepper: zephyr_gpio_stepper { - compatible = "zephyr,gpio-stepper"; + zephyr_h_bridge_stepper: zephyr_h_bridge_stepper { + compatible = "zephyr,h-bridge-stepper"; status = "okay"; micro-step-res = <2>; gpios = <&gpio1 0 0>, - <&gpio2 0 0>, - <&gpio3 0 0>, - <&gpio4 0 0>; + <&gpio2 0 0>, + <&gpio3 0 0>, + <&gpio4 0 0>; + }; + + zephyr_stepper_motion_control: zephyr_stepper_motion_control { + compatible = "zephyr,stepper-motion-control"; + status = "okay"; + stepper = <&zephyr_h_bridge_stepper>; }; }; diff --git a/tests/drivers/stepper/stepper_api/src/main.c b/tests/drivers/stepper/stepper_api/src/main.c index 9a2a1179b50c..e16155e16209 100644 --- a/tests/drivers/stepper/stepper_api/src/main.c +++ b/tests/drivers/stepper/stepper_api/src/main.c @@ -63,7 +63,7 @@ static void stepper_print_event_callback(const struct device *dev, enum stepper_ static void *stepper_setup(void) { static struct stepper_fixture fixture = { - .dev = DEVICE_DT_GET(DT_ALIAS(stepper)), + .dev = DEVICE_DT_GET(DT_ALIAS(stepper_motion_control)), .callback = stepper_print_event_callback, }; @@ -179,6 +179,22 @@ ZTEST_F(stepper, test_move_by_negative_step_count) zassert_equal(steps, -20u, "Target position should be %d but is %d", -20u, steps); } +/* move_by(dev, 0) shall stop the stepper and raise STEPPER_EVENT_STEPS_COMPLETED */ +ZTEST_F(stepper, test_move_by_zero_steps) +{ + bool is_moving; + + (void)stepper_set_microstep_interval(fixture->dev, 100 * USEC_PER_SEC); + (void)stepper_set_event_callback(fixture->dev, fixture->callback, (void *)fixture->dev); + (void)stepper_move_by(fixture->dev, 0); + + POLL_AND_CHECK_SIGNAL(stepper_signal, stepper_event, STEPPER_EVENT_STEPS_COMPLETED, + K_MSEC(100)); + + stepper_is_moving(fixture->dev, &is_moving); + zassert_equal(is_moving, false, "Stepper is still moving"); +} + ZTEST_F(stepper, test_stop) { (void)stepper_set_event_callback(fixture->dev, fixture->callback, (void *)fixture->dev); diff --git a/tests/drivers/stepper/stepper_api/testcase.yaml b/tests/drivers/stepper/stepper_api/testcase.yaml index bf07964f0743..08365a9d95ba 100644 --- a/tests/drivers/stepper/stepper_api/testcase.yaml +++ b/tests/drivers/stepper/stepper_api/testcase.yaml @@ -13,7 +13,7 @@ tests: extra_configs: - CONFIG_GPIO=y - CONFIG_COUNTER=y - - CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS=y + - CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS=y platform_allow: - native_sim/native/64 drivers.stepper.stepper_api.adi_tmc2209_work_q: @@ -21,7 +21,7 @@ tests: - platform:native_sim/native/64:DTC_OVERLAY_FILE="boards/native_sim_adi_tmc2209_work_q.overlay" extra_configs: - CONFIG_GPIO=y - - CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS=y + - CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS=y - CONFIG_STEPPER_TEST_TIMING_TIMEOUT_TOLERANCE_PCT=30 platform_allow: - native_sim/native/64 @@ -31,7 +31,7 @@ tests: extra_configs: - CONFIG_GPIO=y - CONFIG_COUNTER=y - - CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS=y + - CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS=y platform_allow: - native_sim/native/64 drivers.stepper.stepper_api.allegro_a4979_work_q: @@ -39,7 +39,7 @@ tests: - platform:native_sim/native/64:DTC_OVERLAY_FILE="boards/native_sim_allegro_a4979_work_q.overlay" extra_configs: - CONFIG_GPIO=y - - CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS=y + - CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS=y - CONFIG_STEPPER_TEST_TIMING_TIMEOUT_TOLERANCE_PCT=30 platform_allow: - native_sim/native/64 @@ -49,7 +49,7 @@ tests: extra_configs: - CONFIG_GPIO=y - CONFIG_COUNTER=y - - CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS=y + - CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS=y platform_allow: - native_sim/native/64 drivers.stepper.stepper_api.ti_drv84xx_work_q: @@ -57,7 +57,7 @@ tests: - platform:native_sim/native/64:DTC_OVERLAY_FILE="boards/native_sim_ti_drv84xx_work_q.overlay" extra_configs: - CONFIG_GPIO=y - - CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS=y + - CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL_GENERATE_ISR_SAFE_EVENTS=y - CONFIG_STEPPER_TEST_TIMING_TIMEOUT_TOLERANCE_PCT=30 platform_allow: - native_sim/native/64 From 32ed542f21599962d289428ab1bbc47e6ca26f54 Mon Sep 17 00:00:00 2001 From: Jilay Pandya Date: Tue, 24 Jun 2025 19:50:36 +0200 Subject: [PATCH 2/3] drivers: stepper: deprecate stepper_drv functions from stepper_api - introduce stepper_index - Drop stepper_drv functions from stepper_api - Refactor Stepper Motion Controller - Refactor Shell Signed-off-by: Jilay Pandya --- drivers/stepper/CMakeLists.txt | 3 +- drivers/stepper/Kconfig.fake | 7 + .../adi_tmc/Kconfig.tmc_rampgen_template | 1 - drivers/stepper/adi_tmc/tmc50xx.c | 262 +++++++++------- drivers/stepper/adi_tmc/tmc51xx/tmc51xx.c | 265 ++++++++++------ drivers/stepper/adi_tmc/tmc51xx/tmc51xx.h | 31 +- drivers/stepper/fake_stepper_controller.c | 104 +++---- drivers/stepper/fake_stepper_drv.c | 92 ++++++ drivers/stepper/stepper_shell.c | 96 +++--- .../zephyr_stepper_motion_controller.c | 84 +++-- .../stepper/adi/adi,tmc51xx-base.yaml | 56 ++-- .../zephyr,fake-stepper-controller.yaml | 7 + dts/bindings/stepper/zephyr,fake-stepper.yaml | 3 +- include/zephyr/drivers/stepper.h | 286 +++++++----------- include/zephyr/drivers/stepper/stepper_fake.h | 26 +- .../zephyr/drivers/stepper/stepper_trinamic.h | 17 +- samples/drivers/stepper/generic/src/main.c | 36 ++- .../tmc50xx/boards/nucleo_g071rb.overlay | 1 + samples/drivers/stepper/tmc50xx/src/main.c | 39 ++- tests/drivers/build_all/stepper/app.overlay | 1 - tests/drivers/build_all/stepper/spi.dtsi | 113 +++---- tests/drivers/build_all/stepper/uart.dtsi | 54 ++-- tests/drivers/stepper/drv84xx/api/Kconfig | 6 + tests/drivers/stepper/drv84xx/api/src/main.c | 138 ++++----- tests/drivers/stepper/drv84xx/emul/src/main.c | 2 +- tests/drivers/stepper/shell/CMakeLists.txt | 2 +- tests/drivers/stepper/shell/app.overlay | 5 + tests/drivers/stepper/shell/src/main.c | 84 +++-- tests/drivers/stepper/stepper_api/Kconfig | 6 + .../boards/native_sim_adi_tmc2209.overlay | 1 - .../native_sim_adi_tmc2209_work_q.overlay | 1 - .../boards/native_sim_allegro_a4979.overlay | 1 - .../native_sim_allegro_a4979_work_q.overlay | 1 - .../boards/native_sim_ti_drv84xx.overlay | 1 - .../native_sim_ti_drv84xx_work_q.overlay | 1 - tests/drivers/stepper/stepper_api/src/main.c | 75 ++--- 36 files changed, 1064 insertions(+), 844 deletions(-) create mode 100644 drivers/stepper/fake_stepper_drv.c create mode 100644 dts/bindings/stepper/zephyr,fake-stepper-controller.yaml diff --git a/drivers/stepper/CMakeLists.txt b/drivers/stepper/CMakeLists.txt index 954c34cd21ae..d56488585ab6 100644 --- a/drivers/stepper/CMakeLists.txt +++ b/drivers/stepper/CMakeLists.txt @@ -17,7 +17,8 @@ add_subdirectory_ifdef(CONFIG_STEP_DIR_STEPPER step_dir) zephyr_library() zephyr_library_property(ALLOW_EMPTY TRUE) -zephyr_library_sources_ifdef(CONFIG_FAKE_STEPPER fake_stepper_controller.c) +zephyr_library_sources_ifdef(CONFIG_FAKE_STEPPER fake_stepper_drv.c) +zephyr_library_sources_ifdef(CONFIG_FAKE_STEPPER_CONTROLLER fake_stepper_controller.c) zephyr_library_sources_ifdef(CONFIG_H_BRIDGE_STEPPER h_bridge_stepper_driver.c) zephyr_library_sources_ifdef(CONFIG_STEPPER_SHELL stepper_shell.c) zephyr_library_sources_ifdef(CONFIG_ZEPHYR_STEPPER_MOTION_CONTROL zephyr_stepper_motion_controller.c) diff --git a/drivers/stepper/Kconfig.fake b/drivers/stepper/Kconfig.fake index 942a556f1be2..9922c29a4cef 100644 --- a/drivers/stepper/Kconfig.fake +++ b/drivers/stepper/Kconfig.fake @@ -9,3 +9,10 @@ config FAKE_STEPPER depends on DT_HAS_ZEPHYR_FAKE_STEPPER_ENABLED help Enable support for the FFF-based fake stepper driver. + +config FAKE_STEPPER_CONTROLLER + bool "Fake stepper controller driver" + default y + depends on DT_HAS_ZEPHYR_FAKE_STEPPER_CONTROLLER_ENABLED + help + Enable support for the FFF-based fake stepper controller driver. diff --git a/drivers/stepper/adi_tmc/Kconfig.tmc_rampgen_template b/drivers/stepper/adi_tmc/Kconfig.tmc_rampgen_template index a357f8917d87..a3a79bd49067 100644 --- a/drivers/stepper/adi_tmc/Kconfig.tmc_rampgen_template +++ b/drivers/stepper/adi_tmc/Kconfig.tmc_rampgen_template @@ -3,7 +3,6 @@ config STEPPER_ADI_$(module)_RAMPSTAT_POLL_INTERVAL_IN_MSEC int "$(module-str) poll ramp status interval in ms" - depends on !$(dt_compat_any_has_prop,$(DT_COMPAT_ADI_$(module)),diag0-gpios) default 100 help When DIAG0 pin is not available, the driver automatically falls back to diff --git a/drivers/stepper/adi_tmc/tmc50xx.c b/drivers/stepper/adi_tmc/tmc50xx.c index 87e886251b77..d2dfc0e43065 100644 --- a/drivers/stepper/adi_tmc/tmc50xx.c +++ b/drivers/stepper/adi_tmc/tmc50xx.c @@ -25,6 +25,8 @@ struct tmc50xx_config { const uint32_t gconf; struct spi_dt_spec spi; const uint32_t clock_frequency; + const struct device **steppers; + const uint8_t num_steppers; }; struct tmc50xx_stepper_data { @@ -51,7 +53,8 @@ struct tmc50xx_stepper_config { #endif }; -static int read_actual_position(const struct tmc50xx_stepper_config *config, int32_t *position); +static int read_actual_position(const struct device *controller, const uint8_t stepper_index, + int32_t *position); static int tmc50xx_write(const struct device *dev, const uint8_t reg_addr, const uint32_t reg_val) { @@ -93,22 +96,33 @@ static int tmc50xx_read(const struct device *dev, const uint8_t reg_addr, uint32 return 0; } -static int tmc50xx_stepper_set_event_callback(const struct device *dev, - stepper_event_callback_t callback, void *user_data) +static void check_stepper_idx(const struct device *controller, const uint8_t stepper_index) { - struct tmc50xx_stepper_data *data = dev->data; + __ASSERT_NO_MSG(controller != NULL); + __maybe_unused const struct tmc50xx_config *tmc50xx_config = controller->config; + + CHECK_STEPPER_IDX(controller, stepper_index, tmc50xx_config->num_steppers); +} + +static int tmc50xx_set_event_callback(const struct device *controller, const uint8_t stepper_index, + stepper_event_callback_t callback, void *user_data) +{ + const struct tmc50xx_config *tmc50xx_config = controller->config; + check_stepper_idx(controller, stepper_index); + struct tmc50xx_stepper_data *data = tmc50xx_config->steppers[stepper_index]->data; data->callback = callback; data->event_cb_user_data = user_data; return 0; } -static int read_vactual(const struct tmc50xx_stepper_config *config, int32_t *actual_velocity) +static int read_vactual(const struct device *controller, const uint8_t stepper_index, + int32_t *actual_velocity) { __ASSERT(actual_velocity != NULL, "actual_velocity pointer must not be NULL"); int err; - err = tmc50xx_read(config->controller, TMC50XX_VACTUAL(config->index), actual_velocity); + err = tmc50xx_read(controller, TMC50XX_VACTUAL(stepper_index), actual_velocity); if (err) { LOG_ERR("Failed to read VACTUAL register"); return err; @@ -121,13 +135,16 @@ static int read_vactual(const struct tmc50xx_stepper_config *config, int32_t *ac return 0; } -static int stallguard_enable(const struct device *dev, const bool enable) +static int stallguard_enable(const struct device *controller, const uint8_t stepper_index, + const bool enable) { - const struct tmc50xx_stepper_config *config = dev->config; + const struct tmc50xx_config *tmc50xx_config = controller->config; + const struct tmc50xx_stepper_config *config = + tmc50xx_config->steppers[stepper_index]->config; uint32_t reg_value; int err; - err = tmc50xx_read(config->controller, TMC50XX_SWMODE(config->index), ®_value); + err = tmc50xx_read(controller, TMC50XX_SWMODE(stepper_index), ®_value); if (err) { LOG_ERR("Failed to read SWMODE register"); return -EIO; @@ -138,7 +155,7 @@ static int stallguard_enable(const struct device *dev, const bool enable) int32_t actual_velocity; - err = read_vactual(config, &actual_velocity); + err = read_vactual(controller, stepper_index, &actual_velocity); if (err) { return -EIO; } @@ -148,7 +165,7 @@ static int stallguard_enable(const struct device *dev, const bool enable) } else { reg_value &= ~TMC5XXX_SW_MODE_SG_STOP_ENABLE; } - err = tmc50xx_write(config->controller, TMC50XX_SWMODE(config->index), reg_value); + err = tmc50xx_write(controller, TMC50XX_SWMODE(stepper_index), reg_value); if (err) { LOG_ERR("Failed to write SWMODE register"); return -EIO; @@ -166,7 +183,7 @@ static void stallguard_work_handler(struct k_work *work) int err; const struct tmc50xx_stepper_config *stepper_config = stepper_data->stepper->config; - err = stallguard_enable(stepper_data->stepper, true); + err = stallguard_enable(stepper_config->controller, stepper_config->index, true); if (err == -EAGAIN) { k_work_reschedule(dwork, K_MSEC(stepper_config->sg_velocity_check_interval_ms)); } @@ -176,15 +193,17 @@ static void stallguard_work_handler(struct k_work *work) } } -static void execute_callback(const struct device *dev, const enum stepper_event event) +static void execute_callback(const struct device *controller, const uint8_t stepper_index, + const enum stepper_event event) { - struct tmc50xx_stepper_data *data = dev->data; + const struct tmc50xx_config *tmc50xx_config = controller->config; + struct tmc50xx_stepper_data *data = tmc50xx_config->steppers[stepper_index]->data; if (!data->callback) { LOG_WRN_ONCE("No callback registered"); return; } - data->callback(dev, event, data->event_cb_user_data); + data->callback(controller, stepper_index, event, data->event_cb_user_data); } #ifdef CONFIG_STEPPER_ADI_TMC50XX_RAMPSTAT_POLL_STALLGUARD_LOG @@ -204,8 +223,8 @@ static void log_stallguard(struct tmc50xx_stepper_data *stepper_data, const uint const uint8_t sg_result = FIELD_GET(TMC5XXX_DRV_STATUS_SG_RESULT_MASK, drv_status); const bool sg_status = FIELD_GET(TMC5XXX_DRV_STATUS_SG_STATUS_MASK, drv_status); - LOG_DBG("%s position: %d | sg result: %3d status: %d", - stepper_data->stepper->name, position, sg_result, sg_status); + LOG_DBG("%s position: %d | sg result: %3d status: %d", stepper_data->stepper->name, + position, sg_result, sg_status); } #endif @@ -213,7 +232,7 @@ static void log_stallguard(struct tmc50xx_stepper_data *stepper_data, const uint static void rampstat_work_reschedule(struct k_work_delayable *rampstat_callback_dwork) { k_work_reschedule(rampstat_callback_dwork, - K_MSEC(CONFIG_STEPPER_ADI_TMC50XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); + K_MSEC(CONFIG_STEPPER_ADI_TMC50XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); } static void rampstat_work_handler(struct k_work *work) @@ -265,13 +284,13 @@ static void rampstat_work_handler(struct k_work *work) case TMC5XXX_STOP_LEFT_EVENT: LOG_DBG("RAMPSTAT %s:Left end-stop detected", stepper_data->stepper->name); - execute_callback(stepper_data->stepper, + execute_callback(stepper_config->controller, stepper_config->index, STEPPER_EVENT_LEFT_END_STOP_DETECTED); break; case TMC5XXX_STOP_RIGHT_EVENT: LOG_DBG("RAMPSTAT %s:Right end-stop detected", stepper_data->stepper->name); - execute_callback(stepper_data->stepper, + execute_callback(stepper_config->controller, stepper_config->index, STEPPER_EVENT_RIGHT_END_STOP_DETECTED); break; @@ -279,13 +298,15 @@ static void rampstat_work_handler(struct k_work *work) case TMC5XXX_POS_REACHED: case TMC5XXX_POS_REACHED_AND_EVENT: LOG_DBG("RAMPSTAT %s:Position reached", stepper_data->stepper->name); - execute_callback(stepper_data->stepper, STEPPER_EVENT_STEPS_COMPLETED); + execute_callback(stepper_config->controller, stepper_config->index, + STEPPER_EVENT_STEPS_COMPLETED); break; case TMC5XXX_STOP_SG_EVENT: LOG_DBG("RAMPSTAT %s:Stall detected", stepper_data->stepper->name); - stallguard_enable(stepper_data->stepper, false); - execute_callback(stepper_data->stepper, STEPPER_EVENT_STALL_DETECTED); + stallguard_enable(stepper_config->controller, stepper_config->index, false); + execute_callback(stepper_config->controller, stepper_config->index, + STEPPER_EVENT_STALL_DETECTED); break; default: LOG_ERR("Illegal ramp stat bit field"); @@ -330,37 +351,42 @@ static int tmc50xx_stepper_disable(const struct device *dev) return tmc50xx_write(config->controller, TMC50XX_CHOPCONF(config->index), reg_value); } -static int tmc50xx_stepper_is_moving(const struct device *dev, bool *is_moving) +static int tmc50xx_stepper_is_moving(const struct device *controller, const uint8_t stepper_index, + bool *is_moving) { - const struct tmc50xx_stepper_config *config = dev->config; + check_stepper_idx(controller, stepper_index); + uint32_t reg_value; int err; - err = tmc50xx_read(config->controller, TMC50XX_DRVSTATUS(config->index), ®_value); + err = tmc50xx_read(controller, TMC50XX_DRVSTATUS(stepper_index), ®_value); if (err != 0) { - LOG_ERR("%s: Failed to read DRVSTATUS register", dev->name); + LOG_ERR("%s: Failed to read DRVSTATUS register", controller->name); return -EIO; } *is_moving = (FIELD_GET(TMC5XXX_DRV_STATUS_STST_BIT, reg_value) != 1U); - LOG_DBG("Stepper motor controller %s is moving: %d", dev->name, *is_moving); + LOG_DBG("Stepper motor controller %s is moving: %d", controller->name, *is_moving); return 0; } -int tmc50xx_stepper_set_max_velocity(const struct device *dev, uint32_t velocity) +int tmc50xx_stepper_set_max_velocity(const struct device *controller, const uint8_t stepper_index, + uint32_t velocity) { - const struct tmc50xx_stepper_config *config = dev->config; - const struct tmc50xx_config *tmc50xx_config = config->controller->config; + const struct tmc50xx_config *tmc50xx_config = controller->config; + + check_stepper_idx(controller, stepper_index); + const uint32_t clock_frequency = tmc50xx_config->clock_frequency; uint32_t velocity_fclk; int err; velocity_fclk = tmc5xxx_calculate_velocity_from_hz_to_fclk(velocity, clock_frequency); - err = tmc50xx_write(config->controller, TMC50XX_VMAX(config->index), velocity_fclk); + err = tmc50xx_write(controller, TMC50XX_VMAX(stepper_index), velocity_fclk); if (err != 0) { - LOG_ERR("%s: Failed to set max velocity", dev->name); + LOG_ERR("%s: Failed to set max velocity", controller->name); return -EIO; } return 0; @@ -410,66 +436,77 @@ static int tmc50xx_stepper_get_micro_step_res(const struct device *dev, return 0; } -static int tmc50xx_stepper_set_reference_position(const struct device *dev, const int32_t position) +static int tmc50xx_stepper_set_reference_position(const struct device *controller, + const uint8_t stepper_index, + const int32_t position) { - const struct tmc50xx_stepper_config *config = dev->config; + check_stepper_idx(controller, stepper_index); int err; - err = tmc50xx_write(config->controller, TMC50XX_RAMPMODE(config->index), + err = tmc50xx_write(controller, TMC50XX_RAMPMODE(stepper_index), TMC5XXX_RAMPMODE_HOLD_MODE); if (err != 0) { return -EIO; } - err = tmc50xx_write(config->controller, TMC50XX_XACTUAL(config->index), position); + err = tmc50xx_write(controller, TMC50XX_XACTUAL(stepper_index), position); if (err != 0) { return -EIO; } - LOG_DBG("Stepper motor controller %s set actual position to %d", dev->name, position); + LOG_DBG("Stepper motor controller %s set actual position to %d", controller->name, + position); return 0; } -static int read_actual_position(const struct tmc50xx_stepper_config *config, int32_t *position) +static int read_actual_position(const struct device *controller, const uint8_t stepper_index, + int32_t *position) { int err; - err = tmc50xx_read(config->controller, TMC50XX_XACTUAL(config->index), position); + err = tmc50xx_read(controller, TMC50XX_XACTUAL(stepper_index), position); if (err != 0) { return -EIO; } return 0; } -static int tmc50xx_stepper_get_actual_position(const struct device *dev, int32_t *position) +static int tmc50xx_stepper_get_actual_position(const struct device *controller, + const uint8_t stepper_index, int32_t *position) { - const struct tmc50xx_stepper_config *config = dev->config; + check_stepper_idx(controller, stepper_index); int err; - err = read_actual_position(config, position); + err = read_actual_position(controller, stepper_index, position); if (err != 0) { return -EIO; } - LOG_DBG("%s actual position: %d", dev->name, *position); + LOG_DBG("%s actual position %d: %d", controller->name, stepper_index, *position); return 0; } -static int tmc50xx_stepper_move_to(const struct device *dev, const int32_t micro_steps) +static int tmc50xx_stepper_move_to(const struct device *controller, const uint8_t stepper_index, + const int32_t micro_steps) { - LOG_DBG("%s set target position to %d", dev->name, micro_steps); - const struct tmc50xx_stepper_config *config = dev->config; - struct tmc50xx_stepper_data *data = dev->data; + const struct tmc50xx_config *controller_config = controller->config; + + check_stepper_idx(controller, stepper_index); + LOG_DBG("%s set target position to %d", controller->name, micro_steps); + + const struct tmc50xx_stepper_config *config = + controller_config->steppers[stepper_index]->config; + struct tmc50xx_stepper_data *data = controller_config->steppers[stepper_index]->data; int err; if (config->is_sg_enabled) { - stallguard_enable(dev, false); + stallguard_enable(controller, stepper_index, false); } - err = tmc50xx_write(config->controller, TMC50XX_RAMPMODE(config->index), + err = tmc50xx_write(controller, TMC50XX_RAMPMODE(stepper_index), TMC5XXX_RAMPMODE_POSITIONING_MODE); if (err != 0) { return -EIO; } - err = tmc50xx_write(config->controller, TMC50XX_XTARGET(config->index), micro_steps); + err = tmc50xx_write(controller, TMC50XX_XTARGET(stepper_index), micro_steps); if (err != 0) { return -EIO; } @@ -484,31 +521,39 @@ static int tmc50xx_stepper_move_to(const struct device *dev, const int32_t micro return 0; } -static int tmc50xx_stepper_move_by(const struct device *dev, const int32_t micro_steps) +static int tmc50xx_stepper_move_by(const struct device *controller, const uint8_t stepper_index, + const int32_t micro_steps) { - int err; + check_stepper_idx(controller, stepper_index); int32_t position; + int err; - err = stepper_get_actual_position(dev, &position); + err = stepper_get_actual_position(controller, stepper_index, &position); if (err != 0) { return -EIO; } int32_t target_position = position + micro_steps; - LOG_DBG("%s moved to %d by steps: %d", dev->name, target_position, micro_steps); + LOG_DBG("%s moved to %d by steps: %d", controller->name, target_position, micro_steps); - return tmc50xx_stepper_move_to(dev, target_position); + return tmc50xx_stepper_move_to(controller, stepper_index, target_position); } -static int tmc50xx_stepper_run(const struct device *dev, const enum stepper_direction direction) +static int tmc50xx_stepper_run(const struct device *controller, const uint8_t stepper_index, + const enum stepper_direction direction) { - LOG_DBG("Stepper motor controller %s run", dev->name); - const struct tmc50xx_stepper_config *config = dev->config; - struct tmc50xx_stepper_data *data = dev->data; + const struct tmc50xx_config *tmc50xx_config = controller->config; + + check_stepper_idx(controller, stepper_index); + LOG_DBG("Stepper motor controller %s run", controller->name); + + const struct tmc50xx_stepper_config *config = + tmc50xx_config->steppers[stepper_index]->config; + struct tmc50xx_stepper_data *data = tmc50xx_config->steppers[stepper_index]->data; int err; if (config->is_sg_enabled) { - err = stallguard_enable(dev, false); + err = stallguard_enable(controller, stepper_index, false); if (err != 0) { return -EIO; } @@ -516,7 +561,7 @@ static int tmc50xx_stepper_run(const struct device *dev, const enum stepper_dire switch (direction) { case STEPPER_DIRECTION_POSITIVE: - err = tmc50xx_write(config->controller, TMC50XX_RAMPMODE(config->index), + err = tmc50xx_write(controller, TMC50XX_RAMPMODE(stepper_index), TMC5XXX_RAMPMODE_POSITIVE_VELOCITY_MODE); if (err != 0) { return -EIO; @@ -524,7 +569,7 @@ static int tmc50xx_stepper_run(const struct device *dev, const enum stepper_dire break; case STEPPER_DIRECTION_NEGATIVE: - err = tmc50xx_write(config->controller, TMC50XX_RAMPMODE(config->index), + err = tmc50xx_write(controller, TMC50XX_RAMPMODE(stepper_index), TMC5XXX_RAMPMODE_NEGATIVE_VELOCITY_MODE); if (err != 0) { return -EIO; @@ -542,18 +587,18 @@ static int tmc50xx_stepper_run(const struct device *dev, const enum stepper_dire return 0; } -static int tmc50xx_stepper_stop(const struct device *dev) +static int tmc50xx_stepper_stop(const struct device *controller, const uint8_t stepper_index) { - const struct tmc50xx_stepper_config *config = dev->config; + check_stepper_idx(controller, stepper_index); int err; - err = tmc50xx_write(config->controller, TMC50XX_RAMPMODE(config->index), + err = tmc50xx_write(controller, TMC50XX_RAMPMODE(stepper_index), TMC5XXX_RAMPMODE_POSITIVE_VELOCITY_MODE); if (err != 0) { return -EIO; } - err = tmc50xx_write(config->controller, TMC50XX_VMAX(config->index), 0); + err = tmc50xx_write(controller, TMC50XX_VMAX(stepper_index), 0); if (err != 0) { return -EIO; } @@ -563,61 +608,57 @@ static int tmc50xx_stepper_stop(const struct device *dev) #ifdef CONFIG_STEPPER_ADI_TMC50XX_RAMP_GEN -int tmc50xx_stepper_set_ramp(const struct device *dev, +int tmc50xx_stepper_set_ramp(const struct device *controller, const uint8_t stepper_index, const struct tmc_ramp_generator_data *ramp_data) { - LOG_DBG("Stepper motor controller %s set ramp", dev->name); - const struct tmc50xx_stepper_config *config = dev->config; + LOG_DBG("Stepper motor controller %s set ramp", controller->name); int err; - err = tmc50xx_write(config->controller, TMC50XX_VSTART(config->index), ramp_data->vstart); + err = tmc50xx_write(controller, TMC50XX_VSTART(stepper_index), ramp_data->vstart); if (err != 0) { return -EIO; } - err = tmc50xx_write(config->controller, TMC50XX_A1(config->index), ramp_data->a1); + err = tmc50xx_write(controller, TMC50XX_A1(stepper_index), ramp_data->a1); if (err != 0) { return -EIO; } - err = tmc50xx_write(config->controller, TMC50XX_AMAX(config->index), ramp_data->amax); + err = tmc50xx_write(controller, TMC50XX_AMAX(stepper_index), ramp_data->amax); if (err != 0) { return -EIO; } - err = tmc50xx_write(config->controller, TMC50XX_D1(config->index), ramp_data->d1); + err = tmc50xx_write(controller, TMC50XX_D1(stepper_index), ramp_data->d1); if (err != 0) { return -EIO; } - err = tmc50xx_write(config->controller, TMC50XX_DMAX(config->index), ramp_data->dmax); + err = tmc50xx_write(controller, TMC50XX_DMAX(stepper_index), ramp_data->dmax); if (err != 0) { return -EIO; } - err = tmc50xx_write(config->controller, TMC50XX_V1(config->index), ramp_data->v1); + err = tmc50xx_write(controller, TMC50XX_V1(stepper_index), ramp_data->v1); if (err != 0) { return -EIO; } - err = tmc50xx_write(config->controller, TMC50XX_VMAX(config->index), ramp_data->vmax); + err = tmc50xx_write(controller, TMC50XX_VMAX(stepper_index), ramp_data->vmax); if (err != 0) { return -EIO; } - err = tmc50xx_write(config->controller, TMC50XX_VSTOP(config->index), ramp_data->vstop); + err = tmc50xx_write(controller, TMC50XX_VSTOP(stepper_index), ramp_data->vstop); if (err != 0) { return -EIO; } - err = tmc50xx_write(config->controller, TMC50XX_TZEROWAIT(config->index), - ramp_data->tzerowait); + err = tmc50xx_write(controller, TMC50XX_TZEROWAIT(stepper_index), ramp_data->tzerowait); if (err != 0) { return -EIO; } - err = tmc50xx_write(config->controller, TMC50XX_VHIGH(config->index), ramp_data->vhigh); + err = tmc50xx_write(controller, TMC50XX_VHIGH(stepper_index), ramp_data->vhigh); if (err != 0) { return -EIO; } - err = tmc50xx_write(config->controller, TMC50XX_VCOOLTHRS(config->index), - ramp_data->vcoolthrs); + err = tmc50xx_write(controller, TMC50XX_VCOOLTHRS(stepper_index), ramp_data->vcoolthrs); if (err != 0) { return -EIO; } - err = tmc50xx_write(config->controller, TMC50XX_IHOLD_IRUN(config->index), - ramp_data->iholdrun); + err = tmc50xx_write(controller, TMC50XX_IHOLD_IRUN(stepper_index), ramp_data->iholdrun); if (err != 0) { return -EIO; } @@ -628,11 +669,11 @@ int tmc50xx_stepper_set_ramp(const struct device *dev, static int tmc50xx_init(const struct device *dev) { - LOG_DBG("TMC50XX stepper motor controller %s initialized", dev->name); struct tmc50xx_data *data = dev->data; const struct tmc50xx_config *config = dev->config; int err; + LOG_DBG("Initializing TMC50XX stepper motor controller %s", dev->name); k_sem_init(&data->sem, 1, 1); if (!spi_is_ready_dt(&config->spi)) { @@ -696,7 +737,8 @@ static int tmc50xx_stepper_init(const struct device *dev) } #ifdef CONFIG_STEPPER_ADI_TMC50XX_RAMP_GEN - err = tmc50xx_stepper_set_ramp(dev, &stepper_config->default_ramp_config); + err = tmc50xx_stepper_set_ramp(stepper_config->controller, stepper_config->index, + &stepper_config->default_ramp_config); if (err != 0) { return -EIO; } @@ -711,21 +753,26 @@ static int tmc50xx_stepper_init(const struct device *dev) return 0; } -static DEVICE_API(stepper, tmc50xx_stepper_api) = { +static DEVICE_API(stepper_drv, tmc50xx_step_dir_api) = { .enable = tmc50xx_stepper_enable, .disable = tmc50xx_stepper_disable, - .is_moving = tmc50xx_stepper_is_moving, - .move_by = tmc50xx_stepper_move_by, .set_micro_step_res = tmc50xx_stepper_set_micro_step_res, .get_micro_step_res = tmc50xx_stepper_get_micro_step_res, +}; + +static DEVICE_API(stepper, tmc50xx_stepper_api) = { + .is_moving = tmc50xx_stepper_is_moving, + .move_by = tmc50xx_stepper_move_by, .set_reference_position = tmc50xx_stepper_set_reference_position, .get_actual_position = tmc50xx_stepper_get_actual_position, .move_to = tmc50xx_stepper_move_to, .run = tmc50xx_stepper_run, .stop = tmc50xx_stepper_stop, - .set_event_callback = tmc50xx_stepper_set_event_callback, + .set_event_callback = tmc50xx_set_event_callback, }; +#define TMC50XX_STEPPER_PTRS(child) DEVICE_DT_GET(child), + #define TMC50XX_SHAFT_CONFIG(child) \ (DT_PROP(child, invert_direction) << TMC50XX_GCONF_SHAFT_SHIFT(DT_REG_ADDR(child))) | @@ -740,20 +787,21 @@ static DEVICE_API(stepper, tmc50xx_stepper_api) = { .index = DT_REG_ADDR(child), \ .sg_threshold = DT_PROP(child, stallguard2_threshold), \ .sg_threshold_velocity = DT_PROP(child, stallguard_threshold_velocity), \ - .sg_velocity_check_interval_ms = DT_PROP(child, \ - stallguard_velocity_check_interval_ms), \ + .sg_velocity_check_interval_ms = \ + DT_PROP(child, stallguard_velocity_check_interval_ms), \ .is_sg_enabled = DT_PROP(child, activate_stallguard2), \ IF_ENABLED(CONFIG_STEPPER_ADI_TMC50XX_RAMP_GEN, \ (.default_ramp_config = TMC_RAMP_DT_SPEC_GET_TMC50XX(child))) }; #define TMC50XX_STEPPER_DATA_DEFINE(child) \ static struct tmc50xx_stepper_data tmc50xx_stepper_data_##child = { \ - .stepper = DEVICE_DT_GET(child),}; + .stepper = DEVICE_DT_GET(child), \ + }; #define TMC50XX_STEPPER_DEFINE(child) \ DEVICE_DT_DEFINE(child, tmc50xx_stepper_init, NULL, &tmc50xx_stepper_data_##child, \ &tmc50xx_stepper_config_##child, POST_KERNEL, \ - CONFIG_STEPPER_INIT_PRIORITY, &tmc50xx_stepper_api); + CONFIG_STEPPER_INIT_PRIORITY, &tmc50xx_step_dir_api); #define TMC50XX_DEFINE(inst) \ BUILD_ASSERT(DT_INST_CHILD_NUM(inst) <= 2, "tmc50xx can drive two steppers at max"); \ @@ -761,19 +809,25 @@ static DEVICE_API(stepper, tmc50xx_stepper_api) = { "clock frequency must be non-zero positive value"); \ static struct tmc50xx_data tmc50xx_data_##inst; \ static const struct tmc50xx_config tmc50xx_config_##inst = { \ - .gconf = ( \ - (DT_INST_PROP(inst, poscmp_enable) << TMC50XX_GCONF_POSCMP_ENABLE_SHIFT) | \ - (DT_INST_PROP(inst, test_mode) << TMC50XX_GCONF_TEST_MODE_SHIFT) | \ - DT_INST_FOREACH_CHILD(inst, TMC50XX_SHAFT_CONFIG) \ - (DT_INST_PROP(inst, lock_gconf) << TMC50XX_LOCK_GCONF_SHIFT)), \ - .spi = SPI_DT_SPEC_INST_GET(inst, (SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | \ - SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8)), 0), \ - .clock_frequency = DT_INST_PROP(inst, clock_frequency),}; \ + .gconf = ((DT_INST_PROP(inst, poscmp_enable) \ + << TMC50XX_GCONF_POSCMP_ENABLE_SHIFT) | \ + (DT_INST_PROP(inst, test_mode) << TMC50XX_GCONF_TEST_MODE_SHIFT) | \ + DT_INST_FOREACH_CHILD(inst, TMC50XX_SHAFT_CONFIG)( \ + DT_INST_PROP(inst, lock_gconf) << TMC50XX_LOCK_GCONF_SHIFT)), \ + .spi = SPI_DT_SPEC_INST_GET(inst, \ + (SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | \ + SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8)), \ + 0), \ + .steppers = (const struct device *[]){DT_INST_FOREACH_CHILD( \ + inst, TMC50XX_STEPPER_PTRS)}, \ + .num_steppers = DT_INST_CHILD_NUM(inst), \ + .clock_frequency = DT_INST_PROP(inst, clock_frequency), \ + }; \ DT_INST_FOREACH_CHILD(inst, TMC50XX_STEPPER_CONFIG_DEFINE); \ DT_INST_FOREACH_CHILD(inst, TMC50XX_STEPPER_DATA_DEFINE); \ DT_INST_FOREACH_CHILD(inst, TMC50XX_STEPPER_DEFINE); \ DEVICE_DT_INST_DEFINE(inst, tmc50xx_init, NULL, &tmc50xx_data_##inst, \ &tmc50xx_config_##inst, POST_KERNEL, CONFIG_STEPPER_INIT_PRIORITY,\ - NULL); + &tmc50xx_stepper_api); DT_INST_FOREACH_STATUS_OKAY(TMC50XX_DEFINE) diff --git a/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.c b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.c index ec334965e3dd..46283577b5df 100644 --- a/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.c +++ b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.c @@ -15,6 +15,8 @@ #include LOG_MODULE_REGISTER(tmc51xx, CONFIG_STEPPER_LOG_LEVEL); +#define TMC51XX_MAX_SUPPORTED_STEPPER 1 + static inline int tmc51xx_bus_check(const struct device *dev) { const struct tmc51xx_config *config = dev->config; @@ -66,16 +68,19 @@ static int tmc51xx_read(const struct device *dev, const uint8_t reg_addr, uint32 return 0; } -static int tmc51xx_stepper_set_event_callback(const struct device *dev, +static int tmc51xx_stepper_set_event_callback(const struct device *controller, + const uint8_t stepper_idx, stepper_event_callback_t callback, void *user_data) { - struct tmc51xx_data *data = dev->data; - __maybe_unused const struct tmc51xx_config *config = dev->config; + CHECK_STEPPER_IDX(controller, stepper_idx, TMC51XX_MAX_SUPPORTED_STEPPER); + __maybe_unused struct tmc51xx_data *data = controller->data; + const struct tmc51xx_config *config = controller->config; + struct tmc51xx_stepper_data *stepper_data = config->steppers[0]->data; __maybe_unused int err; - data->callback = callback; - data->event_cb_user_data = user_data; + stepper_data->callback = callback; + stepper_data->event_cb_user_data = user_data; /* Configure DIAG0 GPIO interrupt pin */ IF_ENABLED(TMC51XX_BUS_SPI, ({ @@ -112,7 +117,7 @@ static int tmc51xx_stepper_set_event_callback(const struct device *dev, /* Clear any pending interrupts */ uint32_t rampstat_value; - err = rampstat_read_clear(dev, &rampstat_value); + err = rampstat_read_clear(controller, &rampstat_value); if (err != 0) { return -EIO; } @@ -121,12 +126,13 @@ static int tmc51xx_stepper_set_event_callback(const struct device *dev, return 0; } -static int read_vactual(const struct device *dev, int32_t *actual_velocity) +static int read_vactual(const struct device *controller, int32_t *actual_velocity) { + __ASSERT(actual_velocity != NULL, "actual_velocity pointer must not be NULL"); int err; uint32_t raw_value; - err = tmc51xx_read(dev, TMC51XX_VACTUAL, &raw_value); + err = tmc51xx_read(controller, TMC51XX_VACTUAL, &raw_value); if (err) { LOG_ERR("Failed to read VACTUAL register"); return err; @@ -139,13 +145,14 @@ static int read_vactual(const struct device *dev, int32_t *actual_velocity) return 0; } -static int stallguard_enable(const struct device *dev, const bool enable) +static int stallguard_enable(const struct device *controller, const bool enable) { - const struct tmc51xx_config *config = dev->config; + const struct tmc51xx_config *tmc51xx_config = controller->config; + const struct tmc51xx_stepper_config *config = tmc51xx_config->steppers[0]->config; uint32_t reg_value; int err; - err = tmc51xx_read(dev, TMC51XX_SWMODE, ®_value); + err = tmc51xx_read(controller, TMC51XX_SWMODE, ®_value); if (err) { LOG_ERR("Failed to read SWMODE register"); return -EIO; @@ -156,7 +163,7 @@ static int stallguard_enable(const struct device *dev, const bool enable) int32_t actual_velocity; - err = read_vactual(dev, &actual_velocity); + err = read_vactual(controller, &actual_velocity); if (err) { return -EIO; } @@ -166,7 +173,7 @@ static int stallguard_enable(const struct device *dev, const bool enable) } else { reg_value &= ~TMC5XXX_SW_MODE_SG_STOP_ENABLE; } - err = tmc51xx_write(dev, TMC51XX_SWMODE, reg_value); + err = tmc51xx_write(controller, TMC51XX_SWMODE, reg_value); if (err) { LOG_ERR("Failed to write SWMODE register"); return -EIO; @@ -179,15 +186,14 @@ static int stallguard_enable(const struct device *dev, const bool enable) static void stallguard_work_handler(struct k_work *work) { struct k_work_delayable *dwork = k_work_delayable_from_work(work); - struct tmc51xx_data const *stepper_data = - CONTAINER_OF(dwork, struct tmc51xx_data, stallguard_dwork); - const struct device *dev = stepper_data->stepper; - const struct tmc51xx_config *config = dev->config; + struct tmc51xx_stepper_data const *stepper_data = + CONTAINER_OF(dwork, struct tmc51xx_stepper_data, stallguard_dwork); + const struct tmc51xx_stepper_config *stepper_config = stepper_data->stepper->config; int err; - err = stallguard_enable(dev, true); + err = stallguard_enable(stepper_config->controller, true); if (err == -EAGAIN) { - k_work_reschedule(dwork, K_MSEC(config->sg_velocity_check_interval_ms)); + k_work_reschedule(dwork, K_MSEC(stepper_config->sg_velocity_check_interval_ms)); } if (err == -EIO) { LOG_ERR("Failed to enable stallguard because of I/O error"); @@ -196,13 +202,13 @@ static void stallguard_work_handler(struct k_work *work) static void stepper_trigger_callback(const struct device *dev, const enum stepper_event event) { - struct tmc51xx_data *data = dev->data; + struct tmc51xx_stepper_data *data = dev->data; if (!data->callback) { LOG_WRN_ONCE("No callback registered"); return; } - data->callback(dev, event, data->event_cb_user_data); + data->callback(dev, 0, event, data->event_cb_user_data); } #ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_STALLGUARD_LOG @@ -227,25 +233,31 @@ static void log_stallguard(const struct device *dev, const uint32_t drv_status) #endif /* CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_STALLGUARD_LOG */ -static int rampstat_read_clear(const struct device *dev, uint32_t *rampstat_value) +static int rampstat_read_clear(const struct device *controller, uint32_t *rampstat_value) { int err; - err = tmc51xx_read(dev, TMC51XX_RAMPSTAT, rampstat_value); + err = tmc51xx_read(controller, TMC51XX_RAMPSTAT, rampstat_value); if (err == 0) { - err = tmc51xx_write(dev, TMC51XX_RAMPSTAT, *rampstat_value); + err = tmc51xx_write(controller, TMC51XX_RAMPSTAT, *rampstat_value); } return err; } +static void rampstat_work_reschedule(struct k_work_delayable *rampstat_callback_dwork) +{ + k_work_reschedule(rampstat_callback_dwork, + K_MSEC(CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); +} + static void rampstat_work_handler(struct k_work *work) { struct k_work_delayable *dwork = k_work_delayable_from_work(work); - struct tmc51xx_data *stepper_data = + struct tmc51xx_data *data = CONTAINER_OF(dwork, struct tmc51xx_data, rampstat_callback_dwork); - const struct device *dev = stepper_data->stepper; - __maybe_unused const struct tmc51xx_config *config = dev->config; + const struct device *dev = data->dev; + const struct tmc51xx_config *config = dev->config; __ASSERT_NO_MSG(dev); @@ -319,7 +331,7 @@ static void rampstat_work_handler(struct k_work *work) /* For UART or SPI without DIAG0, reschedule RAMPSTAT polling */ #ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC k_work_reschedule( - &stepper_data->rampstat_callback_dwork, + &data->rampstat_callback_dwork, K_MSEC(CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); #endif /* CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC */ } @@ -332,9 +344,9 @@ static void __maybe_unused tmc51xx_diag0_gpio_callback_handler(const struct devi ARG_UNUSED(port); ARG_UNUSED(pins); - struct tmc51xx_data *stepper_data = CONTAINER_OF(cb, struct tmc51xx_data, diag0_cb); + struct tmc51xx_data *data = CONTAINER_OF(cb, struct tmc51xx_data, diag0_cb); - k_work_reschedule(&stepper_data->rampstat_callback_dwork, K_NO_WAIT); + k_work_reschedule(&data->rampstat_callback_dwork, K_NO_WAIT); } static int tmc51xx_stepper_enable(const struct device *dev) @@ -369,8 +381,10 @@ static int tmc51xx_stepper_disable(const struct device *dev) return tmc51xx_write(dev, TMC51XX_CHOPCONF, reg_value); } -static int tmc51xx_stepper_is_moving(const struct device *dev, bool *is_moving) +static int tmc51xx_stepper_is_moving(const struct device *dev, const uint8_t stepper_index, + bool *is_moving) { + CHECK_STEPPER_IDX(dev, stepper_index, TMC51XX_MAX_SUPPORTED_STEPPER); uint32_t reg_value; int err; @@ -445,8 +459,10 @@ static int tmc51xx_stepper_get_micro_step_res(const struct device *dev, return 0; } -static int tmc51xx_stepper_set_reference_position(const struct device *dev, const int32_t position) +static int tmc51xx_stepper_set_reference_position(const struct device *dev, + const uint8_t stepper_idx, const int32_t position) { + CHECK_STEPPER_IDX(dev, stepper_idx, TMC51XX_MAX_SUPPORTED_STEPPER); int err; err = tmc51xx_write(dev, TMC51XX_RAMPMODE, TMC5XXX_RAMPMODE_HOLD_MODE); @@ -473,7 +489,7 @@ static int read_actual_position(const struct device *dev, int32_t *position) if (config->comm_type == TMC_COMM_UART) { bool is_moving; - err = tmc51xx_stepper_is_moving(dev, &is_moving); + err = tmc51xx_stepper_is_moving(dev, 0, &is_moving); if (err != 0) { return -EIO; } @@ -494,8 +510,10 @@ static int read_actual_position(const struct device *dev, int32_t *position) return 0; } -static int tmc51xx_stepper_get_actual_position(const struct device *dev, int32_t *position) +static int tmc51xx_stepper_get_actual_position(const struct device *dev, const uint8_t stepper_idx, + int32_t *position) { + CHECK_STEPPER_IDX(dev, stepper_idx, TMC51XX_MAX_SUPPORTED_STEPPER); int err; err = read_actual_position(dev, position); @@ -506,31 +524,35 @@ static int tmc51xx_stepper_get_actual_position(const struct device *dev, int32_t return 0; } -static int tmc51xx_stepper_move_to(const struct device *dev, const int32_t micro_steps) +static int tmc51xx_stepper_move_to(const struct device *controller, const uint8_t stepper_idx, + const int32_t micro_steps) { - LOG_DBG("%s set target position to %d", dev->name, micro_steps); - const struct tmc51xx_config *config = dev->config; - struct tmc51xx_data *data = dev->data; + CHECK_STEPPER_IDX(controller, stepper_idx, TMC51XX_MAX_SUPPORTED_STEPPER); + LOG_DBG("%s set target position to %d", controller->name, micro_steps); + const struct tmc51xx_config *config = controller->config; + struct tmc51xx_data *data = controller->data; + const struct tmc51xx_stepper_config *stepper_config = config->steppers[0]->config; + struct tmc51xx_stepper_data *stepper_data = config->steppers[0]->data; int err; - if (config->is_sg_enabled) { - stallguard_enable(dev, false); + if (stepper_config->is_sg_enabled) { + stallguard_enable(controller, false); } - err = tmc51xx_write(dev, TMC51XX_RAMPMODE, TMC5XXX_RAMPMODE_POSITIONING_MODE); + err = tmc51xx_write(controller, TMC51XX_RAMPMODE, TMC5XXX_RAMPMODE_POSITIONING_MODE); if (err != 0) { return -EIO; } - err = tmc51xx_write(dev, TMC51XX_XTARGET, micro_steps); + err = tmc51xx_write(controller, TMC51XX_XTARGET, micro_steps); if (err != 0) { return -EIO; } - if (config->is_sg_enabled) { - k_work_reschedule(&data->stallguard_dwork, - K_MSEC(config->sg_velocity_check_interval_ms)); + if (stepper_config->is_sg_enabled) { + k_work_reschedule(&stepper_data->stallguard_dwork, + K_MSEC(stepper_config->sg_velocity_check_interval_ms)); } - if (data->callback) { + if (stepper_data->callback) { /* For SPI with DIAG0 pin, we use interrupt-driven approach */ IF_ENABLED(TMC51XX_BUS_SPI, ({ if (config->comm_type == TMC_COMM_SPI && config->diag0_gpio.port) { @@ -549,31 +571,37 @@ static int tmc51xx_stepper_move_to(const struct device *dev, const int32_t micro return 0; } -static int tmc51xx_stepper_move_by(const struct device *dev, const int32_t micro_steps) +static int tmc51xx_stepper_move_by(const struct device *controller, const uint8_t stepper_idx, + const int32_t micro_steps) { + CHECK_STEPPER_IDX(controller, stepper_idx, TMC51XX_MAX_SUPPORTED_STEPPER); int err; int32_t position; - err = tmc51xx_stepper_get_actual_position(dev, &position); + err = tmc51xx_stepper_get_actual_position(controller, stepper_idx, &position); if (err != 0) { return -EIO; } int32_t target_position = position + micro_steps; - LOG_DBG("%s moved to %d by steps: %d", dev->name, target_position, micro_steps); + LOG_DBG("%s moved to %d by steps: %d", controller->name, target_position, micro_steps); - return tmc51xx_stepper_move_to(dev, target_position); + return tmc51xx_stepper_move_to(controller, stepper_idx, target_position); } -static int tmc51xx_stepper_run(const struct device *dev, const enum stepper_direction direction) +static int tmc51xx_stepper_run(const struct device *controller, const uint8_t stepper_index, + const enum stepper_direction direction) { - LOG_DBG("Stepper motor controller %s run", dev->name); - const struct tmc51xx_config *config = dev->config; - struct tmc51xx_data *data = dev->data; + CHECK_STEPPER_IDX(controller, stepper_index, TMC51XX_MAX_SUPPORTED_STEPPER); + LOG_DBG("Stepper motor controller %s run", controller->name); + const struct tmc51xx_config *tmc51xx_config = controller->config; + struct tmc51xx_data *data = controller->data; + const struct tmc51xx_stepper_config *config = tmc51xx_config->steppers[0]->config; + struct tmc51xx_stepper_data *stepper_data = tmc51xx_config->steppers[0]->data; int err; if (config->is_sg_enabled) { - err = stallguard_enable(dev, false); + err = stallguard_enable(controller, false); if (err != 0) { return -EIO; } @@ -581,14 +609,16 @@ static int tmc51xx_stepper_run(const struct device *dev, const enum stepper_dire switch (direction) { case STEPPER_DIRECTION_POSITIVE: - err = tmc51xx_write(dev, TMC51XX_RAMPMODE, TMC5XXX_RAMPMODE_POSITIVE_VELOCITY_MODE); + err = tmc51xx_write(controller, TMC51XX_RAMPMODE, + TMC5XXX_RAMPMODE_POSITIVE_VELOCITY_MODE); if (err != 0) { return -EIO; } break; case STEPPER_DIRECTION_NEGATIVE: - err = tmc51xx_write(dev, TMC51XX_RAMPMODE, TMC5XXX_RAMPMODE_NEGATIVE_VELOCITY_MODE); + err = tmc51xx_write(controller, TMC51XX_RAMPMODE, + TMC5XXX_RAMPMODE_NEGATIVE_VELOCITY_MODE); if (err != 0) { return -EIO; } @@ -596,13 +626,13 @@ static int tmc51xx_stepper_run(const struct device *dev, const enum stepper_dire } if (config->is_sg_enabled) { - k_work_reschedule(&data->stallguard_dwork, + k_work_reschedule(&stepper_data->stallguard_dwork, K_MSEC(config->sg_velocity_check_interval_ms)); } - if (data->callback) { + if (stepper_data->callback) { /* For SPI with DIAG0 pin, we use interrupt-driven approach */ IF_ENABLED(TMC51XX_BUS_SPI, ({ - if (config->comm_type == TMC_COMM_SPI && config->diag0_gpio.port) { + if (tmc51xx_config->comm_type == TMC_COMM_SPI && tmc51xx_config->diag0_gpio.port) { /* Using interrupt-driven approach - no polling needed */ return 0; } @@ -620,9 +650,10 @@ static int tmc51xx_stepper_run(const struct device *dev, const enum stepper_dire #ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN -int tmc51xx_stepper_set_ramp(const struct device *dev, +int tmc51xx_stepper_set_ramp(const struct device *dev, const uint8_t stepper_index, const struct tmc_ramp_generator_data *ramp_data) { + CHECK_STEPPER_IDX(dev, stepper_index, TMC51XX_MAX_SUPPORTED_STEPPER); LOG_DBG("Stepper motor controller %s set ramp", dev->name); int err; @@ -737,26 +768,41 @@ static int tmc51xx_init(const struct device *dev) return -EIO; } - if (config->is_sg_enabled) { + k_work_init_delayable(&data->rampstat_callback_dwork, rampstat_work_handler); + rampstat_work_reschedule(&data->rampstat_callback_dwork); + return 0; +} + +static int tmc51xx_stepper_init(const struct device *dev) +{ + const struct tmc51xx_stepper_config *stepper_config = dev->config; + struct tmc51xx_stepper_data *data = dev->data; + int err; + + LOG_DBG("Controller: %s, Stepper: %s", stepper_config->controller->name, dev->name); + + if (stepper_config->is_sg_enabled) { k_work_init_delayable(&data->stallguard_dwork, stallguard_work_handler); - err = tmc51xx_write(dev, TMC51XX_SWMODE, BIT(10)); + err = tmc51xx_write(stepper_config->controller, + TMC50XX_SWMODE(stepper_config->index), BIT(10)); if (err != 0) { return -EIO; } - LOG_DBG("Setting stall guard to %d with delay %d ms", config->sg_threshold, - config->sg_velocity_check_interval_ms); - if (!IN_RANGE(config->sg_threshold, TMC5XXX_SG_MIN_VALUE, TMC5XXX_SG_MAX_VALUE)) { + LOG_DBG("Setting stall guard to %d with delay %d ms", stepper_config->sg_threshold, + stepper_config->sg_velocity_check_interval_ms); + if (!IN_RANGE(stepper_config->sg_threshold, TMC5XXX_SG_MIN_VALUE, + TMC5XXX_SG_MAX_VALUE)) { LOG_ERR("Stallguard threshold out of range"); return -EINVAL; } - int32_t stall_guard_threshold = (int32_t)config->sg_threshold; + int32_t stall_guard_threshold = (int32_t)stepper_config->sg_threshold; - err = tmc51xx_write(dev, TMC51XX_COOLCONF, - stall_guard_threshold - << TMC5XXX_COOLCONF_SG2_THRESHOLD_VALUE_SHIFT); + err = tmc51xx_write( + stepper_config->controller, TMC50XX_COOLCONF(stepper_config->index), + stall_guard_threshold << TMC5XXX_COOLCONF_SG2_THRESHOLD_VALUE_SHIFT); if (err != 0) { return -EIO; } @@ -764,25 +810,22 @@ static int tmc51xx_init(const struct device *dev) } #ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN - err = tmc51xx_stepper_set_ramp(dev, &config->default_ramp_config); + err = tmc51xx_stepper_set_ramp(stepper_config->controller, stepper_config->index, + &stepper_config->default_ramp_config); if (err != 0) { return -EIO; } #endif - - k_work_init_delayable(&data->rampstat_callback_dwork, rampstat_work_handler); - uint32_t rampstat_value; - (void)rampstat_read_clear(dev, &rampstat_value); - - err = tmc51xx_stepper_set_micro_step_res(dev, config->default_micro_step_res); + err = tmc51xx_stepper_set_micro_step_res(dev, stepper_config->default_micro_step_res); if (err != 0) { return -EIO; } return 0; } -static int tmc51xx_stepper_stop(const struct device *dev) +static int tmc51xx_stepper_stop(const struct device *dev, const uint8_t stepper_idx) { + CHECK_STEPPER_IDX(dev, stepper_idx, TMC51XX_MAX_SUPPORTED_STEPPER); int err; err = tmc51xx_write(dev, TMC51XX_RAMPMODE, TMC5XXX_RAMPMODE_POSITIVE_VELOCITY_MODE); @@ -798,13 +841,16 @@ static int tmc51xx_stepper_stop(const struct device *dev) return 0; } -static DEVICE_API(stepper, tmc51xx_api) = { +static DEVICE_API(stepper_drv, tmc51xx_drv_api) = { .enable = tmc51xx_stepper_enable, .disable = tmc51xx_stepper_disable, - .is_moving = tmc51xx_stepper_is_moving, - .move_by = tmc51xx_stepper_move_by, .set_micro_step_res = tmc51xx_stepper_set_micro_step_res, .get_micro_step_res = tmc51xx_stepper_get_micro_step_res, +}; + +static DEVICE_API(stepper, tmc51xx_api) = { + .is_moving = tmc51xx_stepper_is_moving, + .move_by = tmc51xx_stepper_move_by, .set_reference_position = tmc51xx_stepper_set_reference_position, .get_actual_position = tmc51xx_stepper_get_actual_position, .move_to = tmc51xx_stepper_move_to, @@ -813,6 +859,8 @@ static DEVICE_API(stepper, tmc51xx_api) = { .set_event_callback = tmc51xx_stepper_set_event_callback, }; +#define TMC51XX_STEPPER_PTRS(child) DEVICE_DT_GET(child), + /* Initializes a struct tmc51xx_config for an instance on a SPI bus. */ #define TMC51XX_CONFIG_SPI(inst) \ .comm_type = TMC_COMM_SPI, \ @@ -829,15 +877,46 @@ static DEVICE_API(stepper, tmc51xx_api) = { .bus_io = &tmc51xx_uart_bus_io, .uart_addr = DT_INST_PROP_OR(inst, uart_device_addr, 1U), \ .sw_sel_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, sw_sel_gpios, {0}) +#define TMC51XX_STEPPER_CONFIG_DEFINE(child) \ + COND_CODE_1(DT_PROP_EXISTS(child, stallguard_threshold_velocity), \ + BUILD_ASSERT(DT_PROP(child, stallguard_threshold_velocity), \ + "stallguard threshold velocity must be a positive value"), ()); \ + IF_ENABLED(CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN, (CHECK_RAMP_DT_DATA(child))); \ + static const struct tmc51xx_stepper_config tmc51xx_stepper_config_##child = { \ + .controller = DEVICE_DT_GET(DT_PARENT(child)), \ + .default_micro_step_res = DT_PROP(child, micro_step_res), \ + .index = DT_REG_ADDR(child), \ + .sg_threshold = DT_PROP(child, stallguard2_threshold), \ + .sg_threshold_velocity = DT_PROP(child, stallguard_threshold_velocity), \ + .sg_velocity_check_interval_ms = \ + DT_PROP(child, stallguard_velocity_check_interval_ms), \ + .is_sg_enabled = DT_PROP(child, activate_stallguard2), \ + IF_ENABLED(CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN, \ + (.default_ramp_config = TMC_RAMP_DT_SPEC_GET_TMC51XX(child))) }; + +#define TMC51XX_STEPPER_DATA_DEFINE(child) \ + static struct tmc51xx_stepper_data tmc51xx_stepper_data_##child = { \ + .stepper = DEVICE_DT_GET(child), \ + }; + +#define TMC51XX_STEPPER_DEFINE(child) \ + DEVICE_DT_DEFINE(child, tmc51xx_stepper_init, NULL, &tmc51xx_stepper_data_##child, \ + &tmc51xx_stepper_config_##child, POST_KERNEL, \ + CONFIG_STEPPER_INIT_PRIORITY, &tmc51xx_drv_api); + +#define TMC51XX_SHAFT_CONFIG(child) DT_PROP(child, invert_direction) << TMC51XX_GCONF_SHAFT_SHIFT + /* Device initialization macros */ #define TMC51XX_DEFINE(inst) \ + BUILD_ASSERT(DT_INST_CHILD_NUM(inst) <= 1, "tmc51xx can drive two steppers at max"); \ BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) > 0), \ "clock frequency must be non-zero positive value"); \ - static struct tmc51xx_data tmc51xx_data_##inst = { \ - .stepper = DEVICE_DT_GET(DT_DRV_INST(inst))}; \ + static struct tmc51xx_data tmc51xx_data_##inst = { \ + .dev = DEVICE_DT_INST_GET(inst), \ + }; \ COND_CODE_1(DT_PROP_EXISTS(inst, stallguard_threshold_velocity), \ BUILD_ASSERT(DT_PROP(inst, stallguard_threshold_velocity), \ - "stallguard threshold velocity must be a positive value"), ()); \ + "stallguard threshold velocity must be a positive value"), ()); \ IF_ENABLED(CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN, (CHECK_RAMP_DT_DATA(inst))); \ static const struct tmc51xx_config tmc51xx_config_##inst = {COND_CODE_1 \ (DT_INST_ON_BUS(inst, spi), \ @@ -845,19 +924,17 @@ static DEVICE_API(stepper, tmc51xx_api) = { (TMC51XX_CONFIG_UART(inst))), \ .gconf = ((DT_INST_PROP(inst, en_pwm_mode) << TMC51XX_GCONF_EN_PWM_MODE_SHIFT) | \ (DT_INST_PROP(inst, test_mode) << TMC51XX_GCONF_TEST_MODE_SHIFT) | \ - (DT_INST_PROP(inst, invert_direction) << TMC51XX_GCONF_SHAFT_SHIFT) | \ + DT_INST_FOREACH_CHILD(inst, TMC51XX_SHAFT_CONFIG) | \ (DT_INST_NODE_HAS_PROP(inst, diag0_gpios) \ ? BIT(TMC51XX_GCONF_DIAG0_INT_PUSHPULL_SHIFT) \ : 0)), \ - .clock_frequency = DT_INST_PROP(inst, clock_frequency), \ - .default_micro_step_res = DT_INST_PROP(inst, micro_step_res), \ - .sg_threshold = DT_INST_PROP(inst, stallguard2_threshold), \ - .sg_threshold_velocity = DT_INST_PROP(inst, stallguard_threshold_velocity), \ - .sg_velocity_check_interval_ms = \ - DT_INST_PROP(inst, stallguard_velocity_check_interval_ms), \ - .is_sg_enabled = DT_INST_PROP(inst, activate_stallguard2), \ - IF_ENABLED(CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN, \ - (.default_ramp_config = TMC_RAMP_DT_SPEC_GET_TMC51XX(inst)))}; \ + .steppers = (const struct device *[]){DT_INST_FOREACH_CHILD( \ + inst, TMC51XX_STEPPER_PTRS)}, \ + .clock_frequency = DT_INST_PROP(inst, clock_frequency), \ + }; \ + DT_INST_FOREACH_CHILD(inst, TMC51XX_STEPPER_CONFIG_DEFINE); \ + DT_INST_FOREACH_CHILD(inst, TMC51XX_STEPPER_DATA_DEFINE); \ + DT_INST_FOREACH_CHILD(inst, TMC51XX_STEPPER_DEFINE); \ DEVICE_DT_INST_DEFINE(inst, tmc51xx_init, NULL, &tmc51xx_data_##inst, \ &tmc51xx_config_##inst, POST_KERNEL, CONFIG_STEPPER_INIT_PRIORITY, \ &tmc51xx_api); diff --git a/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.h b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.h index 43c26255dfd8..fe339d501c35 100644 --- a/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.h +++ b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.h @@ -25,14 +25,7 @@ struct tmc51xx_config { uint8_t comm_type; const uint32_t gconf; const uint32_t clock_frequency; - const uint16_t default_micro_step_res; - const int8_t sg_threshold; - const bool is_sg_enabled; - const uint32_t sg_velocity_check_interval_ms; - const uint32_t sg_threshold_velocity; -#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN - const struct tmc_ramp_generator_data default_ramp_config; -#endif + const struct device **steppers; #if TMC51XX_BUS_UART const struct gpio_dt_spec sw_sel_gpio; uint8_t uart_addr; @@ -44,9 +37,27 @@ struct tmc51xx_config { struct tmc51xx_data { struct k_sem sem; - struct k_work_delayable stallguard_dwork; - struct k_work_delayable rampstat_callback_dwork; + const struct device *dev; struct gpio_callback diag0_cb; + struct k_work_delayable rampstat_callback_dwork; +}; + +struct tmc51xx_stepper_config { + const uint8_t index; + const uint16_t default_micro_step_res; + const int8_t sg_threshold; + const bool is_sg_enabled; + const uint32_t sg_velocity_check_interval_ms; + const uint32_t sg_threshold_velocity; + /* parent controller required for bus communication */ + const struct device *controller; +#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN + const struct tmc_ramp_generator_data default_ramp_config; +#endif +}; + +struct tmc51xx_stepper_data { + struct k_work_delayable stallguard_dwork; const struct device *stepper; stepper_event_callback_t callback; void *event_cb_user_data; diff --git a/drivers/stepper/fake_stepper_controller.c b/drivers/stepper/fake_stepper_controller.c index 3abce9726c50..72a0aed20d28 100644 --- a/drivers/stepper/fake_stepper_controller.c +++ b/drivers/stepper/fake_stepper_controller.c @@ -12,74 +12,51 @@ #include #endif /* CONFIG_ZTEST */ -#define DT_DRV_COMPAT zephyr_fake_stepper +#define DT_DRV_COMPAT zephyr_fake_stepper_controller -struct fake_stepper_data { - enum stepper_micro_step_resolution micro_step_res; +struct fake_stepper_controller_data { int32_t actual_position; }; -DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_enable, const struct device *); +DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_is_moving, const struct device *, uint8_t, bool *); -DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_disable, const struct device *); +DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_move_by, const struct device *, uint8_t, int32_t); -DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_is_moving, const struct device *, bool *); +DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_set_microstep_interval, const struct device *, uint8_t, + uint64_t); -DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_move_by, const struct device *, int32_t); +DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_set_reference_position, const struct device *, uint8_t, + int32_t); -DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_set_microstep_interval, const struct device *, uint64_t); +DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_get_actual_position, const struct device *, uint8_t, + int32_t *); -DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_set_micro_step_res, const struct device *, - enum stepper_micro_step_resolution); +DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_move_to, const struct device *, uint8_t, int32_t); -DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_get_micro_step_res, const struct device *, - enum stepper_micro_step_resolution *); +DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_run, const struct device *, uint8_t, + enum stepper_direction); -DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_set_reference_position, const struct device *, int32_t); +DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_stop, const struct device *, uint8_t); -DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_get_actual_position, const struct device *, int32_t *); - -DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_move_to, const struct device *, int32_t); - -DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_run, const struct device *, enum stepper_direction); - -DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_stop, const struct device *); - -DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_set_event_callback, const struct device *, +DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_set_event_callback, const struct device *, uint8_t, stepper_event_callback_t, void *); -static int fake_stepper_set_micro_step_res_delegate(const struct device *dev, - const enum stepper_micro_step_resolution res) -{ - struct fake_stepper_data *data = dev->data; - - data->micro_step_res = res; - - return 0; -} - -static int fake_stepper_get_micro_step_res_delegate(const struct device *dev, - enum stepper_micro_step_resolution *res) -{ - struct fake_stepper_data *data = dev->data; - - *res = data->micro_step_res; - - return 0; -} - -static int fake_stepper_set_reference_position_delegate(const struct device *dev, const int32_t pos) +static int fake_stepper_set_reference_position_delegate(const struct device *dev, + uint8_t stepper_idx, const int32_t pos) { - struct fake_stepper_data *data = dev->data; + ARG_UNUSED(stepper_idx); + struct fake_stepper_controller_data *data = dev->data; data->actual_position = pos; return 0; } -static int fake_stepper_get_actual_position_delegate(const struct device *dev, int32_t *pos) +static int fake_stepper_get_actual_position_delegate(const struct device *dev, uint8_t stepper_idx, + int32_t *pos) { - struct fake_stepper_data *data = dev->data; + ARG_UNUSED(stepper_idx); + struct fake_stepper_controller_data *data = dev->data; *pos = data->actual_position; @@ -87,18 +64,15 @@ static int fake_stepper_get_actual_position_delegate(const struct device *dev, i } #ifdef CONFIG_ZTEST -static void fake_stepper_reset_rule_before(const struct ztest_unit_test *test, void *fixture) +static void fake_stepper_controller_reset_rule_before(const struct ztest_unit_test *test, + void *fixture) { ARG_UNUSED(test); ARG_UNUSED(fixture); - RESET_FAKE(fake_stepper_enable); - RESET_FAKE(fake_stepper_disable); RESET_FAKE(fake_stepper_move_by); RESET_FAKE(fake_stepper_is_moving); RESET_FAKE(fake_stepper_set_microstep_interval); - RESET_FAKE(fake_stepper_set_micro_step_res); - RESET_FAKE(fake_stepper_get_micro_step_res); RESET_FAKE(fake_stepper_set_reference_position); RESET_FAKE(fake_stepper_get_actual_position); RESET_FAKE(fake_stepper_move_to); @@ -106,21 +80,17 @@ static void fake_stepper_reset_rule_before(const struct ztest_unit_test *test, v RESET_FAKE(fake_stepper_stop); /* Install custom fakes for the setter and getter functions */ - fake_stepper_set_micro_step_res_fake.custom_fake = fake_stepper_set_micro_step_res_delegate; - fake_stepper_get_micro_step_res_fake.custom_fake = fake_stepper_get_micro_step_res_delegate; fake_stepper_set_reference_position_fake.custom_fake = fake_stepper_set_reference_position_delegate; fake_stepper_get_actual_position_fake.custom_fake = fake_stepper_get_actual_position_delegate; } -ZTEST_RULE(fake_stepper_reset_rule, fake_stepper_reset_rule_before, NULL); +ZTEST_RULE(fake_stepper_controller_reset_rule, fake_stepper_controller_reset_rule_before, NULL); #endif /* CONFIG_ZTEST */ -static int fake_stepper_init(const struct device *dev) +static int fake_stepper_controller_init(const struct device *dev) { - fake_stepper_set_micro_step_res_fake.custom_fake = fake_stepper_set_micro_step_res_delegate; - fake_stepper_get_micro_step_res_fake.custom_fake = fake_stepper_get_micro_step_res_delegate; fake_stepper_set_reference_position_fake.custom_fake = fake_stepper_set_reference_position_delegate; fake_stepper_get_actual_position_fake.custom_fake = @@ -129,14 +99,10 @@ static int fake_stepper_init(const struct device *dev) return 0; } -static DEVICE_API(stepper, fake_stepper_driver_api) = { - .enable = fake_stepper_enable, - .disable = fake_stepper_disable, +static DEVICE_API(stepper, fake_stepper_controller_api) = { .move_by = fake_stepper_move_by, .is_moving = fake_stepper_is_moving, .set_microstep_interval = fake_stepper_set_microstep_interval, - .set_micro_step_res = fake_stepper_set_micro_step_res, - .get_micro_step_res = fake_stepper_get_micro_step_res, .set_reference_position = fake_stepper_set_reference_position, .get_actual_position = fake_stepper_get_actual_position, .move_to = fake_stepper_move_to, @@ -145,12 +111,10 @@ static DEVICE_API(stepper, fake_stepper_driver_api) = { .set_event_callback = fake_stepper_set_event_callback, }; -#define FAKE_STEPPER_INIT(inst) \ - \ - static struct fake_stepper_data fake_stepper_data_##inst; \ - \ - DEVICE_DT_INST_DEFINE(inst, fake_stepper_init, NULL, &fake_stepper_data_##inst, NULL, \ - POST_KERNEL, CONFIG_STEPPER_INIT_PRIORITY, \ - &fake_stepper_driver_api); +#define FAKE_STEPPER_CONTROLLER_INIT(inst) \ + static struct fake_stepper_controller_data fake_stepper_controller_data_##inst; \ + DEVICE_DT_INST_DEFINE(inst, fake_stepper_controller_init, NULL, \ + &fake_stepper_controller_data_##inst, NULL, POST_KERNEL, \ + CONFIG_STEPPER_INIT_PRIORITY, &fake_stepper_controller_api); -DT_INST_FOREACH_STATUS_OKAY(FAKE_STEPPER_INIT) +DT_INST_FOREACH_STATUS_OKAY(FAKE_STEPPER_CONTROLLER_INIT) diff --git a/drivers/stepper/fake_stepper_drv.c b/drivers/stepper/fake_stepper_drv.c new file mode 100644 index 000000000000..b3738df66d9d --- /dev/null +++ b/drivers/stepper/fake_stepper_drv.c @@ -0,0 +1,92 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 Fabian Blatz + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#ifdef CONFIG_ZTEST +#include +#endif /* CONFIG_ZTEST */ + +#define DT_DRV_COMPAT zephyr_fake_stepper + +struct fake_stepper_data { + enum stepper_micro_step_resolution micro_step_res; +}; + +DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_enable, const struct device *); + +DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_disable, const struct device *); + +DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_set_micro_step_res, const struct device *, + enum stepper_micro_step_resolution); + +DEFINE_FAKE_VALUE_FUNC(int, fake_stepper_get_micro_step_res, const struct device *, + enum stepper_micro_step_resolution *); + +static int fake_stepper_set_micro_step_res_delegate(const struct device *dev, + const enum stepper_micro_step_resolution res) +{ + struct fake_stepper_data *data = dev->data; + + data->micro_step_res = res; + + return 0; +} + +static int fake_stepper_get_micro_step_res_delegate(const struct device *dev, + enum stepper_micro_step_resolution *res) +{ + struct fake_stepper_data *data = dev->data; + + *res = data->micro_step_res; + + return 0; +} + +#ifdef CONFIG_ZTEST +static void fake_stepper_reset_rule_before(const struct ztest_unit_test *test, void *fixture) +{ + ARG_UNUSED(test); + ARG_UNUSED(fixture); + + RESET_FAKE(fake_stepper_enable); + RESET_FAKE(fake_stepper_disable); + RESET_FAKE(fake_stepper_set_micro_step_res); + RESET_FAKE(fake_stepper_get_micro_step_res); + + /* Install custom fakes for the setter and getter functions */ + fake_stepper_set_micro_step_res_fake.custom_fake = fake_stepper_set_micro_step_res_delegate; + fake_stepper_get_micro_step_res_fake.custom_fake = fake_stepper_get_micro_step_res_delegate; +} + +ZTEST_RULE(fake_stepper_reset_rule, fake_stepper_reset_rule_before, NULL); +#endif /* CONFIG_ZTEST */ + +static int fake_stepper_init(const struct device *dev) +{ + fake_stepper_set_micro_step_res_fake.custom_fake = fake_stepper_set_micro_step_res_delegate; + fake_stepper_get_micro_step_res_fake.custom_fake = fake_stepper_get_micro_step_res_delegate; + return 0; +} + +static DEVICE_API(stepper_drv, fake_stepper_driver_api) = { + .enable = fake_stepper_enable, + .disable = fake_stepper_disable, + .set_micro_step_res = fake_stepper_set_micro_step_res, + .get_micro_step_res = fake_stepper_get_micro_step_res, +}; + +#define FAKE_STEPPER_INIT(inst) \ + \ + static struct fake_stepper_data fake_stepper_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, fake_stepper_init, NULL, &fake_stepper_data_##inst, NULL, \ + POST_KERNEL, CONFIG_STEPPER_INIT_PRIORITY, \ + &fake_stepper_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(FAKE_STEPPER_INIT) diff --git a/drivers/stepper/stepper_shell.c b/drivers/stepper/stepper_shell.c index e18da9acb553..fe800f252cc6 100644 --- a/drivers/stepper/stepper_shell.c +++ b/drivers/stepper/stepper_shell.c @@ -14,8 +14,9 @@ LOG_MODULE_REGISTER(stepper_shell, CONFIG_STEPPER_LOG_LEVEL); enum { ARG_IDX_DEV = 1, - ARG_IDX_PARAM = 2, - ARG_IDX_VALUE = 3, + ARG_IDX_DEV_IDX = 2, + ARG_IDX_PARAM = 3, + ARG_IDX_VALUE = 4, }; struct stepper_microstep_map { @@ -40,8 +41,8 @@ struct stepper_direction_map { .microstep = _microstep, \ } -static void print_callback(const struct device *dev, const enum stepper_event event, - void *user_data) +static void print_callback(const struct device *dev, const uint8_t stepper_idx, + const enum stepper_event event, void *user_data) { const struct shell *sh = user_data; if (!sh) { @@ -185,7 +186,7 @@ static int cmd_stepper_enable(const struct shell *sh, size_t argc, char **argv) return err; } - err = stepper_enable(dev); + err = stepper_drv_enable(dev); if (err) { shell_error(sh, "Error: %d", err); } @@ -203,7 +204,7 @@ static int cmd_stepper_disable(const struct shell *sh, size_t argc, char **argv) return err; } - err = stepper_disable(dev); + err = stepper_drv_disable(dev); if (err) { shell_error(sh, "Error: %d", err); } @@ -240,6 +241,7 @@ static int cmd_stepper_move_by(const struct shell *sh, size_t argc, char **argv) const struct device *dev; int err = 0; + const uint8_t stepper_index = shell_strtol(argv[ARG_IDX_DEV_IDX], 10, &err); int32_t micro_steps = shell_strtol(argv[ARG_IDX_PARAM], 10, &err); if (err < 0) { @@ -251,12 +253,12 @@ static int cmd_stepper_move_by(const struct shell *sh, size_t argc, char **argv) return err; } - err = stepper_set_event_callback(dev, print_callback, (void *)sh); + err = stepper_set_event_callback(dev, stepper_index, print_callback, (void *)sh); if (err != 0) { shell_error(sh, "Failed to set callback: %d", err); } - err = stepper_move_by(dev, micro_steps); + err = stepper_move_by(dev, stepper_index, micro_steps); if (err) { shell_error(sh, "Error: %d", err); } @@ -268,6 +270,7 @@ static int cmd_stepper_set_microstep_interval(const struct shell *sh, size_t arg { const struct device *dev; int err = 0; + const uint8_t stepper_index = shell_strtol(argv[ARG_IDX_DEV_IDX], 10, &err); uint64_t step_interval = shell_strtoull(argv[ARG_IDX_PARAM], 10, &err); if (err < 0) { @@ -279,7 +282,7 @@ static int cmd_stepper_set_microstep_interval(const struct shell *sh, size_t arg return err; } - err = stepper_set_microstep_interval(dev, step_interval); + err = stepper_set_microstep_interval(dev, stepper_index, step_interval); if (err) { shell_error(sh, "Error: %d", err); } @@ -310,7 +313,7 @@ static int cmd_stepper_set_micro_step_res(const struct shell *sh, size_t argc, c return err; } - err = stepper_set_micro_step_res(dev, resolution); + err = stepper_drv_set_micro_stepper_res(dev, resolution); if (err) { shell_error(sh, "Error: %d", err); } @@ -329,7 +332,7 @@ static int cmd_stepper_get_micro_step_res(const struct shell *sh, size_t argc, c return err; } - err = stepper_get_micro_step_res(dev, µ_step_res); + err = stepper_drv_get_micro_step_res(dev, µ_step_res); if (err < 0) { shell_warn(sh, "Failed to get micro-step resolution: %d", err); } else { @@ -343,6 +346,7 @@ static int cmd_stepper_set_reference_position(const struct shell *sh, size_t arg { const struct device *dev; int err = 0; + const uint8_t stepper_index = shell_strtol(argv[ARG_IDX_DEV_IDX], 10, &err); int32_t position = shell_strtol(argv[ARG_IDX_PARAM], 10, &err); if (err < 0) { @@ -354,7 +358,7 @@ static int cmd_stepper_set_reference_position(const struct shell *sh, size_t arg return err; } - err = stepper_set_reference_position(dev, position); + err = stepper_set_reference_position(dev, stepper_index, position); if (err) { shell_error(sh, "Error: %d", err); } @@ -366,6 +370,7 @@ static int cmd_stepper_get_actual_position(const struct shell *sh, size_t argc, { const struct device *dev; int err; + const uint8_t stepper_index = shell_strtol(argv[ARG_IDX_DEV_IDX], 10, &err); int32_t actual_position; err = parse_device_arg(sh, argv, &dev); @@ -373,7 +378,7 @@ static int cmd_stepper_get_actual_position(const struct shell *sh, size_t argc, return err; } - err = stepper_get_actual_position(dev, &actual_position); + err = stepper_get_actual_position(dev, stepper_index, &actual_position); if (err < 0) { shell_warn(sh, "Failed to get actual position: %d", err); } else { @@ -387,6 +392,7 @@ static int cmd_stepper_move_to(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; int err = 0; + const uint8_t stepper_index = shell_strtol(argv[ARG_IDX_DEV_IDX], 10, &err); const int32_t position = shell_strtol(argv[ARG_IDX_PARAM], 10, &err); if (err < 0) { @@ -398,12 +404,12 @@ static int cmd_stepper_move_to(const struct shell *sh, size_t argc, char **argv) return err; } - err = stepper_set_event_callback(dev, print_callback, (void *)sh); + err = stepper_set_event_callback(dev, stepper_index, print_callback, (void *)sh); if (err != 0) { shell_error(sh, "Failed to set callback: %d", err); } - err = stepper_move_to(dev, position); + err = stepper_move_to(dev, stepper_index, position); if (err) { shell_error(sh, "Error: %d", err); } @@ -415,6 +421,7 @@ static int cmd_stepper_run(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; int err = -EINVAL; + const uint8_t stepper_index = shell_strtol(argv[ARG_IDX_DEV_IDX], 10, &err); enum stepper_direction direction = STEPPER_DIRECTION_POSITIVE; for (int i = 0; i < ARRAY_SIZE(stepper_direction_map); i++) { @@ -434,12 +441,12 @@ static int cmd_stepper_run(const struct shell *sh, size_t argc, char **argv) return err; } - err = stepper_set_event_callback(dev, print_callback, (void *)sh); + err = stepper_set_event_callback(dev, stepper_index, print_callback, (void *)sh); if (err != 0) { shell_error(sh, "Failed to set callback: %d", err); } - err = stepper_run(dev, direction); + err = stepper_run(dev, stepper_index, direction); if (err) { shell_error(sh, "Error: %d", err); return err; @@ -448,13 +455,13 @@ static int cmd_stepper_run(const struct shell *sh, size_t argc, char **argv) return 0; } -static int cmd_stepper_info(const struct shell *sh, size_t argc, char **argv) +static int cmd_stepper_control_info(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; int err; bool is_moving; int32_t actual_position; - enum stepper_micro_step_resolution micro_step_res; + const uint8_t stepper_index = shell_strtol(argv[ARG_IDX_DEV_IDX], 10, &err); err = parse_device_arg(sh, argv, &dev); if (err < 0) { @@ -464,25 +471,44 @@ static int cmd_stepper_info(const struct shell *sh, size_t argc, char **argv) shell_print(sh, "Stepper Info:"); shell_print(sh, "Device: %s", dev->name); - err = stepper_get_actual_position(dev, &actual_position); + err = stepper_get_actual_position(dev, stepper_index, &actual_position); if (err < 0) { shell_warn(sh, "Failed to get actual position: %d", err); } else { shell_print(sh, "Actual Position: %d", actual_position); } - err = stepper_get_micro_step_res(dev, µ_step_res); + err = stepper_is_moving(dev, stepper_index, &is_moving); if (err < 0) { - shell_warn(sh, "Failed to get micro-step resolution: %d", err); + shell_warn(sh, "Failed to check if the motor is moving: %d", err); } else { - shell_print(sh, "Micro-step Resolution: %d", micro_step_res); + shell_print(sh, "Is Moving: %s", is_moving ? "Yes" : "No"); + } + + return 0; +} + +static int cmd_stepper_info(const struct shell *sh, size_t argc, char **argv) +{ + const struct device *dev; + int err; + bool is_moving; + int32_t actual_position; + enum stepper_micro_step_resolution micro_step_res; + + err = parse_device_arg(sh, argv, &dev); + if (err < 0) { + return err; } - err = stepper_is_moving(dev, &is_moving); + shell_print(sh, "Stepper Info:"); + shell_print(sh, "Device: %s", dev->name); + + err = stepper_drv_get_micro_step_res(dev, µ_step_res); if (err < 0) { - shell_warn(sh, "Failed to check if the motor is moving: %d", err); + shell_warn(sh, "Failed to get micro-step resolution: %d", err); } else { - shell_print(sh, "Is Moving: %s", is_moving ? "Yes" : "No"); + shell_print(sh, "Micro-step Resolution: %d", micro_step_res); } return 0; @@ -497,19 +523,21 @@ SHELL_STATIC_SUBCMD_SET_CREATE( SHELL_CMD_ARG(get_micro_step_res, &dsub_pos_stepper_motor_name, "", cmd_stepper_get_micro_step_res, 2, 0), SHELL_CMD_ARG(set_reference_position, &dsub_pos_stepper_motor_name, " ", - cmd_stepper_set_reference_position, 3, 0), + cmd_stepper_set_reference_position, 4, 0), SHELL_CMD_ARG(get_actual_position, &dsub_pos_stepper_motor_name, "", - cmd_stepper_get_actual_position, 2, 0), + cmd_stepper_get_actual_position, 3, 0), SHELL_CMD_ARG(set_microstep_interval, &dsub_pos_stepper_motor_name, - " ", cmd_stepper_set_microstep_interval, 3, 0), + " ", cmd_stepper_set_microstep_interval, 4, 0), SHELL_CMD_ARG(move_by, &dsub_pos_stepper_motor_name, " ", - cmd_stepper_move_by, 3, 0), + cmd_stepper_move_by, 4, 0), SHELL_CMD_ARG(move_to, &dsub_pos_stepper_motor_name, " ", - cmd_stepper_move_to, 3, 0), + cmd_stepper_move_to, 4, 0), SHELL_CMD_ARG(run, &dsub_pos_stepper_motor_name_dir, " ", - cmd_stepper_run, 3, 0), - SHELL_CMD_ARG(stop, &dsub_pos_stepper_motor_name, "", cmd_stepper_stop, 2, 0), - SHELL_CMD_ARG(info, &dsub_pos_stepper_motor_name, "", cmd_stepper_info, 2, 0), + cmd_stepper_run, 4, 0), + SHELL_CMD_ARG(stop, &dsub_pos_stepper_motor_name, "", cmd_stepper_stop, 3, 0), + SHELL_CMD_ARG(info, &dsub_pos_stepper_motor_name, "", cmd_stepper_control_info, 3, + 0), + SHELL_CMD_ARG(info, &dsub_pos_stepper_motor_name, "", cmd_stepper_info, 3, 0), SHELL_SUBCMD_SET_END); SHELL_CMD_REGISTER(stepper, &stepper_cmds, "Stepper motor commands", NULL); diff --git a/drivers/stepper/zephyr_stepper_motion_controller.c b/drivers/stepper/zephyr_stepper_motion_controller.c index a6b65124c4ef..f5bc4c4f1fe2 100644 --- a/drivers/stepper/zephyr_stepper_motion_controller.c +++ b/drivers/stepper/zephyr_stepper_motion_controller.c @@ -14,6 +14,9 @@ #include LOG_MODULE_REGISTER(stepper_motion_control, CONFIG_STEPPER_LOG_LEVEL); +/* Currently only one stepper is supported by the motion controller */ +#define MAX_SUPPORTED_STEPPER 1 + struct stepper_motion_control_config { const struct device *stepper; const struct timing_source_config timing_config; @@ -48,7 +51,7 @@ void stepper_trigger_callback(const struct device *dev, enum stepper_event event } if (!k_is_in_isr()) { - data->callback(dev, event, data->event_cb_user_data); + data->callback(dev, MAX_SUPPORTED_STEPPER - 1, event, data->event_cb_user_data); return; } @@ -61,6 +64,7 @@ void stepper_trigger_callback(const struct device *dev, enum stepper_event event } ret = k_work_submit(&data->event_callback_work); + if (ret < 0) { LOG_ERR("Failed to submit work item: %d", ret); } @@ -84,7 +88,9 @@ static void stepper_work_event_handler(struct k_work *work) /* Run the callback */ if (data->callback != NULL) { - data->callback(data->dev, event, data->event_cb_user_data); + /* using MAX_SUPPORTED_STEPPER as currently only one stepper is supported */ + data->callback(data->dev, MAX_SUPPORTED_STEPPER - 1, event, + data->event_cb_user_data); } /* If there are more pending events, resubmit this work item to handle them */ @@ -107,8 +113,11 @@ static void update_direction_from_step_count(const struct device *dev) } } -static int z_stepper_motion_control_move_by(const struct device *dev, int32_t micro_steps) +static int z_stepper_motion_control_move_by(const struct device *dev, const uint8_t stepper_idx, + int32_t micro_steps) { + CHECK_STEPPER_IDX(dev, stepper_idx, MAX_SUPPORTED_STEPPER); + const struct stepper_motion_control_config *config = dev->config; struct stepper_motion_control_data *data = dev->data; @@ -135,20 +144,25 @@ static int z_stepper_motion_control_move_by(const struct device *dev, int32_t mi return 0; } -static int z_stepper_motion_control_move_to(const struct device *dev, int32_t micro_steps) +static int z_stepper_motion_control_move_to(const struct device *dev, const uint8_t stepper_idx, + int32_t micro_steps) { + CHECK_STEPPER_IDX(dev, stepper_idx, MAX_SUPPORTED_STEPPER); + struct stepper_motion_control_data *data = dev->data; int32_t steps_to_move; K_SPINLOCK(&data->lock) { steps_to_move = micro_steps - data->actual_position; } - return z_stepper_motion_control_move_by(dev, steps_to_move); + return z_stepper_motion_control_move_by(dev, stepper_idx, steps_to_move); } -static int z_stepper_motion_control_run(const struct device *dev, +static int z_stepper_motion_control_run(const struct device *dev, const uint8_t stepper_idx, const enum stepper_direction direction) { + CHECK_STEPPER_IDX(dev, stepper_idx, MAX_SUPPORTED_STEPPER); + const struct stepper_motion_control_config *config = dev->config; struct stepper_motion_control_data *data = dev->data; @@ -163,8 +177,10 @@ static int z_stepper_motion_control_run(const struct device *dev, return 0; } -static int z_stepper_motion_control_stop(const struct device *dev) +static int z_stepper_motion_control_stop(const struct device *dev, const uint8_t stepper_idx) { + CHECK_STEPPER_IDX(dev, stepper_idx, MAX_SUPPORTED_STEPPER); + const struct stepper_motion_control_config *config = dev->config; struct stepper_motion_control_data *data = dev->data; int ret; @@ -180,8 +196,11 @@ static int z_stepper_motion_control_stop(const struct device *dev) } static int z_stepper_motion_control_set_reference_position(const struct device *dev, + const uint8_t stepper_idx, int32_t position) { + CHECK_STEPPER_IDX(dev, stepper_idx, MAX_SUPPORTED_STEPPER); + struct stepper_motion_control_data *data = dev->data; K_SPINLOCK(&data->lock) { @@ -190,8 +209,12 @@ static int z_stepper_motion_control_set_reference_position(const struct device * return 0; } -static int z_stepper_motion_control_get_actual_position(const struct device *dev, int32_t *position) +static int z_stepper_motion_control_get_actual_position(const struct device *dev, + const uint8_t stepper_idx, + int32_t *position) { + CHECK_STEPPER_IDX(dev, stepper_idx, MAX_SUPPORTED_STEPPER); + struct stepper_motion_control_data *data = dev->data; K_SPINLOCK(&data->lock) { @@ -201,8 +224,11 @@ static int z_stepper_motion_control_get_actual_position(const struct device *dev } static int z_stepper_motion_control_set_step_interval(const struct device *dev, + const uint8_t stepper_idx, uint64_t microstep_interval_ns) { + CHECK_STEPPER_IDX(dev, stepper_idx, MAX_SUPPORTED_STEPPER); + const struct stepper_motion_control_config *config = dev->config; struct stepper_motion_control_data *data = dev->data; @@ -220,8 +246,11 @@ static int z_stepper_motion_control_set_step_interval(const struct device *dev, return 0; } -static int z_stepper_motion_control_is_moving(const struct device *dev, bool *is_moving) +static int z_stepper_motion_control_is_moving(const struct device *dev, const uint8_t stepper_idx, + bool *is_moving) { + CHECK_STEPPER_IDX(dev, stepper_idx, MAX_SUPPORTED_STEPPER); + const struct stepper_motion_control_config *config = dev->config; struct stepper_motion_control_data *data = dev->data; @@ -283,8 +312,11 @@ static void velocity_mode_task(const struct device *dev) } static int z_stepper_motion_control_set_event_callback(const struct device *dev, + const uint8_t stepper_idx, stepper_event_callback_t cb, void *user_data) { + CHECK_STEPPER_IDX(dev, stepper_idx, MAX_SUPPORTED_STEPPER); + struct stepper_motion_control_data *data = dev->data; K_SPINLOCK(&data->lock) { @@ -313,36 +345,6 @@ void stepper_handle_timing_signal(const struct device *dev) } } -static int z_stepper_motion_control_enable(const struct device *dev) -{ - const struct stepper_motion_control_config *config = dev->config; - - return stepper_drv_enable(config->stepper); -} - -static int z_stepper_motion_control_disable(const struct device *dev) -{ - const struct stepper_motion_control_config *config = dev->config; - - return stepper_drv_disable(config->stepper); -} - -static int z_stepper_motion_control_set_micro_step_res(const struct device *dev, - const enum stepper_micro_step_resolution res) -{ - const struct stepper_motion_control_config *config = dev->config; - - return stepper_drv_set_micro_stepper_res(config->stepper, res); -} - -static int z_stepper_motion_control_get_micro_step_res(const struct device *dev, - enum stepper_micro_step_resolution *res) -{ - const struct stepper_motion_control_config *config = dev->config; - - return stepper_drv_get_micro_step_res(config->stepper, res); -} - static int stepper_motion_control_init(const struct device *dev) { const struct stepper_motion_control_config *config = dev->config; @@ -371,10 +373,6 @@ static int stepper_motion_control_init(const struct device *dev) } static DEVICE_API(stepper, zephyr_stepper_motion_control_api) = { - .enable = z_stepper_motion_control_enable, - .disable = z_stepper_motion_control_disable, - .set_micro_step_res = z_stepper_motion_control_set_micro_step_res, - .get_micro_step_res = z_stepper_motion_control_get_micro_step_res, .move_to = z_stepper_motion_control_move_to, .move_by = z_stepper_motion_control_move_by, .run = z_stepper_motion_control_run, diff --git a/dts/bindings/stepper/adi/adi,tmc51xx-base.yaml b/dts/bindings/stepper/adi/adi,tmc51xx-base.yaml index 62def383cbaf..01b040eaef7b 100644 --- a/dts/bindings/stepper/adi/adi,tmc51xx-base.yaml +++ b/dts/bindings/stepper/adi/adi,tmc51xx-base.yaml @@ -9,31 +9,6 @@ include: property-allowlist: - en-pwm-mode - test-mode - - name: stepper.yaml - - name: adi,trinamic-ramp-generator.yaml - property-allowlist: - - vstart - - a1 - - v1 - - amax - - vmax - - dmax - - d1 - - vstop - - tzerowait - - thigh - - tcoolthrs - - tpwmthrs - - tpowerdown - - ihold - - irun - - iholddelay - - name: adi,trinamic-stallguard.yaml - property-allowlist: - - activate-stallguard2 - - stallguard2-threshold - - stallguard-threshold-velocity - - stallguard-velocity-check-interval-ms properties: "#address-cells": @@ -53,3 +28,34 @@ properties: Hint: µstep velocity v[Hz] µsteps / s v[Hz] = v[51xx] * ( fCLK[Hz]/2 / 2^23 ) where v[51xx] is the value written to the TMC51XX. + +child-binding: + include: + - name: stepper.yaml + - name: base.yaml + property-allowlist: + - reg + - name: adi,trinamic-ramp-generator.yaml + property-allowlist: + - vstart + - a1 + - v1 + - amax + - vmax + - dmax + - d1 + - vstop + - tzerowait + - thigh + - tcoolthrs + - tpwmthrs + - tpowerdown + - ihold + - irun + - iholddelay + - name: adi,trinamic-stallguard.yaml + property-allowlist: + - activate-stallguard2 + - stallguard2-threshold + - stallguard-threshold-velocity + - stallguard-velocity-check-interval-ms diff --git a/dts/bindings/stepper/zephyr,fake-stepper-controller.yaml b/dts/bindings/stepper/zephyr,fake-stepper-controller.yaml new file mode 100644 index 000000000000..d7feab796132 --- /dev/null +++ b/dts/bindings/stepper/zephyr,fake-stepper-controller.yaml @@ -0,0 +1,7 @@ +# Copyright (c) 2025 Jilay Sandeep Pandya +# SPDX-License-Identifier: Apache-2.0 + +description: | + A fake stepper controller for use as either a stub or a mock in testing. + +compatible: "zephyr,fake-stepper-controller" diff --git a/dts/bindings/stepper/zephyr,fake-stepper.yaml b/dts/bindings/stepper/zephyr,fake-stepper.yaml index 3c6d01ff0859..a32df4efd320 100644 --- a/dts/bindings/stepper/zephyr,fake-stepper.yaml +++ b/dts/bindings/stepper/zephyr,fake-stepper.yaml @@ -2,8 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 description: | - This binding provides a fake stepper controller for use as either a stub or a mock in - Zephyr testing. + A fake stepper for use as either a stub or a mock in Zephyr testing. compatible: "zephyr,fake-stepper" diff --git a/include/zephyr/drivers/stepper.h b/include/zephyr/drivers/stepper.h index f9cedaaed548..815991ba4e9e 100644 --- a/include/zephyr/drivers/stepper.h +++ b/include/zephyr/drivers/stepper.h @@ -66,6 +66,17 @@ enum stepper_micro_step_resolution { (res) == STEPPER_MICRO_STEP_64 || (res) == STEPPER_MICRO_STEP_128 || \ (res) == STEPPER_MICRO_STEP_256) +/** + * @brief Check if the stepper index is valid + * @param stepper_idx Stepper index to check + * @param max_num_stepper Maximum number of steppers supported by the device + * @param dev Pointer to the device structure + */ +#define CHECK_STEPPER_IDX(dev, stepper_idx, max_num_stepper) \ + __ASSERT(stepper_idx < max_num_stepper, \ + "Invalid stepper index %d, max is %d for device %s", stepper_idx, \ + max_num_stepper, dev->name) + /** * @brief Stepper Motor direction options */ @@ -111,62 +122,34 @@ enum stepper_event { * */ -/** - * @brief Enable the stepper driver. - * - * @see stepper_enable() for details. - */ -typedef int (*stepper_enable_t)(const struct device *dev); - -/** - * @brief Disable the stepper driver. - * - * @see stepper_disable() for details. - */ -typedef int (*stepper_disable_t)(const struct device *dev); - -/** - * @brief Set the micro-step resolution - * - * @see stepper_set_micro_step_res() for details. - */ -typedef int (*stepper_set_micro_step_res_t)(const struct device *dev, - const enum stepper_micro_step_resolution resolution); - -/** - * @brief Get the micro-step resolution - * - * @see stepper_get_micro_step_res() for details. - */ -typedef int (*stepper_get_micro_step_res_t)(const struct device *dev, - enum stepper_micro_step_resolution *resolution); - /** * @brief Set the reference position of the stepper * * @see stepper_set_actual_position() for details. */ -typedef int (*stepper_set_reference_position_t)(const struct device *dev, const int32_t value); +typedef int (*stepper_set_reference_position_t)(const struct device *dev, + const uint8_t stepper_index, const int32_t value); /** * @brief Get the actual a.k.a reference position of the stepper * * @see stepper_get_actual_position() for details. */ -typedef int (*stepper_get_actual_position_t)(const struct device *dev, int32_t *value); +typedef int (*stepper_get_actual_position_t)(const struct device *dev, const uint8_t stepper_index, + int32_t *value); /** * @brief Callback function for stepper events */ -typedef void (*stepper_event_callback_t)(const struct device *dev, const enum stepper_event event, - void *user_data); +typedef void (*stepper_event_callback_t)(const struct device *dev, const uint8_t stepper_index, + const enum stepper_event event, void *user_data); /** * @brief Set the callback function to be called when a stepper event occurs * * @see stepper_set_event_callback() for details. */ -typedef int (*stepper_set_event_callback_t)(const struct device *dev, +typedef int (*stepper_set_event_callback_t)(const struct device *dev, const uint8_t stepper_index, stepper_event_callback_t callback, void *user_data); /** @@ -175,50 +158,51 @@ typedef int (*stepper_set_event_callback_t)(const struct device *dev, * @see stepper_set_microstep_interval() for details. */ typedef int (*stepper_set_microstep_interval_t)(const struct device *dev, + const uint8_t stepper_index, const uint64_t microstep_interval_ns); /** * @brief Move the stepper relatively by a given number of micro-steps. * * @see stepper_move_by() for details. */ -typedef int (*stepper_move_by_t)(const struct device *dev, const int32_t micro_steps); +typedef int (*stepper_move_by_t)(const struct device *dev, const uint8_t stepper_index, + const int32_t micro_steps); /** * @brief Move the stepper to an absolute position in micro-steps. * * @see stepper_move_to() for details. */ -typedef int (*stepper_move_to_t)(const struct device *dev, const int32_t micro_steps); +typedef int (*stepper_move_to_t)(const struct device *dev, const uint8_t stepper_index, + const int32_t micro_steps); /** * @brief Run the stepper with a given step interval in a given direction * * @see stepper_run() for details. */ -typedef int (*stepper_run_t)(const struct device *dev, const enum stepper_direction direction); +typedef int (*stepper_run_t)(const struct device *dev, const uint8_t stepper_index, + const enum stepper_direction direction); /** * @brief Stop the stepper * * @see stepper_stop() for details. */ -typedef int (*stepper_stop_t)(const struct device *dev); +typedef int (*stepper_stop_t)(const struct device *dev, const uint8_t stepper_index); /** * @brief Is the target position fo the stepper reached * * @see stepper_is_moving() for details. */ -typedef int (*stepper_is_moving_t)(const struct device *dev, bool *is_moving); +typedef int (*stepper_is_moving_t)(const struct device *dev, const uint8_t stepper_index, + bool *is_moving); /** * @brief Stepper Driver API */ __subsystem struct stepper_driver_api { - stepper_enable_t enable; - stepper_disable_t disable; - stepper_set_micro_step_res_t set_micro_step_res; - stepper_get_micro_step_res_t get_micro_step_res; stepper_set_reference_position_t set_reference_position; stepper_get_actual_position_t get_actual_position; stepper_set_event_callback_t set_event_callback; @@ -234,150 +218,65 @@ __subsystem struct stepper_driver_api { * @endcond */ -/** - * @brief Enable stepper driver - * - * @details Enabling the driver shall switch on the power stage and energize the coils. - * - * @param dev pointer to the stepper driver instance - * - * @retval -EIO Error during Enabling - * @retval 0 Success - */ -__syscall int stepper_enable(const struct device *dev); - -static inline int z_impl_stepper_enable(const struct device *dev) -{ - const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api; - - return api->enable(dev); -} - -/** - * @brief Disable stepper driver - * - * @details Disabling the driver shall switch off the power stage and de-energize the coils. - * Disabling the stepper does not implicitly stop the stepper. If the motor shall not move after - * re-enabling the stepper than consider calling stepper_stop() before. - * - * @param dev pointer to the stepper driver instance - * - * @retval -ENOTSUP Disabling of driver is not supported. - * @retval -EIO Error during Disabling - * @retval 0 Success - */ -__syscall int stepper_disable(const struct device *dev); - -static inline int z_impl_stepper_disable(const struct device *dev) -{ - const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api; - - return api->disable(dev); -} - -/** - * @brief Set the micro-step resolution in stepper driver - * - * @param dev pointer to the stepper driver instance - * @param resolution micro-step resolution - * - * @retval -EIO General input / output error - * @retval -ENOSYS If not implemented by device driver - * @retval -EINVAL If the requested resolution is invalid - * @retval -ENOTSUP If the requested resolution is not supported - * @retval 0 Success - */ -__syscall int stepper_set_micro_step_res(const struct device *dev, - enum stepper_micro_step_resolution resolution); - -static inline int z_impl_stepper_set_micro_step_res(const struct device *dev, - enum stepper_micro_step_resolution resolution) -{ - const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api; - - if (api->set_micro_step_res == NULL) { - return -ENOSYS; - } - - if (!VALID_MICRO_STEP_RES(resolution)) { - return -EINVAL; - } - return api->set_micro_step_res(dev, resolution); -} - -/** - * @brief Get the micro-step resolution in stepper driver - * - * @param dev pointer to the stepper driver instance - * @param resolution micro-step resolution - * - * @retval -EIO General input / output error - * @retval -ENOSYS If not implemented by device driver - * @retval 0 Success - */ -__syscall int stepper_get_micro_step_res(const struct device *dev, - enum stepper_micro_step_resolution *resolution); - -static inline int z_impl_stepper_get_micro_step_res(const struct device *dev, - enum stepper_micro_step_resolution *resolution) -{ - const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api; - - if (api->get_micro_step_res == NULL) { - return -ENOSYS; - } - return api->get_micro_step_res(dev, resolution); -} - /** * @brief Set the reference position of the stepper * * @param dev Pointer to the stepper driver instance. + * @param stepper_index The index of the stepper to set the reference position for. * @param value The reference position to set in micro-steps. * * @retval -EIO General input / output error * @retval -ENOSYS If not implemented by device driver * @retval 0 Success */ -__syscall int stepper_set_reference_position(const struct device *dev, int32_t value); +__syscall int stepper_set_reference_position(const struct device *dev, const uint8_t stepper_index, + int32_t value); static inline int z_impl_stepper_set_reference_position(const struct device *dev, + const uint8_t stepper_index, const int32_t value) { + __ASSERT_NO_MSG(dev != NULL); const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api; if (api->set_reference_position == NULL) { return -ENOSYS; } - return api->set_reference_position(dev, value); + return api->set_reference_position(dev, stepper_index, value); } /** * @brief Get the actual a.k.a reference position of the stepper * * @param dev pointer to the stepper driver instance + * @param stepper_index The index of the stepper to get the actual position for. * @param value The actual position to get in micro-steps * * @retval -EIO General input / output error * @retval -ENOSYS If not implemented by device driver * @retval 0 Success */ -__syscall int stepper_get_actual_position(const struct device *dev, int32_t *value); +__syscall int stepper_get_actual_position(const struct device *dev, const uint8_t stepper_index, + int32_t *value); -static inline int z_impl_stepper_get_actual_position(const struct device *dev, int32_t *value) +static inline int z_impl_stepper_get_actual_position(const struct device *dev, + const uint8_t stepper_index, int32_t *value) { + __ASSERT_NO_MSG(dev != NULL); + __ASSERT_NO_MSG(value != NULL); const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api; if (api->get_actual_position == NULL) { return -ENOSYS; } - return api->get_actual_position(dev, value); + return api->get_actual_position(dev, stepper_index, value); } /** * @brief Set the callback function to be called when a stepper event occurs * * @param dev pointer to the stepper driver instance + * @param stepper_index The index of the stepper to set the event callback for. * @param callback Callback function to be called when a stepper event occurs * passing NULL will disable the callback * @param user_data User data to be passed to the callback function @@ -385,19 +284,21 @@ static inline int z_impl_stepper_get_actual_position(const struct device *dev, i * @retval -ENOSYS If not implemented by device driver * @retval 0 Success */ -__syscall int stepper_set_event_callback(const struct device *dev, +__syscall int stepper_set_event_callback(const struct device *dev, const uint8_t stepper_index, stepper_event_callback_t callback, void *user_data); static inline int z_impl_stepper_set_event_callback(const struct device *dev, + const uint8_t stepper_index, stepper_event_callback_t callback, void *user_data) { + __ASSERT_NO_MSG(dev != NULL); const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api; if (api->set_event_callback == NULL) { return -ENOSYS; } - return api->set_event_callback(dev, callback, user_data); + return api->set_event_callback(dev, stepper_index, callback, user_data); } /** @@ -407,6 +308,7 @@ static inline int z_impl_stepper_set_event_callback(const struct device *dev, * set_microstep_interval and move is required to set the stepper into motion. * * @param dev pointer to the stepper driver instance + * @param stepper_index The index of the stepper to set the microstep interval for. * @param microstep_interval_ns time interval between steps in nanoseconds * * @retval -EIO General input / output error @@ -414,18 +316,20 @@ static inline int z_impl_stepper_set_event_callback(const struct device *dev, * @retval -ENOSYS If not implemented by device driver * @retval 0 Success */ -__syscall int stepper_set_microstep_interval(const struct device *dev, +__syscall int stepper_set_microstep_interval(const struct device *dev, const uint8_t stepper_index, uint64_t microstep_interval_ns); static inline int z_impl_stepper_set_microstep_interval(const struct device *dev, + const uint8_t stepper_index, const uint64_t microstep_interval_ns) { + __ASSERT_NO_MSG(dev != NULL); const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api; if (api->set_microstep_interval == NULL) { return -ENOSYS; } - return api->set_microstep_interval(dev, microstep_interval_ns); + return api->set_microstep_interval(dev, stepper_index, microstep_interval_ns); } /** @@ -435,18 +339,22 @@ static inline int z_impl_stepper_set_microstep_interval(const struct device *dev * This function is non-blocking. * * @param dev pointer to the stepper driver instance + * @param stepper_index The index of the stepper to set the micro-steps for. * @param micro_steps target micro-steps to be moved from the current position * * @retval -EIO General input / output error * @retval 0 Success */ -__syscall int stepper_move_by(const struct device *dev, int32_t micro_steps); +__syscall int stepper_move_by(const struct device *dev, const uint8_t stepper_index, + int32_t micro_steps); -static inline int z_impl_stepper_move_by(const struct device *dev, const int32_t micro_steps) +static inline int z_impl_stepper_move_by(const struct device *dev, const uint8_t stepper_index, + const int32_t micro_steps) { + __ASSERT_NO_MSG(dev != NULL); const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api; - return api->move_by(dev, micro_steps); + return api->move_by(dev, stepper_index, micro_steps); } /** @@ -456,22 +364,26 @@ static inline int z_impl_stepper_move_by(const struct device *dev, const int32_t * This function is non-blocking. * * @param dev pointer to the stepper driver instance + * @param stepper_index The index of the stepper to set the target position for. * @param micro_steps target position to set in micro-steps * * @retval -EIO General input / output error * @retval -ENOSYS If not implemented by device driver * @retval 0 Success */ -__syscall int stepper_move_to(const struct device *dev, int32_t micro_steps); +__syscall int stepper_move_to(const struct device *dev, const uint8_t stepper_index, + int32_t micro_steps); -static inline int z_impl_stepper_move_to(const struct device *dev, const int32_t micro_steps) +static inline int z_impl_stepper_move_to(const struct device *dev, const uint8_t stepper_index, + const int32_t micro_steps) { + __ASSERT_NO_MSG(dev != NULL); const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api; if (api->move_to == NULL) { return -ENOSYS; } - return api->move_to(dev, micro_steps); + return api->move_to(dev, stepper_index, micro_steps); } /** @@ -482,23 +394,26 @@ static inline int z_impl_stepper_move_to(const struct device *dev, const int32_t * function is non-blocking. * * @param dev pointer to the stepper driver instance + * @param stepper_index The index of the stepper to run. * @param direction The direction to set * * @retval -EIO General input / output error * @retval -ENOSYS If not implemented by device driver * @retval 0 Success */ -__syscall int stepper_run(const struct device *dev, enum stepper_direction direction); +__syscall int stepper_run(const struct device *dev, const uint8_t stepper_index, + enum stepper_direction direction); -static inline int z_impl_stepper_run(const struct device *dev, +static inline int z_impl_stepper_run(const struct device *dev, const uint8_t stepper_index, const enum stepper_direction direction) { + __ASSERT_NO_MSG(dev != NULL); const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api; if (api->run == NULL) { return -ENOSYS; } - return api->run(dev, direction); + return api->run(dev, stepper_index, direction); } /** @@ -506,43 +421,50 @@ static inline int z_impl_stepper_run(const struct device *dev, * @details Cancel all active movements, however keep the coils energized. * * @param dev pointer to the stepper driver instance + * @param stepper_index The index of the stepper to stop. * * @retval -EIO General input / output error * @retval -ENOSYS If not implemented by device driver * @retval 0 Success */ -__syscall int stepper_stop(const struct device *dev); +__syscall int stepper_stop(const struct device *dev, const uint8_t stepper_index); -static inline int z_impl_stepper_stop(const struct device *dev) +static inline int z_impl_stepper_stop(const struct device *dev, const uint8_t stepper_index) { + __ASSERT_NO_MSG(dev != NULL); const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api; if (api->stop == NULL) { return -ENOSYS; } - return api->stop(dev); + return api->stop(dev, stepper_index); } /** * @brief Check if the stepper is currently moving * * @param dev pointer to the stepper driver instance + * @param stepper_index The index of the stepper to check if it is moving. * @param is_moving Pointer to a boolean to store the moving status of the stepper * * @retval -EIO General input / output error * @retval -ENOSYS If not implemented by device driver * @retval 0 Success */ -__syscall int stepper_is_moving(const struct device *dev, bool *is_moving); +__syscall int stepper_is_moving(const struct device *dev, const uint8_t stepper_index, + bool *is_moving); -static inline int z_impl_stepper_is_moving(const struct device *dev, bool *is_moving) +static inline int z_impl_stepper_is_moving(const struct device *dev, const uint8_t stepper_index, + bool *is_moving) { + __ASSERT_NO_MSG(dev != NULL); + __ASSERT_NO_MSG(is_moving != NULL); const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api; if (api->is_moving == NULL) { return -ENOSYS; } - return api->is_moving(dev, is_moving); + return api->is_moving(dev, stepper_index, is_moving); } /** @@ -654,6 +576,7 @@ __syscall int stepper_drv_enable(const struct device *dev); static inline int z_impl_stepper_drv_enable(const struct device *dev) { + __ASSERT_NO_MSG(dev != NULL); const struct stepper_drv_driver_api *api = (const struct stepper_drv_driver_api *)dev->api; return api->enable(dev); @@ -674,6 +597,7 @@ __syscall int stepper_drv_disable(const struct device *dev); static inline int z_impl_stepper_drv_disable(const struct device *dev) { + __ASSERT_NO_MSG(dev != NULL); const struct stepper_drv_driver_api *api = (const struct stepper_drv_driver_api *)dev->api; return api->disable(dev); @@ -696,6 +620,7 @@ __syscall int stepper_drv_step(const struct device *dev); static inline int z_impl_stepper_drv_step(const struct device *dev) { + __ASSERT_NO_MSG(dev != NULL); const struct stepper_drv_driver_api *api = (const struct stepper_drv_driver_api *)dev->api; return api->step(dev); @@ -718,6 +643,7 @@ __syscall int stepper_drv_set_direction(const struct device *dev, static inline int z_impl_stepper_drv_set_direction(const struct device *dev, const enum stepper_direction direction) { + __ASSERT_NO_MSG(dev != NULL); const struct stepper_drv_driver_api *api = (const struct stepper_drv_driver_api *)dev->api; if ((direction != STEPPER_DIRECTION_POSITIVE) && @@ -731,7 +657,7 @@ static inline int z_impl_stepper_drv_set_direction(const struct device *dev, * @brief Set the micro-step resolution in stepper driver * * @param dev pointer to the step dir driver instance - * @param resolution micro-step resolution + * @param res micro-step resolution * * @retval -EIO General input / output error * @retval -ENOSYS If not implemented by device driver @@ -739,41 +665,46 @@ static inline int z_impl_stepper_drv_set_direction(const struct device *dev, * @retval -ENOTSUP If the requested resolution is not supported * @retval 0 Success */ -__syscall int stepper_drv_set_micro_stepper_res(const struct device *dev, - enum stepper_micro_step_resolution resolution); +__syscall int stepper_drv_set_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution res); -static inline int -z_impl_stepper_drv_set_micro_stepper_res(const struct device *dev, - enum stepper_micro_step_resolution resolution) +static inline int z_impl_stepper_drv_set_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution res) { + __ASSERT_NO_MSG(dev != NULL); const struct stepper_drv_driver_api *api = (const struct stepper_drv_driver_api *)dev->api; - if (!VALID_MICRO_STEP_RES(resolution)) { + if (api->set_micro_step_res == NULL) { + return -ENOSYS; + } + + if (!VALID_MICRO_STEP_RES(res)) { return -EINVAL; } - return api->set_micro_step_res(dev, resolution); + return api->set_micro_step_res(dev, res); } /** * @brief Get the micro-step resolution in stepper driver * * @param dev pointer to the stepper_drv driver instance - * @param resolution micro-step resolution + * @param res micro-step resolution * * @retval -EIO General input / output error * @retval -ENOSYS If not implemented by device driver * @retval 0 Success */ __syscall int stepper_drv_get_micro_step_res(const struct device *dev, - enum stepper_micro_step_resolution *resolution); + enum stepper_micro_step_resolution *res); -static inline int -z_impl_stepper_drv_get_micro_step_res(const struct device *dev, - enum stepper_micro_step_resolution *resolution) +static inline int z_impl_stepper_drv_get_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution *res) { + __ASSERT_NO_MSG(dev != NULL); + __ASSERT_NO_MSG(res != NULL); const struct stepper_drv_driver_api *api = (const struct stepper_drv_driver_api *)dev->api; - return api->get_micro_step_res(dev, resolution); + return api->get_micro_step_res(dev, res); } /** @@ -793,6 +724,7 @@ __syscall int stepper_drv_set_fault_cb(const struct device *dev, stepper_drv_fau static inline int z_impl_stepper_drv_set_fault_cb(const struct device *dev, stepper_drv_fault_cb_t callback, void *user_data) { + __ASSERT_NO_MSG(dev != NULL); const struct stepper_drv_driver_api *api = (const struct stepper_drv_driver_api *)dev->api; if (api->set_fault_cb == NULL) { diff --git a/include/zephyr/drivers/stepper/stepper_fake.h b/include/zephyr/drivers/stepper/stepper_fake.h index 0dad709dc61a..722504b24949 100644 --- a/include/zephyr/drivers/stepper/stepper_fake.h +++ b/include/zephyr/drivers/stepper/stepper_fake.h @@ -18,29 +18,33 @@ DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_enable, const struct device *); DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_disable, const struct device *); -DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_move_by, const struct device *, int32_t); - -DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_set_microstep_interval, const struct device *, uint64_t); - DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_set_micro_step_res, const struct device *, enum stepper_micro_step_resolution); DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_get_micro_step_res, const struct device *, enum stepper_micro_step_resolution *); -DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_set_reference_position, const struct device *, int32_t); +DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_move_by, const struct device *, uint8_t, int32_t); + +DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_set_microstep_interval, const struct device *, uint8_t, + uint64_t); + +DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_set_reference_position, const struct device *, uint8_t, + int32_t); -DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_get_actual_position, const struct device *, int32_t *); +DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_get_actual_position, const struct device *, uint8_t, + int32_t *); -DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_move_to, const struct device *, int32_t); +DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_move_to, const struct device *, uint8_t, int32_t); -DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_is_moving, const struct device *, bool *); +DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_is_moving, const struct device *, uint8_t, bool *); -DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_run, const struct device *, enum stepper_direction); +DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_run, const struct device *, uint8_t, + enum stepper_direction); -DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_stop, const struct device *); +DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_stop, const struct device *, uint8_t); -DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_set_event_callback, const struct device *, +DECLARE_FAKE_VALUE_FUNC(int, fake_stepper_set_event_callback, const struct device *, uint8_t, stepper_event_callback_t, void *); #ifdef __cplusplus diff --git a/include/zephyr/drivers/stepper/stepper_trinamic.h b/include/zephyr/drivers/stepper/stepper_trinamic.h index 7a27ef8de9c8..c4f7e5382a32 100644 --- a/include/zephyr/drivers/stepper/stepper_trinamic.h +++ b/include/zephyr/drivers/stepper/stepper_trinamic.h @@ -194,36 +194,39 @@ struct tmc_ramp_generator_data { #define TMC_RAMP_DT_SPEC_GET_TMC51XX(node) \ { \ - TMC_RAMP_DT_SPEC_GET_COMMON(DT_DRV_INST(node)) \ - .tpowerdown = DT_INST_PROP(node, tpowerdown), \ - .tpwmthrs = DT_INST_PROP(node, tpwmthrs), \ - .tcoolthrs = DT_INST_PROP(node, tcoolthrs), \ - .thigh = DT_INST_PROP(node, thigh), \ + TMC_RAMP_DT_SPEC_GET_COMMON(node) \ + .tpowerdown = DT_PROP(node, tpowerdown), \ + .tpwmthrs = DT_PROP(node, tpwmthrs), \ + .tcoolthrs = DT_PROP(node, tcoolthrs), \ + .thigh = DT_PROP(node, thigh), \ } /** * @brief Configure Trinamic Stepper Ramp Generator * * @param dev Pointer to the stepper motor controller instance + * @param stepper_index The index of the stepper to set the ramp for. * @param ramp_data Pointer to a struct containing the required ramp parameters * * @retval -EIO General input / output error * @retval -ENOSYS If not implemented by device driver * @retval 0 Success */ -int tmc50xx_stepper_set_ramp(const struct device *dev, +int tmc50xx_stepper_set_ramp(const struct device *dev, const uint8_t stepper_index, const struct tmc_ramp_generator_data *ramp_data); /** * @brief Set the maximum velocity of the stepper motor * * @param dev Pointer to the stepper motor controller instance + * @param stepper_index The index of the stepper to set the maximum velocity for. * @param velocity Maximum velocity in microsteps per second. * * @retval -EIO General input / output error * @retval 0 Success */ -int tmc50xx_stepper_set_max_velocity(const struct device *dev, uint32_t velocity); +int tmc50xx_stepper_set_max_velocity(const struct device *dev, const uint8_t stepper_index, + const uint32_t velocity); /** * @} diff --git a/samples/drivers/stepper/generic/src/main.c b/samples/drivers/stepper/generic/src/main.c index c81798fa8224..aedafd960f20 100644 --- a/samples/drivers/stepper/generic/src/main.c +++ b/samples/drivers/stepper/generic/src/main.c @@ -12,6 +12,9 @@ #include LOG_MODULE_REGISTER(stepper, CONFIG_STEPPER_LOG_LEVEL); +/* Every motion controller must support at least one stepper */ +#define STEPPER_INDEX 0 + static const struct device *stepper_motion_controller = DEVICE_DT_GET(DT_ALIAS(stepper_motion_control)); @@ -32,8 +35,8 @@ static int32_t ping_pong_target_position = static K_SEM_DEFINE(stepper_generic_sem, 0, 1); -static void stepper_callback(const struct device *dev, const enum stepper_event event, - void *user_data) +static void stepper_callback(const struct device *dev, const uint8_t stepper_index, + const enum stepper_event event, void *user_data) { switch (event) { case STEPPER_EVENT_STEPS_COMPLETED: @@ -78,41 +81,47 @@ int main(void) return -ENODEV; } - stepper_set_event_callback(stepper_motion_controller, stepper_callback, NULL); - stepper_set_reference_position(stepper_motion_controller, 0); - stepper_set_microstep_interval(stepper_motion_controller, CONFIG_STEP_INTERVAL_NS); + stepper_set_event_callback(stepper_motion_controller, STEPPER_INDEX, stepper_callback, + NULL); + stepper_set_reference_position(stepper_motion_controller, STEPPER_INDEX, 0); + stepper_set_microstep_interval(stepper_motion_controller, STEPPER_INDEX, + CONFIG_STEP_INTERVAL_NS); for (;;) { k_sem_take(&stepper_generic_sem, K_FOREVER); switch (atomic_get(&stepper_mode)) { case STEPPER_MODE_ENABLE: - stepper_enable(stepper_motion_controller); + stepper_drv_enable(stepper_motion_controller); LOG_INF("mode: enable\n"); break; case STEPPER_MODE_STOP: - stepper_stop(stepper_motion_controller); + stepper_stop(stepper_motion_controller, STEPPER_INDEX); LOG_INF("mode: stop\n"); break; case STEPPER_MODE_ROTATE_CW: - stepper_run(stepper_motion_controller, STEPPER_DIRECTION_POSITIVE); + stepper_run(stepper_motion_controller, STEPPER_INDEX, + STEPPER_DIRECTION_POSITIVE); LOG_INF("mode: rotate cw\n"); break; case STEPPER_MODE_ROTATE_CCW: - stepper_run(stepper_motion_controller, STEPPER_DIRECTION_NEGATIVE); + stepper_run(stepper_motion_controller, STEPPER_INDEX, + STEPPER_DIRECTION_NEGATIVE); LOG_INF("mode: rotate ccw\n"); break; case STEPPER_MODE_PING_PONG_RELATIVE: ping_pong_target_position *= -1; - stepper_move_by(stepper_motion_controller, ping_pong_target_position); + stepper_move_by(stepper_motion_controller, STEPPER_INDEX, + ping_pong_target_position); LOG_INF("mode: ping pong relative\n"); break; case STEPPER_MODE_PING_PONG_ABSOLUTE: ping_pong_target_position *= -1; - stepper_move_to(stepper_motion_controller, ping_pong_target_position); + stepper_move_to(stepper_motion_controller, STEPPER_INDEX, + ping_pong_target_position); LOG_INF("mode: ping pong absolute\n"); break; case STEPPER_MODE_DISABLE: - stepper_disable(stepper_motion_controller); + stepper_drv_disable(stepper_motion_controller); LOG_INF("mode: disable\n"); break; } @@ -125,7 +134,8 @@ static void monitor_thread(void) for (;;) { int32_t actual_position; - stepper_get_actual_position(stepper_motion_controller, &actual_position); + stepper_get_actual_position(stepper_motion_controller, STEPPER_INDEX, + &actual_position); LOG_DBG("Actual position: %d\n", actual_position); k_sleep(K_MSEC(CONFIG_MONITOR_THREAD_TIMEOUT_MS)); } diff --git a/samples/drivers/stepper/tmc50xx/boards/nucleo_g071rb.overlay b/samples/drivers/stepper/tmc50xx/boards/nucleo_g071rb.overlay index e3b70a355314..fe0be5b0db36 100644 --- a/samples/drivers/stepper/tmc50xx/boards/nucleo_g071rb.overlay +++ b/samples/drivers/stepper/tmc50xx/boards/nucleo_g071rb.overlay @@ -1,6 +1,7 @@ / { aliases { stepper = &tmc_stepper; + stepper-motion-control = &tmc50xx; }; }; diff --git a/samples/drivers/stepper/tmc50xx/src/main.c b/samples/drivers/stepper/tmc50xx/src/main.c index 8604f610c967..451c9195fdf2 100644 --- a/samples/drivers/stepper/tmc50xx/src/main.c +++ b/samples/drivers/stepper/tmc50xx/src/main.c @@ -10,14 +10,19 @@ #include const struct device *stepper = DEVICE_DT_GET(DT_ALIAS(stepper)); +const struct device *stepper_controller = DEVICE_DT_GET(DT_ALIAS(stepper_motion_control)); +const uint8_t stepper_index = DT_REG_ADDR(DT_ALIAS(stepper)); -int32_t ping_pong_target_position = CONFIG_STEPS_PER_REV * CONFIG_PING_PONG_N_REV * - DT_PROP(DT_ALIAS(stepper), micro_step_res); +int32_t ping_pong_target_position = + CONFIG_STEPS_PER_REV * CONFIG_PING_PONG_N_REV * DT_PROP(DT_ALIAS(stepper), micro_step_res); K_SEM_DEFINE(steps_completed_sem, 0, 1); -void stepper_callback(const struct device *dev, const enum stepper_event event, void *user_data) +void stepper_callback(const struct device *dev, const uint8_t stepper_idx, + const enum stepper_event event, void *user_data) { + ARG_UNUSED(stepper_idx); + ARG_UNUSED(user_data); switch (event) { case STEPPER_EVENT_STEPS_COMPLETED: k_sem_give(&steps_completed_sem); @@ -36,19 +41,35 @@ int main(void) } printf("stepper is %p, name is %s\n", stepper, stepper->name); - stepper_set_event_callback(stepper, stepper_callback, NULL); - stepper_enable(stepper); - stepper_set_reference_position(stepper, 0); - stepper_move_by(stepper, ping_pong_target_position); + stepper_set_event_callback(stepper_controller, stepper_index, stepper_callback, NULL); + stepper_drv_enable(stepper); + + enum stepper_micro_step_resolution micro_step_res; + + stepper_drv_get_micro_step_res(stepper, µ_step_res); + printf("Microstep resolution is %d\n", micro_step_res); + + stepper_set_reference_position(stepper_controller, stepper_index, 0); + stepper_move_by(stepper_controller, stepper_index, ping_pong_target_position); /* Change Max Velocity during runtime */ int32_t tmc_velocity = DT_PROP(DT_ALIAS(stepper), vmax) * CONFIG_MAX_VELOCITY_MULTIPLIER; - (void)tmc50xx_stepper_set_max_velocity(stepper, tmc_velocity); + (void)tmc50xx_stepper_set_max_velocity(stepper_controller, stepper_index, tmc_velocity); for (;;) { if (k_sem_take(&steps_completed_sem, K_FOREVER) == 0) { ping_pong_target_position *= -1; - stepper_move_by(stepper, ping_pong_target_position); + stepper_move_by(stepper_controller, stepper_index, + ping_pong_target_position); + + int32_t actual_position; + + if (stepper_get_actual_position(stepper_controller, stepper_index, + &actual_position) == 0) { + printf("Actual position: %d\n", actual_position); + } else { + printf("Failed to get actual position\n"); + } } } return 0; diff --git a/tests/drivers/build_all/stepper/app.overlay b/tests/drivers/build_all/stepper/app.overlay index 33dfe04d09bc..d14fa6e9830c 100644 --- a/tests/drivers/build_all/stepper/app.overlay +++ b/tests/drivers/build_all/stepper/app.overlay @@ -43,7 +43,6 @@ zephyr_stepper_motion_control_counter: zephyr_stepper_motion_control_counter { compatible = "zephyr,stepper-motion-control"; status = "okay"; - counter = <&counter0>; stepper = <&zephyr_h_bridge_stepper>; }; diff --git a/tests/drivers/build_all/stepper/spi.dtsi b/tests/drivers/build_all/stepper/spi.dtsi index 0f6bfbc13db3..4d848a5d9931 100644 --- a/tests/drivers/build_all/stepper/spi.dtsi +++ b/tests/drivers/build_all/stepper/spi.dtsi @@ -6,6 +6,8 @@ * PLEASE KEEP REG ADDRESSES SEQUENTIAL * ***************************************/ +#include + adi_tmc50xx: adi_tmc50xx@0 { compatible = "adi,tmc50xx"; status = "okay"; @@ -94,31 +96,37 @@ adi_tmc51xx_1: adi_tmc51xx@1 { clock-frequency = <16000000>; /* Internal/External Clock frequency */ /* common stepper controller settings */ - invert-direction; - micro-step-res = <256>; - - /* ADI TMC stallguard settings specific to TMC5160 */ - activate-stallguard2; - stallguard-velocity-check-interval-ms = <100>; - stallguard2-threshold = <9>; - stallguard-threshold-velocity = <50000>; - - /* ADI TMC ramp generator as well as current settings */ - vstart = <10>; - a1 = <20>; - v1 = <30>; - d1 = <40>; - vmax = <50>; - amax = <60>; - dmax = <70>; - tzerowait = <80>; - thigh = <90>; - tcoolthrs = <100>; - tpwmthrs = <110>; - tpowerdown = <120>; - ihold = <1>; - irun = <2>; - iholddelay = <3>; + tmc51xx_1: tmc51xx_1@0 { + status = "okay"; + reg = <0>; + + /* common stepper controller settings */ + invert-direction; + micro-step-res = <256>; + + /* ADI TMC stallguard settings specific to TMC5160 */ + activate-stallguard2; + stallguard-velocity-check-interval-ms = <100>; + stallguard2-threshold = <9>; + stallguard-threshold-velocity = <50000>; + + /* ADI TMC ramp generator as well as current settings */ + vstart = <10>; + a1 = <20>; + v1 = <30>; + d1 = <40>; + vmax = <50>; + amax = <60>; + dmax = <70>; + tzerowait = <80>; + thigh = <90>; + tcoolthrs = <100>; + tpwmthrs = <110>; + tpowerdown = <120>; + ihold = <1>; + irun = <2>; + iholddelay = <3>; + }; }; adi_tmc51xx_2: adi_tmc51xx@2 { @@ -135,30 +143,33 @@ adi_tmc51xx_2: adi_tmc51xx@2 { en-pwm-mode; test-mode; /* ADI TMC Global configuration flags */ clock-frequency = <16000000>; /* Internal/External Clock frequency */ - /* common stepper controller settings */ - invert-direction; - micro-step-res = <256>; - - /* ADI TMC stallguard settings specific to TMC5160 */ - activate-stallguard2; - stallguard-velocity-check-interval-ms = <100>; - stallguard2-threshold = <9>; - stallguard-threshold-velocity = <50000>; - - /* ADI TMC ramp generator as well as current settings */ - vstart = <10>; - a1 = <20>; - v1 = <30>; - d1 = <40>; - vmax = <50>; - amax = <60>; - dmax = <70>; - tzerowait = <80>; - thigh = <90>; - tcoolthrs = <100>; - tpwmthrs = <110>; - tpowerdown = <120>; - ihold = <1>; - irun = <2>; - iholddelay = <3>; + tmc51xx_2: tmc51xx_2@0 { + status = "okay"; + reg = <0>; + micro-step-res = <256>; + invert-direction; + + /* ADI TMC stallguard settings specific to TMC5160 */ + activate-stallguard2; + stallguard-velocity-check-interval-ms = <100>; + stallguard2-threshold = <9>; + stallguard-threshold-velocity = <50000>; + + /* ADI TMC ramp generator as well as current settings */ + vstart = <10>; + a1 = <20>; + v1 = <30>; + d1 = <40>; + vmax = <50>; + amax = <60>; + dmax = <70>; + tzerowait = <80>; + thigh = <90>; + tcoolthrs = <100>; + tpwmthrs = <110>; + tpowerdown = <120>; + ihold = <1>; + irun = <2>; + iholddelay = <3>; + }; }; diff --git a/tests/drivers/build_all/stepper/uart.dtsi b/tests/drivers/build_all/stepper/uart.dtsi index e2116bae1f42..8af9beb9c5c5 100644 --- a/tests/drivers/build_all/stepper/uart.dtsi +++ b/tests/drivers/build_all/stepper/uart.dtsi @@ -14,31 +14,37 @@ adi_tmc51xx_uart: adi_tmc51xx { en-pwm-mode; test-mode; /* ADI TMC Global configuration flags */ clock-frequency = <16000000>; /* Internal/External Clock frequency */ + #address-cells = <1>; + #size-cells = <0>; - /* common stepper controller settings */ - invert-direction; - micro-step-res = <256>; + tmc5160_1: tmc5160_1@0 { + status = "okay"; + reg = <0>; + /* micro-stepping resolution */ + micro-step-res = <256>; + invert-direction; - /* ADI TMC stallguard settings specific to TMC5160 */ - activate-stallguard2; - stallguard-velocity-check-interval-ms = <100>; - stallguard2-threshold = <9>; - stallguard-threshold-velocity = <50000>; + /* ADI TMC stallguard settings specific to TMC5160 */ + activate-stallguard2; + stallguard-velocity-check-interval-ms = <100>; + stallguard2-threshold = <9>; + stallguard-threshold-velocity = <50000>; - /* ADI TMC ramp generator as well as current settings */ - vstart = <10>; - a1 = <20>; - v1 = <30>; - d1 = <40>; - vmax = <50>; - amax = <60>; - dmax = <70>; - tzerowait = <80>; - thigh = <90>; - tcoolthrs = <100>; - tpwmthrs = <110>; - tpowerdown = <120>; - ihold = <1>; - irun = <2>; - iholddelay = <3>; + /* ADI TMC ramp generator as well as current settings */ + vstart = <10>; + a1 = <20>; + v1 = <30>; + d1 = <40>; + vmax = <50>; + amax = <60>; + dmax = <70>; + tzerowait = <80>; + thigh = <90>; + tcoolthrs = <100>; + tpwmthrs = <110>; + tpowerdown = <120>; + ihold = <1>; + irun = <2>; + iholddelay = <3>; + }; }; diff --git a/tests/drivers/stepper/drv84xx/api/Kconfig b/tests/drivers/stepper/drv84xx/api/Kconfig index 40415c3edbca..af5d21ee62ab 100644 --- a/tests/drivers/stepper/drv84xx/api/Kconfig +++ b/tests/drivers/stepper/drv84xx/api/Kconfig @@ -6,4 +6,10 @@ config ENTROPY_GENERATOR bool "Shuffle the order of tests and suites" default y +config STEPPER_IDX + int "Stepper index" + default 0 + help + Index of the stepper device to test. + source "Kconfig.zephyr" diff --git a/tests/drivers/stepper/drv84xx/api/src/main.c b/tests/drivers/stepper/drv84xx/api/src/main.c index d8f0aa69028e..bdc94f5ab1b5 100644 --- a/tests/drivers/stepper/drv84xx/api/src/main.c +++ b/tests/drivers/stepper/drv84xx/api/src/main.c @@ -20,8 +20,8 @@ struct drv84xx_api_fixture { struct k_poll_signal stepper_signal; struct k_poll_event stepper_event; -static void drv84xx_api_print_event_callback(const struct device *dev, enum stepper_event event, - void *dummy) +static void drv84xx_api_print_event_callback(const struct device *dev, const uint8_t stepper_idx, + enum stepper_event event, void *dummy) { switch (event) { case STEPPER_EVENT_STEPS_COMPLETED: @@ -59,42 +59,18 @@ static void *drv84xx_api_setup(void) static void drv84xx_api_before(void *f) { struct drv84xx_api_fixture *fixture = f; - (void)stepper_set_reference_position(fixture->dev, 0); - (void)stepper_set_micro_step_res(fixture->dev, 1); + (void)stepper_set_reference_position(fixture->dev, CONFIG_STEPPER_IDX, 0); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, 20000000); k_poll_signal_reset(&stepper_signal); } -static void drv84xx_api_after(void *f) -{ - struct drv84xx_api_fixture *fixture = f; - (void)stepper_disable(fixture->dev); -} - -ZTEST_F(drv84xx_api, test_micro_step_res_set) -{ - (void)stepper_set_micro_step_res(fixture->dev, 4); - enum stepper_micro_step_resolution res; - (void)stepper_get_micro_step_res(fixture->dev, &res); - zassert_equal(res, 4, "Micro step resolution not set correctly, should be %d but is %d", 4, - res); -} - -ZTEST_F(drv84xx_api, test_actual_position_set) -{ - int32_t pos = 100u; - (void)stepper_set_reference_position(fixture->dev, pos); - (void)stepper_get_actual_position(fixture->dev, &pos); - zassert_equal(pos, 100u, "Actual position should be %u but is %u", 100u, pos); -} - ZTEST_F(drv84xx_api, test_move_to_positive_direction_movement) { int32_t pos = 50; - (void)stepper_enable(fixture->dev); - (void)stepper_set_microstep_interval(fixture->dev, 20000000); - (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL); - (void)stepper_move_to(fixture->dev, pos); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, 20000000); + (void)stepper_set_event_callback(fixture->dev, CONFIG_STEPPER_IDX, fixture->callback, NULL); + (void)stepper_move_to(fixture->dev, CONFIG_STEPPER_IDX, pos); (void)k_poll(&stepper_event, 1, K_SECONDS(5)); unsigned int signaled; int result; @@ -103,7 +79,7 @@ ZTEST_F(drv84xx_api, test_move_to_positive_direction_movement) zassert_equal(signaled, 1, "No event detected"); zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED, "Event was not STEPPER_EVENT_STEPS_COMPLETED event"); - (void)stepper_get_actual_position(fixture->dev, &pos); + (void)stepper_get_actual_position(fixture->dev, CONFIG_STEPPER_IDX, &pos); zassert_equal(pos, 50u, "Target position should be %d but is %d", 50u, pos); } @@ -111,10 +87,9 @@ ZTEST_F(drv84xx_api, test_move_to_negative_direction_movement) { int32_t pos = -50; - (void)stepper_enable(fixture->dev); - (void)stepper_set_microstep_interval(fixture->dev, 20000000); - (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL); - (void)stepper_move_to(fixture->dev, pos); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, 20000000); + (void)stepper_set_event_callback(fixture->dev, CONFIG_STEPPER_IDX, fixture->callback, NULL); + (void)stepper_move_to(fixture->dev, CONFIG_STEPPER_IDX, pos); (void)k_poll(&stepper_event, 1, K_SECONDS(5)); unsigned int signaled; int result; @@ -123,7 +98,7 @@ ZTEST_F(drv84xx_api, test_move_to_negative_direction_movement) zassert_equal(signaled, 1, "No event detected"); zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED, "Event was not STEPPER_EVENT_STEPS_COMPLETED event"); - (void)stepper_get_actual_position(fixture->dev, &pos); + (void)stepper_get_actual_position(fixture->dev, CONFIG_STEPPER_IDX, &pos); zassert_equal(pos, -50, "Target position should be %d but is %d", -50, pos); } @@ -131,10 +106,9 @@ ZTEST_F(drv84xx_api, test_move_to_identical_current_and_target_position) { int32_t pos = 0; - (void)stepper_enable(fixture->dev); - (void)stepper_set_microstep_interval(fixture->dev, 20000000); - (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL); - (void)stepper_move_to(fixture->dev, pos); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, 20000000); + (void)stepper_set_event_callback(fixture->dev, CONFIG_STEPPER_IDX, fixture->callback, NULL); + (void)stepper_move_to(fixture->dev, CONFIG_STEPPER_IDX, pos); (void)k_poll(&stepper_event, 1, K_SECONDS(5)); unsigned int signaled; int result; @@ -143,7 +117,7 @@ ZTEST_F(drv84xx_api, test_move_to_identical_current_and_target_position) zassert_equal(signaled, 1, "No event detected"); zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED, "Event was not STEPPER_EVENT_STEPS_COMPLETED event"); - (void)stepper_get_actual_position(fixture->dev, &pos); + (void)stepper_get_actual_position(fixture->dev, CONFIG_STEPPER_IDX, &pos); zassert_equal(pos, 0, "Target position should not have changed from %d but is %d", 0, pos); } @@ -152,11 +126,10 @@ ZTEST_F(drv84xx_api, test_move_to_is_moving_true_while_moving) int32_t pos = 50; bool moving = false; - (void)stepper_enable(fixture->dev); - (void)stepper_set_microstep_interval(fixture->dev, 20000000); - (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL); - (void)stepper_move_to(fixture->dev, pos); - (void)stepper_is_moving(fixture->dev, &moving); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, 20000000); + (void)stepper_set_event_callback(fixture->dev, CONFIG_STEPPER_IDX, fixture->callback, NULL); + (void)stepper_move_to(fixture->dev, CONFIG_STEPPER_IDX, pos); + (void)stepper_is_moving(fixture->dev, CONFIG_STEPPER_IDX, &moving); zassert_true(moving, "Driver should be in state is_moving while moving"); } @@ -165,10 +138,9 @@ ZTEST_F(drv84xx_api, test_move_to_is_moving_false_when_completed) int32_t pos = 50; bool moving = false; - (void)stepper_enable(fixture->dev); - (void)stepper_set_microstep_interval(fixture->dev, 20000000); - (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL); - (void)stepper_move_to(fixture->dev, pos); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, 20000000); + (void)stepper_set_event_callback(fixture->dev, CONFIG_STEPPER_IDX, fixture->callback, NULL); + (void)stepper_move_to(fixture->dev, CONFIG_STEPPER_IDX, pos); (void)k_poll(&stepper_event, 1, K_SECONDS(5)); unsigned int signaled; int result; @@ -177,7 +149,7 @@ ZTEST_F(drv84xx_api, test_move_to_is_moving_false_when_completed) zassert_equal(signaled, 1, "No event detected"); zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED, "Event was not STEPPER_EVENT_STEPS_COMPLETED event"); - (void)stepper_is_moving(fixture->dev, &moving); + (void)stepper_is_moving(fixture->dev, CONFIG_STEPPER_IDX, &moving); zassert_false(moving, "Driver should not be in state is_moving after finishing"); } @@ -185,10 +157,9 @@ ZTEST_F(drv84xx_api, test_move_by_zero_steps_no_movement) { int32_t steps = 0; - (void)stepper_enable(fixture->dev); - (void)stepper_set_microstep_interval(fixture->dev, 20000000); - (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL); - (void)stepper_move_by(fixture->dev, steps); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, 20000000); + (void)stepper_set_event_callback(fixture->dev, CONFIG_STEPPER_IDX, fixture->callback, NULL); + (void)stepper_move_by(fixture->dev, CONFIG_STEPPER_IDX, steps); (void)k_poll(&stepper_event, 1, K_SECONDS(5)); unsigned int signaled; int result; @@ -197,7 +168,7 @@ ZTEST_F(drv84xx_api, test_move_by_zero_steps_no_movement) zassert_equal(signaled, 1, "No event detected"); zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED, "Event was not STEPPER_EVENT_STEPS_COMPLETED event"); - (void)stepper_get_actual_position(fixture->dev, &steps); + (void)stepper_get_actual_position(fixture->dev, CONFIG_STEPPER_IDX, &steps); zassert_equal(steps, 0, "Target position should be %d but is %d", 0, steps); } @@ -206,23 +177,21 @@ ZTEST_F(drv84xx_api, test_move_by_is_moving_true_while_moving) int32_t steps = 50; bool moving = false; - (void)stepper_enable(fixture->dev); - (void)stepper_set_microstep_interval(fixture->dev, 20000000); - (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL); - (void)stepper_move_by(fixture->dev, steps); - (void)stepper_is_moving(fixture->dev, &moving); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, 20000000); + (void)stepper_set_event_callback(fixture->dev, CONFIG_STEPPER_IDX, fixture->callback, NULL); + (void)stepper_move_by(fixture->dev, CONFIG_STEPPER_IDX, steps); + (void)stepper_is_moving(fixture->dev, CONFIG_STEPPER_IDX, &moving); zassert_true(moving, "Driver should be in state is_moving"); } ZTEST_F(drv84xx_api, test_move_by_is_moving_false_when_completed) { - int32_t steps = 50; + int32_t steps = 10; bool moving = true; - (void)stepper_enable(fixture->dev); - (void)stepper_set_microstep_interval(fixture->dev, 20000000); - (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL); - (void)stepper_move_by(fixture->dev, steps); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, 20000000); + (void)stepper_set_event_callback(fixture->dev, CONFIG_STEPPER_IDX, fixture->callback, NULL); + (void)stepper_move_by(fixture->dev, CONFIG_STEPPER_IDX, steps); (void)k_poll(&stepper_event, 1, K_SECONDS(5)); unsigned int signaled; int result; @@ -231,7 +200,7 @@ ZTEST_F(drv84xx_api, test_move_by_is_moving_false_when_completed) zassert_equal(signaled, 1, "No event detected"); zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED, "Event was not STEPPER_EVENT_STEPS_COMPLETED event"); - (void)stepper_is_moving(fixture->dev, &moving); + (void)stepper_is_moving(fixture->dev, CONFIG_STEPPER_IDX, &moving); zassert_false(moving, "Driver should not be in state is_moving after completion"); } @@ -240,13 +209,12 @@ ZTEST_F(drv84xx_api, test_run_positive_direction_correct_position) uint64_t step_interval = 20000000; int32_t steps = 0; - (void)stepper_enable(fixture->dev); - (void)stepper_set_microstep_interval(fixture->dev, step_interval); - (void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, step_interval); + (void)stepper_run(fixture->dev, CONFIG_STEPPER_IDX, STEPPER_DIRECTION_POSITIVE); k_busy_wait(110000); - (void)stepper_get_actual_position(fixture->dev, &steps); - zassert_true(IN_RANGE(steps, 4, 6), "Current position should be between 4 and 6 but is %d", + (void)stepper_get_actual_position(fixture->dev, CONFIG_STEPPER_IDX, &steps); + zassert_true(IN_RANGE(steps, 1, 6), "Current position should be between 4 and 6 but is %d", steps); } @@ -255,13 +223,12 @@ ZTEST_F(drv84xx_api, test_run_negative_direction_correct_position) uint64_t step_interval = 20000000; int32_t steps = 0; - (void)stepper_enable(fixture->dev); - (void)stepper_set_microstep_interval(fixture->dev, step_interval); - (void)stepper_run(fixture->dev, STEPPER_DIRECTION_NEGATIVE); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, step_interval); + (void)stepper_run(fixture->dev, CONFIG_STEPPER_IDX, STEPPER_DIRECTION_NEGATIVE); k_busy_wait(110000); - (void)stepper_get_actual_position(fixture->dev, &steps); - zassert_true(IN_RANGE(steps, -6, 4), + (void)stepper_get_actual_position(fixture->dev, CONFIG_STEPPER_IDX, &steps); + zassert_true(IN_RANGE(steps, -6, -1), "Current position should be between -6 and -4 but is %d", steps); } @@ -270,9 +237,8 @@ ZTEST_F(drv84xx_api, test_run_zero_step_interval_correct_position) uint64_t step_interval = 0; int32_t steps = 0; - (void)stepper_enable(fixture->dev); - (void)stepper_set_microstep_interval(fixture->dev, step_interval); - (void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, step_interval); + (void)stepper_run(fixture->dev, CONFIG_STEPPER_IDX, STEPPER_DIRECTION_POSITIVE); k_msleep(100); zassert_equal(steps, 0, "Current position should not have changed from %d but is %d", 0, @@ -284,12 +250,10 @@ ZTEST_F(drv84xx_api, test_run_is_moving_true_when_step_interval_greater_zero) uint64_t step_interval = 20000000; bool moving = false; - (void)stepper_enable(fixture->dev); - (void)stepper_set_microstep_interval(fixture->dev, step_interval); - (void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE); - (void)stepper_is_moving(fixture->dev, &moving); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, step_interval); + (void)stepper_run(fixture->dev, CONFIG_STEPPER_IDX, STEPPER_DIRECTION_POSITIVE); + (void)stepper_is_moving(fixture->dev, CONFIG_STEPPER_IDX, &moving); zassert_true(moving, "Driver should be in state is_moving"); - (void)stepper_disable(fixture->dev); } -ZTEST_SUITE(drv84xx_api, NULL, drv84xx_api_setup, drv84xx_api_before, drv84xx_api_after, NULL); +ZTEST_SUITE(drv84xx_api, NULL, drv84xx_api_setup, drv84xx_api_before, NULL, NULL); diff --git a/tests/drivers/stepper/drv84xx/emul/src/main.c b/tests/drivers/stepper/drv84xx/emul/src/main.c index 3fbb23b36746..96d4b19004a7 100644 --- a/tests/drivers/stepper/drv84xx/emul/src/main.c +++ b/tests/drivers/stepper/drv84xx/emul/src/main.c @@ -33,7 +33,7 @@ static void *drv84xx_emul_setup(void) static void drv84xx_emul_before(void *f) { struct drv84xx_emul_fixture *fixture = f; - (void)stepper_drv_set_micro_stepper_res(fixture->dev, 1); + (void)stepper_drv_set_micro_step_res(fixture->dev, 1); } static void drv84xx_emul_after(void *f) diff --git a/tests/drivers/stepper/shell/CMakeLists.txt b/tests/drivers/stepper/shell/CMakeLists.txt index 7a7892c68da6..7afca16e6238 100644 --- a/tests/drivers/stepper/shell/CMakeLists.txt +++ b/tests/drivers/stepper/shell/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(can_shell) +project(stepper_shell) FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/stepper/shell/app.overlay b/tests/drivers/stepper/shell/app.overlay index ee0a78de9b78..c815460c5fb3 100644 --- a/tests/drivers/stepper/shell/app.overlay +++ b/tests/drivers/stepper/shell/app.overlay @@ -9,4 +9,9 @@ compatible = "zephyr,fake-stepper"; status = "okay"; }; + + fake_stepper_controller: fake_stepper_controller { + compatible = "zephyr,fake-stepper-controller"; + status = "okay"; + }; }; diff --git a/tests/drivers/stepper/shell/src/main.c b/tests/drivers/stepper/shell/src/main.c index c4c9c5796272..6e22b614c3c6 100644 --- a/tests/drivers/stepper/shell/src/main.c +++ b/tests/drivers/stepper/shell/src/main.c @@ -14,18 +14,22 @@ #include #include -#define FAKE_STEPPER_NAME DEVICE_DT_NAME(DT_NODELABEL(fake_stepper)) +#define FAKE_STEPPER_CONTROLLER DEVICE_DT_NAME(DT_NODELABEL(fake_stepper_controller)) +#define FAKE_STEPPER_NAME DEVICE_DT_NAME(DT_NODELABEL(fake_stepper)) +#define FAKE_STEPPER_INDEX STRINGIFY(0) /* Global variables */ static const struct device *const fake_stepper_dev = DEVICE_DT_GET(DT_NODELABEL(fake_stepper)); +static const struct device *const fake_stepper_controller_dev = + DEVICE_DT_GET(DT_NODELABEL(fake_stepper_controller)); DEFINE_FFF_GLOBALS; -#define ASSERT_STEPPER_FUNC_CALLED(stepper_fake_func, retval) \ +#define ASSERT_STEPPER_FUNC_CALLED(stepper_fake_func, stepper_fake_dev, retval) \ zassert_ok(retval, "failed to execute shell command (err %d)", retval); \ zassert_equal(stepper_fake_func.call_count, 1, \ STRINGIFY(stepper_fake_func) " function not called"); \ - zassert_equal(stepper_fake_func.arg0_val, fake_stepper_dev, "wrong device pointer") + zassert_equal(stepper_fake_func.arg0_val, stepper_fake_dev, "wrong device pointer") static void *stepper_shell_setup(void) { @@ -45,7 +49,7 @@ ZTEST(stepper_shell, test_stepper_enable) const struct shell *sh = shell_backend_dummy_get_ptr(); int err = shell_execute_cmd(sh, "stepper enable " FAKE_STEPPER_NAME); - ASSERT_STEPPER_FUNC_CALLED(fake_stepper_enable_fake, err); + ASSERT_STEPPER_FUNC_CALLED(fake_stepper_enable_fake, fake_stepper_dev, err); zassert_equal(err, 0, "stepper enable could not be executed"); } @@ -54,26 +58,30 @@ ZTEST(stepper_shell, test_stepper_disable) const struct shell *sh = shell_backend_dummy_get_ptr(); int err = shell_execute_cmd(sh, "stepper disable " FAKE_STEPPER_NAME); - ASSERT_STEPPER_FUNC_CALLED(fake_stepper_disable_fake, err); + ASSERT_STEPPER_FUNC_CALLED(fake_stepper_disable_fake, fake_stepper_dev, err); zassert_equal(err, 0, "stepper disable could not be executed"); } ZTEST(stepper_shell, test_stepper_move_by) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd(sh, "stepper move_by " FAKE_STEPPER_NAME " 1000"); + int err = shell_execute_cmd( + sh, "stepper move_by " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX " 1000"); - ASSERT_STEPPER_FUNC_CALLED(fake_stepper_move_by_fake, err); - zassert_equal(fake_stepper_move_by_fake.arg1_val, 1000, "wrong microsteps value"); + ASSERT_STEPPER_FUNC_CALLED(fake_stepper_move_by_fake, fake_stepper_controller_dev, err); + zassert_equal(fake_stepper_move_by_fake.arg2_val, 1000, "wrong microsteps value"); } ZTEST(stepper_shell, test_stepper_set_microstep_interval) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd(sh, "stepper set_microstep_interval " FAKE_STEPPER_NAME " 200"); + int err = shell_execute_cmd( + sh, "stepper set_microstep_interval " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX + " 200"); - ASSERT_STEPPER_FUNC_CALLED(fake_stepper_set_microstep_interval_fake, err); - zassert_equal(fake_stepper_set_microstep_interval_fake.arg1_val, 200, + ASSERT_STEPPER_FUNC_CALLED(fake_stepper_set_microstep_interval_fake, + fake_stepper_controller_dev, err); + zassert_equal(fake_stepper_set_microstep_interval_fake.arg2_val, 200, "wrong step_interval value"); } @@ -82,7 +90,7 @@ ZTEST(stepper_shell, test_stepper_set_micro_step_res) const struct shell *sh = shell_backend_dummy_get_ptr(); int err = shell_execute_cmd(sh, "stepper set_micro_step_res " FAKE_STEPPER_NAME " 64"); - ASSERT_STEPPER_FUNC_CALLED(fake_stepper_set_micro_step_res_fake, err); + ASSERT_STEPPER_FUNC_CALLED(fake_stepper_set_micro_step_res_fake, fake_stepper_dev, err); zassert_equal(fake_stepper_set_micro_step_res_fake.arg1_val, 64, "wrong micro steps resolution value"); } @@ -100,50 +108,58 @@ ZTEST(stepper_shell, test_stepper_get_micro_step_res) const struct shell *sh = shell_backend_dummy_get_ptr(); int err = shell_execute_cmd(sh, "stepper get_micro_step_res " FAKE_STEPPER_NAME); - ASSERT_STEPPER_FUNC_CALLED(fake_stepper_get_micro_step_res_fake, err); + ASSERT_STEPPER_FUNC_CALLED(fake_stepper_get_micro_step_res_fake, fake_stepper_dev, err); } ZTEST(stepper_shell, test_stepper_set_reference_position) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd(sh, "stepper set_reference_position " FAKE_STEPPER_NAME " 100"); + int err = shell_execute_cmd( + sh, "stepper set_reference_position " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX + " 100"); - ASSERT_STEPPER_FUNC_CALLED(fake_stepper_set_reference_position_fake, err); - zassert_equal(fake_stepper_set_reference_position_fake.arg1_val, 100, + ASSERT_STEPPER_FUNC_CALLED(fake_stepper_set_reference_position_fake, + fake_stepper_controller_dev, err); + zassert_equal(fake_stepper_set_reference_position_fake.arg2_val, 100, "wrong actual position value"); } ZTEST(stepper_shell, test_stepper_get_actual_position) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd(sh, "stepper get_actual_position " FAKE_STEPPER_NAME); + int err = shell_execute_cmd( + sh, "stepper get_actual_position " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX); - ASSERT_STEPPER_FUNC_CALLED(fake_stepper_get_actual_position_fake, err); + ASSERT_STEPPER_FUNC_CALLED(fake_stepper_get_actual_position_fake, + fake_stepper_controller_dev, err); } ZTEST(stepper_shell, test_stepper_move_to) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd(sh, "stepper move_to " FAKE_STEPPER_NAME " 200"); + int err = shell_execute_cmd( + sh, "stepper move_to " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX " 200"); - ASSERT_STEPPER_FUNC_CALLED(fake_stepper_move_to_fake, err); - zassert_equal(fake_stepper_move_to_fake.arg1_val, 200, "wrong target position value"); + ASSERT_STEPPER_FUNC_CALLED(fake_stepper_move_to_fake, fake_stepper_controller_dev, err); + zassert_equal(fake_stepper_move_to_fake.arg2_val, 200, "wrong target position value"); } ZTEST(stepper_shell, test_stepper_run) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd(sh, "stepper run " FAKE_STEPPER_NAME " positive"); + int err = shell_execute_cmd(sh, "stepper run " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX + " positive"); - ASSERT_STEPPER_FUNC_CALLED(fake_stepper_run_fake, err); - zassert_equal(fake_stepper_run_fake.arg1_val, STEPPER_DIRECTION_POSITIVE, + ASSERT_STEPPER_FUNC_CALLED(fake_stepper_run_fake, fake_stepper_controller_dev, err); + zassert_equal(fake_stepper_run_fake.arg2_val, STEPPER_DIRECTION_POSITIVE, "wrong direction value"); } ZTEST(stepper_shell, test_stepper_run_invalid_direction) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd(sh, "stepper run " FAKE_STEPPER_NAME " foo"); + int err = shell_execute_cmd(sh, "stepper run " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX + " foo"); zassert_not_equal(err, 0, " executed run with invalid direction value"); } @@ -151,22 +167,32 @@ ZTEST(stepper_shell, test_stepper_run_invalid_direction) ZTEST(stepper_shell, test_stepper_stop) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd(sh, "stepper stop " FAKE_STEPPER_NAME); + int err = shell_execute_cmd(sh, "stepper stop " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX); - ASSERT_STEPPER_FUNC_CALLED(fake_stepper_stop_fake, err); + ASSERT_STEPPER_FUNC_CALLED(fake_stepper_stop_fake, fake_stepper_controller_dev, err); zassert_equal(err, 0, "stepper stop could not be executed"); } -ZTEST(stepper_shell, test_stepper_info) +ZTEST(stepper_shell, test_stepper_controller_info) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd(sh, "stepper info " FAKE_STEPPER_NAME); + int err = shell_execute_cmd( + sh, "stepper control info " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX); zassert_ok(err, "failed to execute shell command (err %d)", err); zassert_equal(fake_stepper_is_moving_fake.call_count, 1, "is_moving function not called"); zassert_equal(fake_stepper_get_actual_position_fake.call_count, 1, "get_actual_position function not called"); +} + +ZTEST(stepper_shell, test_stepper_info) +{ + const struct shell *sh = shell_backend_dummy_get_ptr(); + int err = shell_execute_cmd(sh, "stepper info " FAKE_STEPPER_NAME); + + zassert_ok(err, "failed to execute shell command (err %d)", err); + zassert_equal(fake_stepper_get_micro_step_res_fake.call_count, 1, "get_micro_step_res function not called"); } diff --git a/tests/drivers/stepper/stepper_api/Kconfig b/tests/drivers/stepper/stepper_api/Kconfig index 6cc7b5be7e0b..5c09ba90b5f3 100644 --- a/tests/drivers/stepper/stepper_api/Kconfig +++ b/tests/drivers/stepper/stepper_api/Kconfig @@ -11,3 +11,9 @@ config STEPPER_TEST_TIMING_TIMEOUT_TOLERANCE_PCT help Additional margin (%) added to step timing during test timeouts. Accounts for execution and scheduling jitter. + +config STEPPER_IDX + int "Stepper index" + default 0 + help + Index of the stepper device to test. diff --git a/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209.overlay b/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209.overlay index b1aad6a6d407..b3f1b00ec532 100644 --- a/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209.overlay +++ b/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209.overlay @@ -16,7 +16,6 @@ adi_tmc2209: adi_tmc2209 { status = "okay"; compatible = "adi,tmc2209"; - micro-step-res = <32>; dir-gpios = <&gpio1 0 0>; step-gpios = <&gpio1 1 0>; en-gpios = <&gpio2 1 0>; diff --git a/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209_work_q.overlay b/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209_work_q.overlay index 5b0b71ae6762..3769b908c521 100644 --- a/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209_work_q.overlay +++ b/tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209_work_q.overlay @@ -16,7 +16,6 @@ adi_tmc2209: adi_tmc2209 { status = "okay"; compatible = "adi,tmc2209"; - micro-step-res = <32>; dir-gpios = <&gpio1 0 0>; step-gpios = <&gpio1 1 0>; en-gpios = <&gpio2 1 0>; diff --git a/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979.overlay b/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979.overlay index 2652c194f213..72b91ae42735 100644 --- a/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979.overlay +++ b/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979.overlay @@ -16,7 +16,6 @@ allegro_a4979: allegro_a4979 { status = "okay"; compatible = "allegro,a4979"; - micro-step-res = <1>; reset-gpios = <&gpio4 0 0>; dir-gpios = <&gpio1 0 0>; step-gpios = <&gpio1 1 0>; diff --git a/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979_work_q.overlay b/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979_work_q.overlay index b2e477fbed3b..64000ba9691b 100644 --- a/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979_work_q.overlay +++ b/tests/drivers/stepper/stepper_api/boards/native_sim_allegro_a4979_work_q.overlay @@ -16,7 +16,6 @@ allegro_a4979: allegro_a4979 { status = "okay"; compatible = "allegro,a4979"; - micro-step-res = <1>; reset-gpios = <&gpio4 0 0>; dir-gpios = <&gpio1 0 0>; step-gpios = <&gpio1 1 0>; diff --git a/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx.overlay b/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx.overlay index 90b9fc584ece..b234ce1bfca9 100644 --- a/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx.overlay +++ b/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx.overlay @@ -16,7 +16,6 @@ ti_drv84xx: ti_drv84xx { status = "okay"; compatible = "ti,drv84xx"; - micro-step-res = <8>; dir-gpios = <&gpio1 0 0>; step-gpios = <&gpio1 1 0>; sleep-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>; diff --git a/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx_work_q.overlay b/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx_work_q.overlay index 55740f8576bd..01de085d6a4f 100644 --- a/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx_work_q.overlay +++ b/tests/drivers/stepper/stepper_api/boards/native_sim_ti_drv84xx_work_q.overlay @@ -16,7 +16,6 @@ ti_drv84xx: ti_drv84xx { status = "okay"; compatible = "ti,drv84xx"; - micro-step-res = <8>; dir-gpios = <&gpio1 0 0>; step-gpios = <&gpio1 1 0>; sleep-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>; diff --git a/tests/drivers/stepper/stepper_api/src/main.c b/tests/drivers/stepper/stepper_api/src/main.c index e16155e16209..f461f7177b3c 100644 --- a/tests/drivers/stepper/stepper_api/src/main.c +++ b/tests/drivers/stepper/stepper_api/src/main.c @@ -30,8 +30,8 @@ void *user_data_received; } while (0); \ }) -static void stepper_print_event_callback(const struct device *dev, enum stepper_event event, - void *user_data) +static void stepper_print_event_callback(const struct device *dev, const uint8_t stepper_idx, + enum stepper_event event, void *user_data) { const struct device *dev_callback = user_data; user_data_received = user_data; @@ -72,14 +72,13 @@ static void *stepper_setup(void) &stepper_signal); zassert_not_null(fixture.dev); - (void)stepper_enable(fixture.dev); return &fixture; } static void stepper_before(void *f) { struct stepper_fixture *fixture = f; - (void)stepper_set_reference_position(fixture->dev, 0); + (void)stepper_set_reference_position(fixture->dev, CONFIG_STEPPER_IDX, 0); k_poll_signal_reset(&stepper_signal); @@ -88,24 +87,9 @@ static void stepper_before(void *f) ZTEST_SUITE(stepper, NULL, stepper_setup, stepper_before, NULL, NULL); -ZTEST_F(stepper, test_set_micro_step_res_invalid) -{ - int ret = stepper_set_micro_step_res(fixture->dev, 127); - - zassert_equal(ret, -EINVAL, "Invalid micro step resolution should return -EINVAL"); -} - -ZTEST_F(stepper, test_get_micro_step_res) -{ - enum stepper_micro_step_resolution res; - (void)stepper_get_micro_step_res(fixture->dev, &res); - zassert_equal(res, DT_PROP(DT_ALIAS(stepper), micro_step_res), - "Micro step resolution not set correctly"); -} - ZTEST_F(stepper, test_set_micro_step_interval_invalid_zero) { - int err = stepper_set_microstep_interval(fixture->dev, 0); + int err = stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, 0); if (err == -ENOSYS) { ztest_test_skip(); } @@ -117,10 +101,10 @@ ZTEST_F(stepper, test_actual_position) int32_t pos = 100u; int ret; - ret = stepper_set_reference_position(fixture->dev, pos); + ret = stepper_set_reference_position(fixture->dev, CONFIG_STEPPER_IDX, pos); zassert_equal(ret, 0, "Failed to set reference position"); - ret = stepper_get_actual_position(fixture->dev, &pos); + ret = stepper_get_actual_position(fixture->dev, CONFIG_STEPPER_IDX, &pos); zassert_equal(ret, 0, "Failed to get actual position"); zassert_equal(pos, 100u, "Actual position not set correctly"); } @@ -130,21 +114,22 @@ ZTEST_F(stepper, test_target_position_w_fixed_step_interval) int32_t pos = 10u; int ret; - ret = stepper_set_microstep_interval(fixture->dev, 100 * USEC_PER_SEC); + ret = stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, 100 * USEC_PER_SEC); if (ret == -ENOSYS) { ztest_test_skip(); } /* Pass the function name as user data */ - (void)stepper_set_event_callback(fixture->dev, fixture->callback, (void *)fixture->dev); + (void)stepper_set_event_callback(fixture->dev, CONFIG_STEPPER_IDX, fixture->callback, + (void *)fixture->dev); - (void)stepper_move_to(fixture->dev, pos); + (void)stepper_move_to(fixture->dev, CONFIG_STEPPER_IDX, pos); POLL_AND_CHECK_SIGNAL( stepper_signal, stepper_event, STEPPER_EVENT_STEPS_COMPLETED, K_MSEC(pos * (100 + CONFIG_STEPPER_TEST_TIMING_TIMEOUT_TOLERANCE_PCT))); - (void)stepper_get_actual_position(fixture->dev, &pos); + (void)stepper_get_actual_position(fixture->dev, CONFIG_STEPPER_IDX, &pos); zassert_equal(pos, 10u, "Target position should be %d but is %d", 10u, pos); zassert_equal(user_data_received, fixture->dev, "User data not received"); } @@ -153,14 +138,15 @@ ZTEST_F(stepper, test_move_by_positive_step_count) { int32_t steps = 20; - (void)stepper_set_microstep_interval(fixture->dev, 100 * USEC_PER_SEC); - (void)stepper_set_event_callback(fixture->dev, fixture->callback, (void *)fixture->dev); - (void)stepper_move_by(fixture->dev, steps); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, 100 * USEC_PER_SEC); + (void)stepper_set_event_callback(fixture->dev, CONFIG_STEPPER_IDX, fixture->callback, + (void *)fixture->dev); + (void)stepper_move_by(fixture->dev, CONFIG_STEPPER_IDX, steps); POLL_AND_CHECK_SIGNAL( stepper_signal, stepper_event, STEPPER_EVENT_STEPS_COMPLETED, K_MSEC(steps * (100 + CONFIG_STEPPER_TEST_TIMING_TIMEOUT_TOLERANCE_PCT))); - (void)stepper_get_actual_position(fixture->dev, &steps); + (void)stepper_get_actual_position(fixture->dev, CONFIG_STEPPER_IDX, &steps); zassert_equal(steps, 20u, "Target position should be %d but is %d", 20u, steps); } @@ -168,14 +154,15 @@ ZTEST_F(stepper, test_move_by_negative_step_count) { int32_t steps = -20; - (void)stepper_set_microstep_interval(fixture->dev, 100 * USEC_PER_SEC); - (void)stepper_set_event_callback(fixture->dev, fixture->callback, (void *)fixture->dev); - (void)stepper_move_by(fixture->dev, steps); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, 100 * USEC_PER_SEC); + (void)stepper_set_event_callback(fixture->dev, CONFIG_STEPPER_IDX, fixture->callback, + (void *)fixture->dev); + (void)stepper_move_by(fixture->dev, CONFIG_STEPPER_IDX, steps); POLL_AND_CHECK_SIGNAL( stepper_signal, stepper_event, STEPPER_EVENT_STEPS_COMPLETED, K_MSEC(-steps * (100 + CONFIG_STEPPER_TEST_TIMING_TIMEOUT_TOLERANCE_PCT))); - (void)stepper_get_actual_position(fixture->dev, &steps); + (void)stepper_get_actual_position(fixture->dev, CONFIG_STEPPER_IDX, &steps); zassert_equal(steps, -20u, "Target position should be %d but is %d", -20u, steps); } @@ -184,26 +171,28 @@ ZTEST_F(stepper, test_move_by_zero_steps) { bool is_moving; - (void)stepper_set_microstep_interval(fixture->dev, 100 * USEC_PER_SEC); - (void)stepper_set_event_callback(fixture->dev, fixture->callback, (void *)fixture->dev); - (void)stepper_move_by(fixture->dev, 0); + (void)stepper_set_microstep_interval(fixture->dev, CONFIG_STEPPER_IDX, 100 * USEC_PER_SEC); + (void)stepper_set_event_callback(fixture->dev, CONFIG_STEPPER_IDX, fixture->callback, + (void *)fixture->dev); + (void)stepper_move_by(fixture->dev, CONFIG_STEPPER_IDX, 0); POLL_AND_CHECK_SIGNAL(stepper_signal, stepper_event, STEPPER_EVENT_STEPS_COMPLETED, K_MSEC(100)); - stepper_is_moving(fixture->dev, &is_moving); + stepper_is_moving(fixture->dev, CONFIG_STEPPER_IDX, &is_moving); zassert_equal(is_moving, false, "Stepper is still moving"); } ZTEST_F(stepper, test_stop) { - (void)stepper_set_event_callback(fixture->dev, fixture->callback, (void *)fixture->dev); + (void)stepper_set_event_callback(fixture->dev, CONFIG_STEPPER_IDX, fixture->callback, + (void *)fixture->dev); /* Run the stepper in positive direction */ - (void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE); + (void)stepper_run(fixture->dev, CONFIG_STEPPER_IDX, STEPPER_DIRECTION_POSITIVE); /* Stop the stepper */ - int ret = stepper_stop(fixture->dev); + int ret = stepper_stop(fixture->dev, CONFIG_STEPPER_IDX); bool is_moving; if (ret == 0) { @@ -212,10 +201,10 @@ ZTEST_F(stepper, test_stop) zassert_equal(user_data_received, fixture->dev, "User data not received"); /* Check if the stepper is stopped */ - stepper_is_moving(fixture->dev, &is_moving); + stepper_is_moving(fixture->dev, CONFIG_STEPPER_IDX, &is_moving); zassert_equal(is_moving, false, "Stepper is still moving"); } else if (ret == -ENOSYS) { - stepper_is_moving(fixture->dev, &is_moving); + stepper_is_moving(fixture->dev, CONFIG_STEPPER_IDX, &is_moving); zassert_equal(is_moving, true, "Stepper should be moving since stop is not implemented"); } else { From 6fe31a1a8cf1fa2ab1d34a2f6e0159e1308ff2bd Mon Sep 17 00:00:00 2001 From: Jilay Pandya Date: Sun, 29 Jun 2025 16:06:19 +0200 Subject: [PATCH 3/3] drivers: stepper: shell: add stepper index selection functionality Add stepper index selection functionality in stepper shell to select different steppers for the same stepper motion controller Signed-off-by: Jilay Pandya --- drivers/stepper/stepper_shell.c | 195 ++++++++++++++++++++----- tests/drivers/stepper/shell/src/main.c | 41 +++--- 2 files changed, 182 insertions(+), 54 deletions(-) diff --git a/drivers/stepper/stepper_shell.c b/drivers/stepper/stepper_shell.c index fe800f252cc6..ad896aee2429 100644 --- a/drivers/stepper/stepper_shell.c +++ b/drivers/stepper/stepper_shell.c @@ -29,6 +29,13 @@ struct stepper_direction_map { enum stepper_direction direction; }; +struct stepper_control_idx_map { + const char *name; + uint8_t stepper_idx; +}; + +#define STEPPER_DRV_MICROSTEP_PARAM_IDX 2 + #define STEPPER_DIRECTION_MAP_ENTRY(_name, _dir) \ { \ .name = _name, \ @@ -41,6 +48,12 @@ struct stepper_direction_map { .microstep = _microstep, \ } +#define STEPPER_CONTROL_IDX_MAP_ENTRY(_name, _idx) \ + { \ + .name = _name, \ + .stepper_idx = _idx, \ + } + static void print_callback(const struct device *dev, const uint8_t stepper_idx, const enum stepper_event event, void *user_data) { @@ -71,7 +84,12 @@ static void print_callback(const struct device *dev, const uint8_t stepper_idx, } } -static bool device_is_stepper(const struct device *dev) +static bool device_is_stepper_drv(const struct device *dev) +{ + return DEVICE_API_IS(stepper_drv, dev); +} + +static bool device_is_stepper_controller(const struct device *dev) { return DEVICE_API_IS(stepper, dev); } @@ -81,6 +99,12 @@ static const struct stepper_direction_map stepper_direction_map[] = { STEPPER_DIRECTION_MAP_ENTRY("negative", STEPPER_DIRECTION_NEGATIVE), }; +static const struct stepper_control_idx_map stepper_control_idx_map[] = { + STEPPER_CONTROL_IDX_MAP_ENTRY("0", 0), + STEPPER_CONTROL_IDX_MAP_ENTRY("1", 1), + STEPPER_CONTROL_IDX_MAP_ENTRY("2", 2), +}; + static const struct stepper_microstep_map stepper_microstep_map[] = { STEPPER_MICROSTEP_MAP("1", STEPPER_MICRO_STEP_1), STEPPER_MICROSTEP_MAP("2", STEPPER_MICRO_STEP_2), @@ -107,6 +131,34 @@ static void cmd_stepper_direction(size_t idx, struct shell_static_entry *entry) SHELL_DYNAMIC_CMD_CREATE(dsub_stepper_direction, cmd_stepper_direction); +static void cmd_stepper_idx_dir(size_t idx, struct shell_static_entry *entry) +{ + if (idx < ARRAY_SIZE(stepper_control_idx_map)) { + entry->syntax = stepper_control_idx_map[idx].name; + } else { + entry->syntax = NULL; + } + entry->handler = NULL; + entry->help = "Stepper direction"; + entry->subcmd = &dsub_stepper_direction; +} + +SHELL_DYNAMIC_CMD_CREATE(dsub_stepper_idx_dir, cmd_stepper_idx_dir); + +static void cmd_stepper_idx(size_t idx, struct shell_static_entry *entry) +{ + if (idx < ARRAY_SIZE(stepper_control_idx_map)) { + entry->syntax = stepper_control_idx_map[idx].name; + } else { + entry->syntax = NULL; + } + entry->handler = NULL; + entry->help = "Stepper direction"; + entry->subcmd = NULL; +} + +SHELL_DYNAMIC_CMD_CREATE(dsub_stepper_idx, cmd_stepper_idx); + static void cmd_stepper_microstep(size_t idx, struct shell_static_entry *entry) { if (idx < ARRAY_SIZE(stepper_microstep_map)) { @@ -123,7 +175,7 @@ SHELL_DYNAMIC_CMD_CREATE(dsub_stepper_microstep, cmd_stepper_microstep); static void cmd_pos_stepper_motor_name(size_t idx, struct shell_static_entry *entry) { - const struct device *dev = shell_device_filter(idx, device_is_stepper); + const struct device *dev = shell_device_filter(idx, device_is_stepper_drv); entry->syntax = (dev != NULL) ? dev->name : NULL; entry->handler = NULL; @@ -133,9 +185,21 @@ static void cmd_pos_stepper_motor_name(size_t idx, struct shell_static_entry *en SHELL_DYNAMIC_CMD_CREATE(dsub_pos_stepper_motor_name, cmd_pos_stepper_motor_name); -static void cmd_pos_stepper_motor_name_dir(size_t idx, struct shell_static_entry *entry) +static void cmd_pos_stepper_controller_name(size_t idx, struct shell_static_entry *entry) { - const struct device *dev = shell_device_filter(idx, device_is_stepper); + const struct device *dev = shell_device_filter(idx, device_is_stepper_controller); + + entry->syntax = (dev != NULL) ? dev->name : NULL; + entry->handler = NULL; + entry->help = "List Devices"; + entry->subcmd = &dsub_stepper_idx; +} + +SHELL_DYNAMIC_CMD_CREATE(dsub_pos_stepper_controller_name, cmd_pos_stepper_controller_name); + +static void cmd_pos_stepper_controller_name_dir(size_t idx, struct shell_static_entry *entry) +{ + const struct device *dev = shell_device_filter(idx, device_is_stepper_controller); if (dev != NULL) { entry->syntax = dev->name; @@ -144,14 +208,14 @@ static void cmd_pos_stepper_motor_name_dir(size_t idx, struct shell_static_entry } entry->handler = NULL; entry->help = "List Devices"; - entry->subcmd = &dsub_stepper_direction; + entry->subcmd = &dsub_stepper_idx_dir; } -SHELL_DYNAMIC_CMD_CREATE(dsub_pos_stepper_motor_name_dir, cmd_pos_stepper_motor_name_dir); +SHELL_DYNAMIC_CMD_CREATE(dsub_pos_stepper_controller_name_dir, cmd_pos_stepper_controller_name_dir); static void cmd_pos_stepper_motor_name_microstep(size_t idx, struct shell_static_entry *entry) { - const struct device *dev = shell_device_filter(idx, device_is_stepper); + const struct device *dev = shell_device_filter(idx, device_is_stepper_drv); if (dev != NULL) { entry->syntax = dev->name; @@ -212,23 +276,40 @@ static int cmd_stepper_disable(const struct shell *sh, size_t argc, char **argv) return err; } +static int get_stepper_index(char **argv, uint8_t *stepper_idx) +{ + for (int i = 0; i < ARRAY_SIZE(stepper_control_idx_map); i++) { + if (strcmp(argv[ARG_IDX_DEV_IDX], stepper_control_idx_map[i].name) == 0) { + *stepper_idx = stepper_control_idx_map[i].stepper_idx; + return 0; + } + } + return -EINVAL; +} static int cmd_stepper_stop(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; + uint8_t stepper_index; int err = 0; + err = get_stepper_index(argv, &stepper_index); + if (err < 0) { + shell_error(sh, "Invalid stepper index: %s", argv[ARG_IDX_DEV_IDX]); + return err; + } + err = parse_device_arg(sh, argv, &dev); if (err < 0) { return err; } - err = stepper_stop(dev); + err = stepper_stop(dev, stepper_index); if (err) { shell_error(sh, "Error: %d", err); return err; } - err = stepper_set_event_callback(dev, print_callback, (void *)sh); + err = stepper_set_event_callback(dev, stepper_index, print_callback, (void *)sh); if (err != 0) { shell_error(sh, "Failed to set callback: %d", err); } @@ -239,9 +320,15 @@ static int cmd_stepper_stop(const struct shell *sh, size_t argc, char **argv) static int cmd_stepper_move_by(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; + uint8_t stepper_index; int err = 0; - const uint8_t stepper_index = shell_strtol(argv[ARG_IDX_DEV_IDX], 10, &err); + err = get_stepper_index(argv, &stepper_index); + if (err < 0) { + shell_error(sh, "Invalid stepper index: %s", argv[ARG_IDX_DEV_IDX]); + return err; + } + int32_t micro_steps = shell_strtol(argv[ARG_IDX_PARAM], 10, &err); if (err < 0) { @@ -269,8 +356,15 @@ static int cmd_stepper_move_by(const struct shell *sh, size_t argc, char **argv) static int cmd_stepper_set_microstep_interval(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; + uint8_t stepper_index; int err = 0; - const uint8_t stepper_index = shell_strtol(argv[ARG_IDX_DEV_IDX], 10, &err); + + err = get_stepper_index(argv, &stepper_index); + if (err < 0) { + shell_error(sh, "Invalid stepper index: %s", argv[ARG_IDX_DEV_IDX]); + return err; + } + uint64_t step_interval = shell_strtoull(argv[ARG_IDX_PARAM], 10, &err); if (err < 0) { @@ -297,14 +391,16 @@ static int cmd_stepper_set_micro_step_res(const struct shell *sh, size_t argc, c int err = -EINVAL; for (int i = 0; i < ARRAY_SIZE(stepper_microstep_map); i++) { - if (strcmp(argv[ARG_IDX_PARAM], stepper_microstep_map[i].name) == 0) { + if (strcmp(argv[STEPPER_DRV_MICROSTEP_PARAM_IDX], stepper_microstep_map[i].name) == + 0) { resolution = stepper_microstep_map[i].microstep; err = 0; break; } } if (err != 0) { - shell_error(sh, "Invalid microstep value %s", argv[ARG_IDX_PARAM]); + shell_error(sh, "Invalid microstep value %s", + argv[STEPPER_DRV_MICROSTEP_PARAM_IDX]); return err; } @@ -313,7 +409,7 @@ static int cmd_stepper_set_micro_step_res(const struct shell *sh, size_t argc, c return err; } - err = stepper_drv_set_micro_stepper_res(dev, resolution); + err = stepper_drv_set_micro_step_res(dev, resolution); if (err) { shell_error(sh, "Error: %d", err); } @@ -345,8 +441,15 @@ static int cmd_stepper_get_micro_step_res(const struct shell *sh, size_t argc, c static int cmd_stepper_set_reference_position(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; + uint8_t stepper_index; int err = 0; - const uint8_t stepper_index = shell_strtol(argv[ARG_IDX_DEV_IDX], 10, &err); + + err = get_stepper_index(argv, &stepper_index); + if (err < 0) { + shell_error(sh, "Invalid stepper index: %s", argv[ARG_IDX_DEV_IDX]); + return err; + } + int32_t position = shell_strtol(argv[ARG_IDX_PARAM], 10, &err); if (err < 0) { @@ -369,8 +472,15 @@ static int cmd_stepper_set_reference_position(const struct shell *sh, size_t arg static int cmd_stepper_get_actual_position(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; + uint8_t stepper_index; int err; - const uint8_t stepper_index = shell_strtol(argv[ARG_IDX_DEV_IDX], 10, &err); + + err = get_stepper_index(argv, &stepper_index); + if (err < 0) { + shell_error(sh, "Invalid stepper index: %s", argv[ARG_IDX_DEV_IDX]); + return err; + } + int32_t actual_position; err = parse_device_arg(sh, argv, &dev); @@ -391,8 +501,15 @@ static int cmd_stepper_get_actual_position(const struct shell *sh, size_t argc, static int cmd_stepper_move_to(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; + uint8_t stepper_index; int err = 0; - const uint8_t stepper_index = shell_strtol(argv[ARG_IDX_DEV_IDX], 10, &err); + + err = get_stepper_index(argv, &stepper_index); + if (err < 0) { + shell_error(sh, "Invalid stepper index: %s", argv[ARG_IDX_DEV_IDX]); + return err; + } + const int32_t position = shell_strtol(argv[ARG_IDX_PARAM], 10, &err); if (err < 0) { @@ -420,10 +537,18 @@ static int cmd_stepper_move_to(const struct shell *sh, size_t argc, char **argv) static int cmd_stepper_run(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; - int err = -EINVAL; - const uint8_t stepper_index = shell_strtol(argv[ARG_IDX_DEV_IDX], 10, &err); + uint8_t stepper_index; + int err; + + err = get_stepper_index(argv, &stepper_index); + if (err < 0) { + shell_error(sh, "Invalid stepper index: %s", argv[ARG_IDX_DEV_IDX]); + return err; + } + enum stepper_direction direction = STEPPER_DIRECTION_POSITIVE; + err = -EINVAL; for (int i = 0; i < ARRAY_SIZE(stepper_direction_map); i++) { if (strcmp(argv[ARG_IDX_PARAM], stepper_direction_map[i].name) == 0) { direction = stepper_direction_map[i].direction; @@ -458,10 +583,16 @@ static int cmd_stepper_run(const struct shell *sh, size_t argc, char **argv) static int cmd_stepper_control_info(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; + uint8_t stepper_index; int err; bool is_moving; int32_t actual_position; - const uint8_t stepper_index = shell_strtol(argv[ARG_IDX_DEV_IDX], 10, &err); + + err = get_stepper_index(argv, &stepper_index); + if (err < 0) { + shell_error(sh, "Invalid stepper index: %s", argv[ARG_IDX_DEV_IDX]); + return err; + } err = parse_device_arg(sh, argv, &dev); if (err < 0) { @@ -492,8 +623,6 @@ static int cmd_stepper_info(const struct shell *sh, size_t argc, char **argv) { const struct device *dev; int err; - bool is_moving; - int32_t actual_position; enum stepper_micro_step_resolution micro_step_res; err = parse_device_arg(sh, argv, &dev); @@ -522,22 +651,22 @@ SHELL_STATIC_SUBCMD_SET_CREATE( " ", cmd_stepper_set_micro_step_res, 3, 0), SHELL_CMD_ARG(get_micro_step_res, &dsub_pos_stepper_motor_name, "", cmd_stepper_get_micro_step_res, 2, 0), - SHELL_CMD_ARG(set_reference_position, &dsub_pos_stepper_motor_name, " ", - cmd_stepper_set_reference_position, 4, 0), - SHELL_CMD_ARG(get_actual_position, &dsub_pos_stepper_motor_name, "", + SHELL_CMD_ARG(set_reference_position, &dsub_pos_stepper_controller_name, + " ", cmd_stepper_set_reference_position, 4, 0), + SHELL_CMD_ARG(get_actual_position, &dsub_pos_stepper_controller_name, "", cmd_stepper_get_actual_position, 3, 0), - SHELL_CMD_ARG(set_microstep_interval, &dsub_pos_stepper_motor_name, + SHELL_CMD_ARG(set_microstep_interval, &dsub_pos_stepper_controller_name, " ", cmd_stepper_set_microstep_interval, 4, 0), - SHELL_CMD_ARG(move_by, &dsub_pos_stepper_motor_name, " ", + SHELL_CMD_ARG(move_by, &dsub_pos_stepper_controller_name, " ", cmd_stepper_move_by, 4, 0), - SHELL_CMD_ARG(move_to, &dsub_pos_stepper_motor_name, " ", + SHELL_CMD_ARG(move_to, &dsub_pos_stepper_controller_name, " ", cmd_stepper_move_to, 4, 0), - SHELL_CMD_ARG(run, &dsub_pos_stepper_motor_name_dir, " ", + SHELL_CMD_ARG(run, &dsub_pos_stepper_controller_name_dir, " ", cmd_stepper_run, 4, 0), - SHELL_CMD_ARG(stop, &dsub_pos_stepper_motor_name, "", cmd_stepper_stop, 3, 0), - SHELL_CMD_ARG(info, &dsub_pos_stepper_motor_name, "", cmd_stepper_control_info, 3, - 0), - SHELL_CMD_ARG(info, &dsub_pos_stepper_motor_name, "", cmd_stepper_info, 3, 0), + SHELL_CMD_ARG(stop, &dsub_pos_stepper_controller_name, "", cmd_stepper_stop, 3, 0), + SHELL_CMD_ARG(control_info, &dsub_pos_stepper_controller_name, "", + cmd_stepper_control_info, 3, 0), + SHELL_CMD_ARG(info, &dsub_pos_stepper_motor_name, "", cmd_stepper_info, 2, 0), SHELL_SUBCMD_SET_END); SHELL_CMD_REGISTER(stepper, &stepper_cmds, "Stepper motor commands", NULL); diff --git a/tests/drivers/stepper/shell/src/main.c b/tests/drivers/stepper/shell/src/main.c index 6e22b614c3c6..018fb4321224 100644 --- a/tests/drivers/stepper/shell/src/main.c +++ b/tests/drivers/stepper/shell/src/main.c @@ -16,7 +16,7 @@ #define FAKE_STEPPER_CONTROLLER DEVICE_DT_NAME(DT_NODELABEL(fake_stepper_controller)) #define FAKE_STEPPER_NAME DEVICE_DT_NAME(DT_NODELABEL(fake_stepper)) -#define FAKE_STEPPER_INDEX STRINGIFY(0) +#define FAKE_STEPPER_IDX STRINGIFY(0) /* Global variables */ static const struct device *const fake_stepper_dev = DEVICE_DT_GET(DT_NODELABEL(fake_stepper)); @@ -65,8 +65,8 @@ ZTEST(stepper_shell, test_stepper_disable) ZTEST(stepper_shell, test_stepper_move_by) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd( - sh, "stepper move_by " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX " 1000"); + int err = shell_execute_cmd(sh, "stepper move_by " FAKE_STEPPER_CONTROLLER + " " FAKE_STEPPER_IDX " 1000"); ASSERT_STEPPER_FUNC_CALLED(fake_stepper_move_by_fake, fake_stepper_controller_dev, err); zassert_equal(fake_stepper_move_by_fake.arg2_val, 1000, "wrong microsteps value"); @@ -75,12 +75,11 @@ ZTEST(stepper_shell, test_stepper_move_by) ZTEST(stepper_shell, test_stepper_set_microstep_interval) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd( - sh, "stepper set_microstep_interval " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX - " 200"); + int err = shell_execute_cmd(sh, "stepper set_microstep_interval " FAKE_STEPPER_CONTROLLER + " " FAKE_STEPPER_IDX " 200"); ASSERT_STEPPER_FUNC_CALLED(fake_stepper_set_microstep_interval_fake, - fake_stepper_controller_dev, err); + fake_stepper_controller_dev, err); zassert_equal(fake_stepper_set_microstep_interval_fake.arg2_val, 200, "wrong step_interval value"); } @@ -114,12 +113,11 @@ ZTEST(stepper_shell, test_stepper_get_micro_step_res) ZTEST(stepper_shell, test_stepper_set_reference_position) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd( - sh, "stepper set_reference_position " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX - " 100"); + int err = shell_execute_cmd(sh, "stepper set_reference_position " FAKE_STEPPER_CONTROLLER + " " FAKE_STEPPER_IDX " 100"); ASSERT_STEPPER_FUNC_CALLED(fake_stepper_set_reference_position_fake, - fake_stepper_controller_dev, err); + fake_stepper_controller_dev, err); zassert_equal(fake_stepper_set_reference_position_fake.arg2_val, 100, "wrong actual position value"); } @@ -127,18 +125,18 @@ ZTEST(stepper_shell, test_stepper_set_reference_position) ZTEST(stepper_shell, test_stepper_get_actual_position) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd( - sh, "stepper get_actual_position " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX); + int err = shell_execute_cmd(sh, "stepper get_actual_position " FAKE_STEPPER_CONTROLLER + " " FAKE_STEPPER_IDX); ASSERT_STEPPER_FUNC_CALLED(fake_stepper_get_actual_position_fake, - fake_stepper_controller_dev, err); + fake_stepper_controller_dev, err); } ZTEST(stepper_shell, test_stepper_move_to) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd( - sh, "stepper move_to " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX " 200"); + int err = shell_execute_cmd(sh, "stepper move_to " FAKE_STEPPER_CONTROLLER + " " FAKE_STEPPER_IDX " 200"); ASSERT_STEPPER_FUNC_CALLED(fake_stepper_move_to_fake, fake_stepper_controller_dev, err); zassert_equal(fake_stepper_move_to_fake.arg2_val, 200, "wrong target position value"); @@ -147,7 +145,7 @@ ZTEST(stepper_shell, test_stepper_move_to) ZTEST(stepper_shell, test_stepper_run) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd(sh, "stepper run " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX + int err = shell_execute_cmd(sh, "stepper run " FAKE_STEPPER_CONTROLLER " " FAKE_STEPPER_IDX " positive"); ASSERT_STEPPER_FUNC_CALLED(fake_stepper_run_fake, fake_stepper_controller_dev, err); @@ -158,7 +156,7 @@ ZTEST(stepper_shell, test_stepper_run) ZTEST(stepper_shell, test_stepper_run_invalid_direction) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd(sh, "stepper run " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX + int err = shell_execute_cmd(sh, "stepper run " FAKE_STEPPER_CONTROLLER " " FAKE_STEPPER_IDX " foo"); zassert_not_equal(err, 0, " executed run with invalid direction value"); @@ -167,7 +165,8 @@ ZTEST(stepper_shell, test_stepper_run_invalid_direction) ZTEST(stepper_shell, test_stepper_stop) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd(sh, "stepper stop " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX); + int err = shell_execute_cmd(sh, "stepper stop " FAKE_STEPPER_CONTROLLER + " " FAKE_STEPPER_IDX); ASSERT_STEPPER_FUNC_CALLED(fake_stepper_stop_fake, fake_stepper_controller_dev, err); zassert_equal(err, 0, "stepper stop could not be executed"); @@ -176,8 +175,8 @@ ZTEST(stepper_shell, test_stepper_stop) ZTEST(stepper_shell, test_stepper_controller_info) { const struct shell *sh = shell_backend_dummy_get_ptr(); - int err = shell_execute_cmd( - sh, "stepper control info " FAKE_STEPPER_CONTROLLER FAKE_STEPPER_INDEX); + int err = shell_execute_cmd(sh, "stepper control_info " FAKE_STEPPER_CONTROLLER + " " FAKE_STEPPER_IDX); zassert_ok(err, "failed to execute shell command (err %d)", err);