diff --git a/drivers/stepper/adi_tmc/CMakeLists.txt b/drivers/stepper/adi_tmc/CMakeLists.txt index a261deef908..c302952f5ad 100644 --- a/drivers/stepper/adi_tmc/CMakeLists.txt +++ b/drivers/stepper/adi_tmc/CMakeLists.txt @@ -5,4 +5,5 @@ zephyr_library() zephyr_library_property(ALLOW_EMPTY TRUE) zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC_SPI adi_tmc_spi.c) +zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC2209 adi_tmc22xx_stepper_controller.c) zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC5041 adi_tmc5041_stepper_controller.c) diff --git a/drivers/stepper/adi_tmc/Kconfig b/drivers/stepper/adi_tmc/Kconfig index 7a88ec598fe..db6c6ed7f05 100644 --- a/drivers/stepper/adi_tmc/Kconfig +++ b/drivers/stepper/adi_tmc/Kconfig @@ -26,30 +26,7 @@ config STEPPER_ADI_TMC_SPI comment "Trinamic Stepper Drivers" -config STEPPER_ADI_TMC5041 - bool "Activate trinamic tmc5041 stepper driver" - depends on DT_HAS_ADI_TMC5041_ENABLED && STEPPER_ADI_TMC - select STEPPER_ADI_TMC_SPI - default y - help - Stepper driver for TMC5041. - -config STEPPER_ADI_TMC5041_RAMPSTAT_POLL - bool "TMC5041 poll ramp status" - depends on STEPPER_ADI_TMC5041 - default y - help - When enabled, the ramp status will be polled on TMC5041, to check for events: - - TMC5041_POS_REACHED_EVENT - - TMC5041_STOP_SG_EVENT - - TMC5041_STOP_LEFT_EVENT - - TMC5041_STOP_RIGHT_EVENT - -config STEPPER_ADI_TMC5041_RAMPSTAT_POLL_INTERVAL_IN_MSEC - int "TMC5041 poll ramp status interval in ms" - depends on STEPPER_ADI_TMC5041_RAMPSTAT_POLL - default 100 - help - The interval in ms to poll the ramp status on TMC5041. +rsource "Kconfig.tmc22xx" +rsource "Kconfig.tmc5041" endif # STEPPER_ADI_TMC diff --git a/drivers/stepper/adi_tmc/Kconfig.tmc22xx b/drivers/stepper/adi_tmc/Kconfig.tmc22xx new file mode 100644 index 00000000000..081d4f5a52e --- /dev/null +++ b/drivers/stepper/adi_tmc/Kconfig.tmc22xx @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 Fabian Blatz +# SPDX-License-Identifier: Apache-2.0 + +config STEPPER_ADI_TMC2209 + bool "Activate trinamic tmc2209 stepper driver" + depends on DT_HAS_ADI_TMC2209_ENABLED + select STEP_DIR_STEPPER + default y + help + Stepper driver for TMC2209. diff --git a/drivers/stepper/adi_tmc/Kconfig.tmc5041 b/drivers/stepper/adi_tmc/Kconfig.tmc5041 new file mode 100644 index 00000000000..af3e0de4f82 --- /dev/null +++ b/drivers/stepper/adi_tmc/Kconfig.tmc5041 @@ -0,0 +1,28 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 Fabian Blatz +# SPDX-License-Identifier: Apache-2.0 + +config STEPPER_ADI_TMC5041 + bool "Activate trinamic tmc5041 stepper driver" + depends on DT_HAS_ADI_TMC5041_ENABLED && STEPPER_ADI_TMC + select STEPPER_ADI_TMC_SPI + default y + help + Stepper driver for TMC5041. + +config STEPPER_ADI_TMC5041_RAMPSTAT_POLL + bool "TMC5041 poll ramp status" + depends on STEPPER_ADI_TMC5041 + default y + help + When enabled, the ramp status will be polled on TMC5041, to check for events: + - TMC5041_POS_REACHED_EVENT + - TMC5041_STOP_SG_EVENT + - TMC5041_STOP_LEFT_EVENT + - TMC5041_STOP_RIGHT_EVENT + +config STEPPER_ADI_TMC5041_RAMPSTAT_POLL_INTERVAL_IN_MSEC + int "TMC5041 poll ramp status interval in ms" + depends on STEPPER_ADI_TMC5041_RAMPSTAT_POLL + default 100 + help + The interval in ms to poll the ramp status on TMC5041. diff --git a/drivers/stepper/adi_tmc/adi_tmc22xx_stepper_controller.c b/drivers/stepper/adi_tmc/adi_tmc22xx_stepper_controller.c new file mode 100644 index 00000000000..51e778eadb2 --- /dev/null +++ b/drivers/stepper/adi_tmc/adi_tmc22xx_stepper_controller.c @@ -0,0 +1,196 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 Fabian Blatz + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "../step_dir_stepper_common.h" + +#include +LOG_MODULE_REGISTER(tmc22xx, CONFIG_STEPPER_LOG_LEVEL); + +#define MSX_PIN_COUNT 2 +#define MSX_PIN_STATE_COUNT 4 + +struct tmc22xx_config { + struct step_dir_stepper_common_config common; + const struct gpio_dt_spec enable_pin; + const struct gpio_dt_spec *msx_pins; + enum stepper_micro_step_resolution *msx_resolutions; +}; + +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); + +static int tmc22xx_stepper_enable(const struct device *dev, const bool enable) +{ + const struct tmc22xx_config *config = dev->config; + + LOG_DBG("Stepper motor controller %s %s", dev->name, enable ? "enabled" : "disabled"); + if (enable) { + return gpio_pin_set_dt(&config->enable_pin, 1); + } else { + return gpio_pin_set_dt(&config->enable_pin, 0); + } +} + +static int tmc22xx_stepper_set_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution micro_step_res) +{ + struct tmc22xx_data *data = dev->data; + const struct tmc22xx_config *config = dev->config; + int ret; + + if (!config->msx_pins) { + LOG_ERR("Microstep resolution pins are not configured"); + return -ENODEV; + } + + for (uint8_t i = 0; i < MSX_PIN_STATE_COUNT; i++) { + if (micro_step_res != config->msx_resolutions[i]) { + continue; + } + + ret = gpio_pin_set_dt(&config->msx_pins[0], i & 0x01); + if (ret < 0) { + LOG_ERR("Failed to set MS1 pin: %d", ret); + return ret; + } + + ret = gpio_pin_set_dt(&config->msx_pins[1], (i & 0x02) >> 1); + if (ret < 0) { + LOG_ERR("Failed to set MS2 pin: %d", ret); + return ret; + } + + data->resolution = micro_step_res; + return 0; + } + + LOG_ERR("Unsupported microstep resolution: %d", micro_step_res); + return -EINVAL; +} + +static int tmc22xx_stepper_get_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution *micro_step_res) +{ + struct tmc22xx_data *data = dev->data; + + *micro_step_res = data->resolution; + return 0; +} + +static int tmc22xx_stepper_configure_msx_pins(const struct device *dev) +{ + const struct tmc22xx_config *config = dev->config; + int ret; + + for (uint8_t i = 0; i < MSX_PIN_COUNT; i++) { + if (!gpio_is_ready_dt(&config->msx_pins[i])) { + LOG_ERR("MSX pin %u are not ready", i); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&config->msx_pins[i], GPIO_OUTPUT); + if (ret < 0) { + LOG_ERR("Failed to configure msx pin %u", i); + return ret; + } + } + return 0; +} + +static int tmc22xx_stepper_init(const struct device *dev) +{ + const struct tmc22xx_config *config = dev->config; + struct tmc22xx_data *data = dev->data; + int ret; + + if (!gpio_is_ready_dt(&config->enable_pin)) { + LOG_ERR("GPIO pins are not ready"); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&config->enable_pin, GPIO_OUTPUT); + if (ret < 0) { + LOG_ERR("Failed to configure enable pin: %d", ret); + return ret; + } + + if (config->msx_pins) { + ret = tmc22xx_stepper_configure_msx_pins(dev); + if (ret < 0) { + LOG_ERR("Failed to configure MSX pins: %d", ret); + return ret; + } + + ret = tmc22xx_stepper_set_micro_step_res(dev, data->resolution); + if (ret < 0) { + LOG_ERR("Failed to set microstep resolution: %d", ret); + return ret; + } + } + + ret = step_dir_stepper_common_init(dev); + if (ret < 0) { + LOG_ERR("Failed to init step dir common stepper: %d", ret); + return ret; + } + + return 0; +} + +static DEVICE_API(stepper, tmc22xx_stepper_api) = { + .enable = tmc22xx_stepper_enable, + .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_max_velocity = step_dir_stepper_common_set_max_velocity, + .run = step_dir_stepper_common_run, + .set_event_callback = step_dir_stepper_common_set_event_callback, + .set_micro_step_res = tmc22xx_stepper_set_micro_step_res, + .get_micro_step_res = tmc22xx_stepper_get_micro_step_res, +}; + +#define TMC22XX_STEPPER_DEFINE(inst, msx_table) \ + IF_ENABLED(DT_INST_NODE_HAS_PROP(inst, msx_gpios), ( \ + static const struct gpio_dt_spec tmc22xx_stepper_msx_pins_##inst[] = { \ + DT_INST_FOREACH_PROP_ELEM_SEP( \ + inst, msx_gpios, GPIO_DT_SPEC_GET_BY_IDX, (,) \ + ), \ + }; \ + BUILD_ASSERT( \ + ARRAY_SIZE(tmc22xx_stepper_msx_pins_##inst) == MSX_PIN_COUNT, \ + "Two microstep config pins needed"); \ + )) \ + \ + static const struct tmc22xx_config tmc22xx_config_##inst = { \ + .common = STEP_DIR_STEPPER_DT_INST_COMMON_CONFIG_INIT(inst), \ + .enable_pin = GPIO_DT_SPEC_INST_GET(inst, enable_gpios), \ + .msx_pins = DT_INST_NODE_HAS_PROP(inst, msx_gpios) \ + ? tmc22xx_stepper_msx_pins_##inst \ + : NULL, \ + .msx_resolutions = msx_table, \ + }; \ + 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, \ + &tmc22xx_config_##inst, POST_KERNEL, CONFIG_STEPPER_INIT_PRIORITY, \ + &tmc22xx_stepper_api); + +#define DT_DRV_COMPAT adi_tmc2209 +static enum stepper_micro_step_resolution tmc2209_msx_resolutions[MSX_PIN_STATE_COUNT] = { + STEPPER_MICRO_STEP_8, + STEPPER_MICRO_STEP_32, + STEPPER_MICRO_STEP_64, + STEPPER_MICRO_STEP_16, +}; +DT_INST_FOREACH_STATUS_OKAY_VARGS(TMC22XX_STEPPER_DEFINE, tmc2209_msx_resolutions) +#undef DT_DRV_COMPAT diff --git a/drivers/stepper/step_dir_stepper_common.c b/drivers/stepper/step_dir_stepper_common.c index 1dfcff418ae..22ef6eef6f4 100644 --- a/drivers/stepper/step_dir_stepper_common.c +++ b/drivers/stepper/step_dir_stepper_common.c @@ -241,7 +241,7 @@ int step_dir_stepper_common_run(const struct device *dev, const enum stepper_dir K_SPINLOCK(&data->lock) { data->run_mode = STEPPER_RUN_MODE_VELOCITY; data->direction = direction; - if (value != 0) { + if (velocity != 0) { data->delay_in_us = USEC_PER_SEC / velocity; (void)k_work_reschedule(&data->stepper_dwork, K_NO_WAIT); } else { diff --git a/dts/bindings/stepper/adi/adi,tmc2209.yaml b/dts/bindings/stepper/adi/adi,tmc2209.yaml new file mode 100644 index 00000000000..c3ad3b81ed7 --- /dev/null +++ b/dts/bindings/stepper/adi/adi,tmc2209.yaml @@ -0,0 +1,45 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 Fabian Blatz +# SPDX-License-Identifier: Apache-2.0 + +description: | + Analog Devices TMC2209 stepper motor driver. + + Example: + tmc2209: tmc2209 { + compatible = "adi,tmc2209"; + enable-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + msx-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>, + <&gpio0 2 GPIO_ACTIVE_HIGH>; + step-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; + direction-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + dual-edge-step; + } + +compatible: "adi,tmc2209" + +include: + - name: stepper-controller.yaml + property-allowlist: + - micro-step-res + - step-gpios + - direction-gpios + +properties: + enable-gpios: + type: phandle-array + description: | + GPIO pins used to control the enable signal of the motor driver. + + msx-gpios: + type: phandle-array + description: | + An array of GPIO pins for configuring the microstep resolution of the driver. + The pins should be listed in the following order: + - MS1 + - MS2 + + dual-edge-step: + type: boolean + description: | + If present, the stepper motor controller supports dual edge step signals. + This means that the step signal can be toggled on both the rising and falling edge.