diff --git a/drivers/stepper/CMakeLists.txt b/drivers/stepper/CMakeLists.txt index 1cda468fac48..d56488585ab6 100644 --- a/drivers/stepper/CMakeLists.txt +++ b/drivers/stepper/CMakeLists.txt @@ -7,12 +7,18 @@ 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 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_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 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.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/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/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/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/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/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/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/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..ad896aee2429 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 { @@ -28,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, \ @@ -40,8 +48,14 @@ struct stepper_direction_map { .microstep = _microstep, \ } -static void print_callback(const struct device *dev, const enum stepper_event event, - void *user_data) +#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) { const struct shell *sh = user_data; if (!sh) { @@ -64,16 +78,18 @@ 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; } } -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); } @@ -83,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), @@ -109,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)) { @@ -125,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; @@ -135,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_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); + const struct device *dev = shell_device_filter(idx, device_is_stepper_controller); if (dev != NULL) { entry->syntax = dev->name; @@ -146,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; @@ -188,7 +250,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); } @@ -206,7 +268,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); } @@ -214,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); } @@ -241,8 +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; + 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) { @@ -254,12 +340,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); } @@ -270,7 +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; + + 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) { @@ -282,7 +376,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); } @@ -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_set_micro_step_res(dev, resolution); + err = stepper_drv_set_micro_step_res(dev, resolution); if (err) { shell_error(sh, "Error: %d", err); } @@ -332,7 +428,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 { @@ -345,7 +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; + + 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) { @@ -357,7 +461,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); } @@ -368,7 +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; + + 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); @@ -376,7 +488,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 { @@ -389,7 +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; + + 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) { @@ -401,12 +521,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); } @@ -417,9 +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; + 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; @@ -437,12 +566,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; @@ -451,13 +580,19 @@ 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; + uint8_t stepper_index; int err; bool is_moving; int32_t actual_position; - enum stepper_micro_step_resolution micro_step_res; + + 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) { @@ -467,25 +602,42 @@ 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; + 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; @@ -499,19 +651,21 @@ 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, 3, 0), - SHELL_CMD_ARG(get_actual_position, &dsub_pos_stepper_motor_name, "", - cmd_stepper_get_actual_position, 2, 0), - SHELL_CMD_ARG(set_microstep_interval, &dsub_pos_stepper_motor_name, - " ", cmd_stepper_set_microstep_interval, 3, 0), - SHELL_CMD_ARG(move_by, &dsub_pos_stepper_motor_name, " ", - cmd_stepper_move_by, 3, 0), - SHELL_CMD_ARG(move_to, &dsub_pos_stepper_motor_name, " ", - cmd_stepper_move_to, 3, 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(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_controller_name, + " ", cmd_stepper_set_microstep_interval, 4, 0), + SHELL_CMD_ARG(move_by, &dsub_pos_stepper_controller_name, " ", + cmd_stepper_move_by, 4, 0), + SHELL_CMD_ARG(move_to, &dsub_pos_stepper_controller_name, " ", + cmd_stepper_move_to, 4, 0), + SHELL_CMD_ARG(run, &dsub_pos_stepper_controller_name_dir, " ", + cmd_stepper_run, 4, 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); 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..f5bc4c4f1fe2 --- /dev/null +++ b/drivers/stepper/zephyr_stepper_motion_controller.c @@ -0,0 +1,404 @@ +/** + * 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); + +/* 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; + 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, MAX_SUPPORTED_STEPPER - 1, 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) { + /* 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 */ + 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, 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; + + 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, 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, stepper_idx, steps_to_move); +} + +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; + + 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 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; + + 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, + 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) { + data->actual_position = position; + } + return 0; +} + +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) { + *position = data->actual_position; + } + return 0; +} + +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; + + 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, 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; + + *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, + 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) { + 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 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) = { + .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..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-controller.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/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-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 d286dfbfeb4c..a32df4efd320 100644 --- a/dts/bindings/stepper/zephyr,fake-stepper.yaml +++ b/dts/bindings/stepper/zephyr,fake-stepper.yaml @@ -2,9 +2,8 @@ # 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" -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..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 */ @@ -102,8 +113,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, }; /** @@ -113,112 +122,87 @@ 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); + /** * @brief Set the time interval between steps in nanoseconds. * * @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,317 @@ 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); +} + +/** + * @} + */ + +/** + * @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) +{ + __ASSERT_NO_MSG(dev != NULL); + 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) +{ + __ASSERT_NO_MSG(dev != NULL); + 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) +{ + __ASSERT_NO_MSG(dev != NULL); + 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) +{ + __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) && + (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 res 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_step_res(const struct device *dev, + enum stepper_micro_step_resolution res); + +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 (api->set_micro_step_res == NULL) { + return -ENOSYS; + } + + if (!VALID_MICRO_STEP_RES(res)) { + return -EINVAL; + } + 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 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 *res); + +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, res); +} + +/** + * @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) +{ + __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) { + return -ENOSYS; + } + + return api->set_fault_cb(dev, callback, user_data); } /** 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/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..aedafd960f20 100644 --- a/samples/drivers/stepper/generic/src/main.c +++ b/samples/drivers/stepper/generic/src/main.c @@ -12,7 +12,11 @@ #include LOG_MODULE_REGISTER(stepper, CONFIG_STEPPER_LOG_LEVEL); -static const struct device *stepper = DEVICE_DT_GET(DT_ALIAS(stepper)); +/* 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)); enum stepper_mode { STEPPER_MODE_ENABLE, @@ -31,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: @@ -65,47 +69,59 @@ 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_motion_controller, + stepper_motion_controller->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); - stepper_set_event_callback(stepper, stepper_callback, NULL); - stepper_set_reference_position(stepper, 0); - stepper_set_microstep_interval(stepper, 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); + stepper_drv_enable(stepper_motion_controller); LOG_INF("mode: enable\n"); break; case STEPPER_MODE_STOP: - stepper_stop(stepper); + stepper_stop(stepper_motion_controller, STEPPER_INDEX); LOG_INF("mode: stop\n"); break; case STEPPER_MODE_ROTATE_CW: - stepper_run(stepper, 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, 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, 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, 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); + stepper_drv_disable(stepper_motion_controller); LOG_INF("mode: disable\n"); break; } @@ -118,7 +134,8 @@ static void monitor_thread(void) for (;;) { int32_t actual_position; - stepper_get_actual_position(stepper, &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 177d15926bcd..d14fa6e9830c 100644 --- a/tests/drivers/build_all/stepper/app.overlay +++ b/tests/drivers/build_all/stepper/app.overlay @@ -39,5 +39,17 @@ #include "uart.dtsi" }; + + zephyr_stepper_motion_control_counter: zephyr_stepper_motion_control_counter { + compatible = "zephyr,stepper-motion-control"; + status = "okay"; + 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/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/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..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: @@ -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, }; @@ -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/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..96d4b19004a7 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_step_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/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..018fb4321224 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_IDX 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,29 @@ 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_IDX " 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_IDX " 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 +89,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 +107,57 @@ 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_IDX " 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_IDX); - 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_IDX " 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_IDX + " 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_IDX + " foo"); zassert_not_equal(err, 0, " executed run with invalid direction value"); } @@ -151,22 +165,33 @@ 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_IDX); - 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_IDX); 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/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/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 caf4f3c5b3a7..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 @@ -7,7 +7,8 @@ / { aliases { - stepper = &adi_tmc2209; + stepper = &adi_tmc2209; + stepper-motion-control = &zephyr_stepper_motion_control; }; }; @@ -15,11 +16,16 @@ 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>; 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..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 @@ -7,7 +7,8 @@ / { aliases { - stepper = &adi_tmc2209; + stepper = &adi_tmc2209; + stepper-motion-control = &zephyr_stepper_motion_control; }; }; @@ -15,10 +16,15 @@ 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>; 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..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 @@ -8,6 +8,7 @@ / { aliases { stepper = &allegro_a4979; + stepper-motion-control = &zephyr_stepper_motion_control; }; }; @@ -15,13 +16,18 @@ 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>; 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..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 @@ -8,6 +8,7 @@ / { aliases { stepper = &allegro_a4979; + stepper-motion-control = &zephyr_stepper_motion_control; }; }; @@ -15,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>; @@ -23,4 +23,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..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 @@ -8,6 +8,7 @@ / { aliases { stepper = &ti_drv84xx; + stepper-motion-control = &zephyr_stepper_motion_control; }; }; @@ -15,13 +16,18 @@ 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>; 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..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 @@ -8,6 +8,7 @@ / { aliases { stepper = &ti_drv84xx; + stepper-motion-control = &zephyr_stepper_motion_control; }; }; @@ -15,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>; @@ -23,4 +23,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..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; @@ -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, }; @@ -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,26 +154,45 @@ 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); } +/* 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, 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, 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) { @@ -196,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 { 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