From b55397e0ceb2e2a763830cd39d8efe5630c833c9 Mon Sep 17 00:00:00 2001 From: Stefano Cottafavi Date: Sat, 2 Nov 2024 23:39:30 +0100 Subject: [PATCH 1/3] tmc5150 spi, sg not working - WIP --- drivers/stepper/adi_tmc/CMakeLists.txt | 1 + drivers/stepper/adi_tmc/Kconfig | 8 + .../adi_tmc/adi_tmc5160_stepper_controller.c | 670 ++++++++++++++++++ drivers/stepper/adi_tmc/adi_tmc_reg.h | 116 +++ dts/bindings/stepper/adi/adi,tmc5160.yaml | 113 +++ .../zephyr/drivers/stepper/stepper_trinamic.h | 25 + 6 files changed, 933 insertions(+) create mode 100644 drivers/stepper/adi_tmc/adi_tmc5160_stepper_controller.c create mode 100644 dts/bindings/stepper/adi/adi,tmc5160.yaml diff --git a/drivers/stepper/adi_tmc/CMakeLists.txt b/drivers/stepper/adi_tmc/CMakeLists.txt index a261deef90802..0a542e7a11b67 100644 --- a/drivers/stepper/adi_tmc/CMakeLists.txt +++ b/drivers/stepper/adi_tmc/CMakeLists.txt @@ -6,3 +6,4 @@ 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_TMC5041 adi_tmc5041_stepper_controller.c) +zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC5160 adi_tmc5160_stepper_controller.c) diff --git a/drivers/stepper/adi_tmc/Kconfig b/drivers/stepper/adi_tmc/Kconfig index 7a88ec598fe17..3f69ef396fdb0 100644 --- a/drivers/stepper/adi_tmc/Kconfig +++ b/drivers/stepper/adi_tmc/Kconfig @@ -52,4 +52,12 @@ config STEPPER_ADI_TMC5041_RAMPSTAT_POLL_INTERVAL_IN_MSEC help The interval in ms to poll the ramp status on TMC5041. +config STEPPER_ADI_TMC5160 + bool "Activate trinamic tmc5160 stepper driver" + depends on DT_HAS_ADI_TMC5160_ENABLED && STEPPER_ADI_TMC + select STEPPER_ADI_TMC_SPI + default y + help + Stepper driver for TMC5160. + endif # STEPPER_ADI_TMC diff --git a/drivers/stepper/adi_tmc/adi_tmc5160_stepper_controller.c b/drivers/stepper/adi_tmc/adi_tmc5160_stepper_controller.c new file mode 100644 index 0000000000000..c3992f5abfdd1 --- /dev/null +++ b/drivers/stepper/adi_tmc/adi_tmc5160_stepper_controller.c @@ -0,0 +1,670 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 Stefano Cottafavi + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_tmc5160 + +#include + +#include +#include + +#include "adi_tmc_reg.h" +#include "adi_tmc_spi.h" + +#include + +LOG_MODULE_REGISTER(tmc5160, CONFIG_STEPPER_LOG_LEVEL); + +struct tmc5160_data { + struct k_sem sem; +}; + +struct tmc5160_config { + const uint32_t gconf; + struct spi_dt_spec spi; + const uint32_t clock_frequency; +}; + +struct tmc5160_stepper_data { + struct k_work_delayable stallguard_dwork; + /* Work item to run the callback in a thread context. */ +#ifdef CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL + struct k_work_delayable rampstat_callback_dwork; +#endif + /* device pointer required to access config in k_work */ + const struct device *stepper; + stepper_event_callback_t callback; + void *event_cb_user_data; +}; + +struct tmc5160_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_TMC_RAMP_GEN + const struct tmc_ramp_generator_data default_ramp_config; +#endif +}; + +static int tmc5160_write(const struct device *dev, const uint8_t reg_addr, const uint32_t reg_val) +{ + const struct tmc5160_config *config = dev->config; + struct tmc5160_data *data = dev->data; + const struct spi_dt_spec bus = config->spi; + int err; + + k_sem_take(&data->sem, K_FOREVER); + + err = tmc_spi_write_register(&bus, TMC5160_WRITE_BIT, reg_addr, reg_val); + + k_sem_give(&data->sem); + + if (err) { + LOG_ERR("Failed to write register 0x%x with value 0x%x", reg_addr, reg_val); + return err; + } + return 0; +} + +static int tmc5160_read(const struct device *dev, const uint8_t reg_addr, uint32_t *reg_val) +{ + const struct tmc5160_config *config = dev->config; + struct tmc5160_data *data = dev->data; + const struct spi_dt_spec bus = config->spi; + int err; + + k_sem_take(&data->sem, K_FOREVER); + + err = tmc_spi_read_register(&bus, TMC5160_ADDRESS_MASK, reg_addr, reg_val); + + k_sem_give(&data->sem); + + if (err) { + LOG_ERR("Failed to read register 0x%x", reg_addr); + return err; + } + return 0; +} + +static void calculate_velocity_from_hz_to_fclk(const struct device *dev, const uint32_t velocity_hz, + uint32_t *const velocity_fclk) +{ + const struct tmc5160_config *config = dev->config; + + *velocity_fclk = + ((uint64_t)(velocity_hz) << TMC5160_CLOCK_FREQ_SHIFT) / config->clock_frequency; + LOG_DBG("Stepper motor controller %s velocity: %d Hz, velocity_fclk: %d", dev->name, + velocity_hz, *velocity_fclk); +} + +static int stallguard_enable(const struct device *dev, const bool enable) +{ + const struct tmc5160_stepper_config *config = dev->config; + uint32_t reg_value; + int err; + + err = tmc5160_read(config->controller, TMC5160_SWMODE, ®_value); + if (err) { + LOG_ERR("Failed to read SWMODE register"); + return -EIO; + } + + if (enable) { + reg_value |= TMC5160_SW_MODE_SG_STOP_ENABLE; + + int32_t actual_velocity; + + err = tmc5160_read(config->controller, TMC5160_VACTUAL, + &actual_velocity); + if (err) { + LOG_ERR("Failed to read VACTUAL register"); + return -EIO; + } + + actual_velocity = (actual_velocity << (31 - TMC_RAMP_VACTUAL_SHIFT)) >> + (31 - TMC_RAMP_VACTUAL_SHIFT); + LOG_DBG("actual velocity: %d", actual_velocity); + + if (abs(actual_velocity) < config->sg_threshold_velocity) { + return -EAGAIN; + } + } else { + reg_value &= ~TMC5160_SW_MODE_SG_STOP_ENABLE; + } + err = tmc5160_write(config->controller, TMC5160_SWMODE, reg_value); + if (err) { + LOG_ERR("Failed to write SWMODE register"); + return -EIO; + } + return 0; +} + +static void stallguard_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct tmc5160_stepper_data *stepper_data = + CONTAINER_OF(dwork, struct tmc5160_stepper_data, stallguard_dwork); + int err; + const struct tmc5160_stepper_config *stepper_config = stepper_data->stepper->config; + + err = stallguard_enable(stepper_data->stepper, true); + if (err == -EAGAIN) { + LOG_ERR("retrying stallguard activation"); + 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"); + return; + } +} + +static int tmc5160_stepper_set_event_callback(const struct device *dev, + stepper_event_callback_t callback, void *user_data) +{ + struct tmc5160_stepper_data *data = dev->data; + + data->callback = callback; + data->event_cb_user_data = user_data; + return 0; +} + +static int tmc5160_stepper_enable(const struct device *dev, const bool enable) +{ + LOG_DBG("Stepper motor controller %s %s", dev->name, enable ? "enabled" : "disabled"); + const struct tmc5160_stepper_config *config = dev->config; + uint32_t reg_value; + int err; + + err = tmc5160_read(config->controller, TMC5160_CHOPCONF, ®_value); + if (err != 0) { + return -EIO; + } + + if (enable) { + reg_value |= TMC5160_CHOPCONF_DRV_ENABLE_MASK; + } else { + reg_value &= ~TMC5160_CHOPCONF_DRV_ENABLE_MASK; + } + + err = tmc5160_write(config->controller, TMC5160_CHOPCONF, reg_value); + if (err != 0) { + return -EIO; + } + return 0; +} + +static int tmc5160_stepper_is_moving(const struct device *dev, bool *is_moving) +{ + const struct tmc5160_stepper_config *config = dev->config; + uint32_t reg_value; + int err; + + err = tmc5160_read(config->controller, TMC5160_DRVSTATUS, ®_value); + + if (err != 0) { + LOG_ERR("%s: Failed to read DRVSTATUS register", dev->name); + return -EIO; + } + + *is_moving = (FIELD_GET(TMC5160_DRV_STATUS_STST_BIT, reg_value) != 1U); + LOG_DBG("Stepper motor controller %s is moving: %d", dev->name, *is_moving); + return 0; +} + +static int tmc5160_stepper_move(const struct device *dev, const int32_t steps) +{ + const struct tmc5160_stepper_config *config = dev->config; + struct tmc5160_stepper_data *data = dev->data; + int err; + + if (config->is_sg_enabled) { + err = stallguard_enable(dev, false); + if (err != 0) { + return -EIO; + } + } + + int32_t position; + + err = stepper_get_actual_position(dev, &position); + if (err != 0) { + return -EIO; + } + int32_t target_position = position + steps; + + err = tmc5160_write(config->controller, TMC5160_RAMPMODE, + TMC5160_RAMPMODE_POSITIONING_MODE); + if (err != 0) { + return -EIO; + } + LOG_DBG("Stepper motor controller %s moved to %d by steps: %d", dev->name, target_position, + steps); + err = tmc5160_write(config->controller, TMC5160_XTARGET, target_position); + if (err != 0) { + return -EIO; + } + + if (config->is_sg_enabled) { + k_work_reschedule(&data->stallguard_dwork, + K_MSEC(config->sg_velocity_check_interval_ms)); + } +#ifdef CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL + if (data->callback) { + k_work_reschedule( + &data->rampstat_callback_dwork, + K_MSEC(CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); + } +#endif + return 0; +} + +static int tmc5160_stepper_set_max_velocity(const struct device *dev, uint32_t velocity) +{ + const struct tmc5160_stepper_config *config = dev->config; + uint32_t velocity_fclk; + int err; + + calculate_velocity_from_hz_to_fclk(config->controller, velocity, &velocity_fclk); + err = tmc5160_write(config->controller, TMC5160_VMAX, velocity_fclk); + if (err != 0) { + LOG_ERR("%s: Failed to set max velocity", dev->name); + return -EIO; + } + return 0; +} + +static int tmc5160_stepper_set_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution res) +{ + const struct tmc5160_stepper_config *config = dev->config; + uint32_t reg_value; + int err; + + err = tmc5160_read(config->controller, TMC5160_CHOPCONF, ®_value); + if (err != 0) { + return -EIO; + } + + reg_value &= ~TMC5160_CHOPCONF_MRES_MASK; + reg_value |= ((MICRO_STEP_RES_INDEX(STEPPER_MICRO_STEP_256) - LOG2(res)) + << TMC5160_CHOPCONF_MRES_SHIFT); + + err = tmc5160_write(config->controller, TMC5160_CHOPCONF, reg_value); + if (err != 0) { + return -EIO; + } + + LOG_DBG("Stepper motor controller %s set micro step resolution to 0x%x", dev->name, + reg_value); + return 0; +} + +static int tmc5160_stepper_get_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution *res) +{ + const struct tmc5160_stepper_config *config = dev->config; + uint32_t reg_value; + int err; + + err = tmc5160_read(config->controller, TMC5160_CHOPCONF, ®_value); + if (err != 0) { + return -EIO; + } + reg_value &= TMC5160_CHOPCONF_MRES_MASK; + reg_value >>= TMC5160_CHOPCONF_MRES_SHIFT; + *res = (1 << (MICRO_STEP_RES_INDEX(STEPPER_MICRO_STEP_256) - reg_value)); + LOG_DBG("Stepper motor controller %s get micro step resolution: %d", dev->name, *res); + return 0; +} + +static int tmc5160_stepper_set_actual_position(const struct device *dev, const int32_t position) +{ + const struct tmc5160_stepper_config *config = dev->config; + int err; + + err = tmc5160_write(config->controller, TMC5160_RAMPMODE, + TMC5160_RAMPMODE_HOLD_MODE); + if (err != 0) { + return -EIO; + } + + err = tmc5160_write(config->controller, TMC5160_XACTUAL, position); + if (err != 0) { + return -EIO; + } + LOG_DBG("Stepper motor controller %s set actual position to %d", dev->name, position); + return 0; +} + +static int tmc5160_stepper_get_actual_position(const struct device *dev, int32_t *position) +{ + const struct tmc5160_stepper_config *config = dev->config; + int err; + + err = tmc5160_read(config->controller, TMC5160_XACTUAL, position); + if (err != 0) { + return -EIO; + } + LOG_DBG("%s actual position: %d", dev->name, *position); + return 0; +} + +static int tmc5160_stepper_set_target_position(const struct device *dev, const int32_t position) +{ + LOG_DBG("Stepper motor controller %s set target position to %d", dev->name, position); + const struct tmc5160_stepper_config *config = dev->config; + struct tmc5160_stepper_data *data = dev->data; + int err; + + if (config->is_sg_enabled) { + stallguard_enable(dev, false); + } + + err = tmc5160_write(config->controller, TMC5160_RAMPMODE, + TMC5160_RAMPMODE_POSITIONING_MODE); + if (err != 0) { + return -EIO; + } + tmc5160_write(config->controller, TMC5160_XTARGET, position); + + if (config->is_sg_enabled) { + k_work_reschedule(&data->stallguard_dwork, + K_MSEC(config->sg_velocity_check_interval_ms)); + } +#ifdef CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL + if (data->callback) { + k_work_reschedule( + &data->rampstat_callback_dwork, + K_MSEC(CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); + } +#endif + return 0; +} + +static int tmc5160_stepper_enable_constant_velocity_mode(const struct device *dev, + const enum stepper_direction direction, + const uint32_t velocity) +{ + LOG_DBG("Stepper motor controller %s enable constant velocity mode", dev->name); + const struct tmc5160_stepper_config *config = dev->config; + struct tmc5160_stepper_data *data = dev->data; + uint32_t velocity_fclk; + int err; + + calculate_velocity_from_hz_to_fclk(config->controller, velocity, &velocity_fclk); + + if (config->is_sg_enabled) { + err = stallguard_enable(dev, false); + if (err != 0) { + return -EIO; + } + } + + switch (direction) { + case STEPPER_DIRECTION_POSITIVE: + err = tmc5160_write(config->controller, TMC5160_RAMPMODE, + TMC5160_RAMPMODE_POSITIVE_VELOCITY_MODE); + if (err != 0) { + return -EIO; + } + err = tmc5160_write(config->controller, TMC5160_VMAX, velocity_fclk); + if (err != 0) { + return -EIO; + } + break; + + case STEPPER_DIRECTION_NEGATIVE: + err = tmc5160_write(config->controller, TMC5160_RAMPMODE, + TMC5160_RAMPMODE_NEGATIVE_VELOCITY_MODE); + if (err != 0) { + return -EIO; + } + err = tmc5160_write(config->controller, TMC5160_VMAX, velocity_fclk); + if (err != 0) { + return -EIO; + } + break; + } + + if (config->is_sg_enabled) { + k_work_reschedule(&data->stallguard_dwork, + K_MSEC(config->sg_velocity_check_interval_ms)); + } +#ifdef CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL + if (data->callback) { + k_work_reschedule( + &data->rampstat_callback_dwork, + K_MSEC(CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); + } +#endif + return 0; +} + +#ifdef CONFIG_STEPPER_ADI_TMC_RAMP_GEN + +int tmc5160_stepper_set_ramp(const struct device *dev, + const struct tmc_ramp_generator_data *ramp_data) +{ + LOG_DBG("Stepper motor controller %s set ramp", dev->name); + const struct tmc5160_stepper_config *config = dev->config; + int err; + + err = tmc5160_write(config->controller, TMC5160_VSTART, ramp_data->vstart); + if (err != 0) { + return -EIO; + } + err = tmc5160_write(config->controller, TMC5160_A1, ramp_data->a1); + if (err != 0) { + return -EIO; + } + err = tmc5160_write(config->controller, TMC5160_AMAX, ramp_data->amax); + if (err != 0) { + return -EIO; + } + err = tmc5160_write(config->controller, TMC5160_D1, ramp_data->d1); + if (err != 0) { + return -EIO; + } + err = tmc5160_write(config->controller, TMC5160_DMAX, ramp_data->dmax); + if (err != 0) { + return -EIO; + } + err = tmc5160_write(config->controller, TMC5160_V1, ramp_data->v1); + if (err != 0) { + return -EIO; + } + err = tmc5160_write(config->controller, TMC5160_VMAX, ramp_data->vmax); + if (err != 0) { + return -EIO; + } + err = tmc5160_write(config->controller, TMC5160_VSTOP, ramp_data->vstop); + if (err != 0) { + return -EIO; + } + err = tmc5160_write(config->controller, TMC5160_TZEROWAIT, + ramp_data->tzerowait); + if (err != 0) { + return -EIO; + } + err = tmc5160_write(config->controller, TMC5160_THIGH, ramp_data->vhigh); + if (err != 0) { + return -EIO; + } + err = tmc5160_write(config->controller, TMC5160_TCOOLTHRS, + ramp_data->vcoolthrs); + if (err != 0) { + return -EIO; + } + err = tmc5160_write(config->controller, TMC5160_IHOLD_IRUN, + ramp_data->iholdrun); + if (err != 0) { + return -EIO; + } + return 0; +} + +#endif + +static int tmc5160_init(const struct device *dev) +{ + LOG_DBG("TMC5160 stepper motor controller %s initialized", dev->name); + struct tmc5160_data *data = dev->data; + const struct tmc5160_config *config = dev->config; + int err; + + k_sem_init(&data->sem, 1, 1); + + if (!spi_is_ready_dt(&config->spi)) { + LOG_ERR("SPI bus is not ready"); + return -ENODEV; + } + + /* Init non motor-index specific registers here. */ + LOG_DBG("GCONF: %d", config->gconf); + err = tmc5160_write(dev, TMC5160_GCONF, config->gconf); + if (err != 0) { + return -EIO; + } + + /* Read GSTAT register values to clear any errors SPI Datagram. */ + uint32_t gstat_value; + + err = tmc5160_read(dev, TMC5160_GSTAT, &gstat_value); + if (err != 0) { + return -EIO; + } + + LOG_DBG("Device %s initialized", dev->name); + return 0; +} + +static int tmc5160_stepper_init(const struct device *dev) +{ + const struct tmc5160_stepper_config *stepper_config = dev->config; + struct tmc5160_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 = tmc5160_write(stepper_config->controller, TMC5160_SWMODE, BIT(10)); + if (err != 0) { + return -EIO; + } + + 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, TMC5160_SG_MIN_VALUE, + TMC5160_SG_MAX_VALUE)) { + LOG_ERR("Stallguard threshold out of range"); + return -EINVAL; + } + + int32_t stall_guard_threshold = (int32_t)stepper_config->sg_threshold; + + err = tmc5160_write( + stepper_config->controller, TMC5160_COOLCONF, + stall_guard_threshold << TMC5160_COOLCONF_SG2_THRESHOLD_VALUE_SHIFT); + if (err != 0) { + return -EIO; + } + err = stallguard_enable(dev, true); + if (err == -EAGAIN) { + LOG_ERR("retrying stallguard activation"); + k_work_reschedule(&data->stallguard_dwork, + K_MSEC(stepper_config->sg_velocity_check_interval_ms)); + } + } + +#ifdef CONFIG_STEPPER_ADI_TMC_RAMP_GEN + err = tmc5160_stepper_set_ramp(dev, &stepper_config->default_ramp_config); + if (err != 0) { + return -EIO; + } +#endif + +#if CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL + k_work_init_delayable(&data->rampstat_callback_dwork, rampstat_work_handler); + k_work_reschedule(&data->rampstat_callback_dwork, + K_MSEC(CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); +#endif + err = tmc5160_stepper_set_micro_step_res(dev, stepper_config->default_micro_step_res); + if (err != 0) { + return -EIO; + } + return 0; +} + +#define TMC5160_SHAFT_CONFIG(child) \ + (DT_PROP(child, invert_direction) << TMC5160_GCONF_SHAFT_SHIFT) | + +#define TMC5160_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_TMC_RAMP_GEN, (CHECK_RAMP_DT_DATA(child))); \ + static const struct tmc5160_stepper_config tmc5160_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_TMC_RAMP_GEN, \ + (.default_ramp_config = TMC_RAMP_DT_SPEC_GET(child))) }; + +#define TMC5160_STEPPER_DATA_DEFINE(child) \ + static struct tmc5160_stepper_data tmc5160_stepper_data_##child = { \ + .stepper = DEVICE_DT_GET(child),}; + +#define TMC5160_STEPPER_API_DEFINE(child) \ + static const struct stepper_driver_api tmc5160_stepper_api_##child = { \ + .enable = tmc5160_stepper_enable, \ + .is_moving = tmc5160_stepper_is_moving, \ + .move = tmc5160_stepper_move, \ + .set_max_velocity = tmc5160_stepper_set_max_velocity, \ + .set_micro_step_res = tmc5160_stepper_set_micro_step_res, \ + .get_micro_step_res = tmc5160_stepper_get_micro_step_res, \ + .set_actual_position = tmc5160_stepper_set_actual_position, \ + .get_actual_position = tmc5160_stepper_get_actual_position, \ + .set_target_position = tmc5160_stepper_set_target_position, \ + .enable_constant_velocity_mode = tmc5160_stepper_enable_constant_velocity_mode, \ + .set_event_callback = tmc5160_stepper_set_event_callback, }; + +#define TMC5160_STEPPER_DEFINE(child) \ + DEVICE_DT_DEFINE(child, tmc5160_stepper_init, NULL, &tmc5160_stepper_data_##child, \ + &tmc5160_stepper_config_##child, POST_KERNEL, \ + CONFIG_STEPPER_INIT_PRIORITY, &tmc5160_stepper_api_##child); + +#define TMC5160_DEFINE(inst) \ + BUILD_ASSERT(DT_INST_CHILD_NUM(inst) <= 1, "tmc5160 can drive one stepper at max"); \ + BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) > 0), \ + "clock frequency must be non-zero positive value"); \ + static struct tmc5160_data tmc5160_data_##inst; \ + static const struct tmc5160_config tmc5160_config_##inst = { \ + .gconf = ( \ + DT_INST_FOREACH_CHILD(inst, TMC5160_SHAFT_CONFIG) \ + (DT_INST_PROP(inst, test_mode) << TMC5160_GCONF_TEST_MODE_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),}; \ + DT_INST_FOREACH_CHILD(inst, TMC5160_STEPPER_CONFIG_DEFINE); \ + DT_INST_FOREACH_CHILD(inst, TMC5160_STEPPER_DATA_DEFINE); \ + DT_INST_FOREACH_CHILD(inst, TMC5160_STEPPER_API_DEFINE); \ + DT_INST_FOREACH_CHILD(inst, TMC5160_STEPPER_DEFINE); \ + DEVICE_DT_INST_DEFINE(inst, tmc5160_init, NULL, &tmc5160_data_##inst, \ + &tmc5160_config_##inst, POST_KERNEL, CONFIG_STEPPER_INIT_PRIORITY,\ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(TMC5160_DEFINE) diff --git a/drivers/stepper/adi_tmc/adi_tmc_reg.h b/drivers/stepper/adi_tmc/adi_tmc_reg.h index 1c88020c352a4..17a7f159c80e2 100644 --- a/drivers/stepper/adi_tmc/adi_tmc_reg.h +++ b/drivers/stepper/adi_tmc/adi_tmc_reg.h @@ -137,6 +137,122 @@ extern "C" { #endif +#ifdef CONFIG_STEPPER_ADI_TMC5160 + +/** + * @name TMC5160 module registers + * @anchor TMC5160_REGISTERS + * + * @{ + */ + +#define TMC5160_GCONF_TEST_MODE_SHIFT 17 +#define TMC5160_GCONF_SHAFT_SHIFT 4 + +#define TMC5160_DRV_STATUS_STST_BIT BIT(31) + +#define TMC5160_WRITE_BIT 0x80U +#define TMC5160_ADDRESS_MASK 0x7FU + +#define TMC5160_GCONF 0x00 +#define TMC5160_GSTAT 0x01 +#define TMC5160_IFCNT 0x02 +#define TMC5160_SLAVECONF 0x03 +#define TMC5160_INP_OUT 0x04 +#define TMC5160_X_COMPARE 0x05 +#define TMC5160_OTP_PROG 0x06 +#define TMC5160_OTP_READ 0x07 +#define TMC5160_FACTORY_CONF 0x08 +#define TMC5160_SHORT_CONF 0x09 +#define TMC5160_DRV_CONF 0x0A +#define TMC5160_GLOBAL_SCALER 0x0B +#define TMC5160_OFFSET_READ 0x0C +#define TMC5160_IHOLD_IRUN 0x10 +#define TMC5160_TPOWERDOWN 0x11 +#define TMC5160_TSTEP 0x12 +#define TMC5160_TPWMTHRS 0x13 +#define TMC5160_TCOOLTHRS 0x14 +#define TMC5160_THIGH 0x15 + +#define TMC5160_RAMPMODE 0x20 +#define TMC5160_XACTUAL 0x21 +#define TMC5160_VACTUAL 0x22 +#define TMC5160_VSTART 0x23 +#define TMC5160_A1 0x24 +#define TMC5160_V1 0x25 +#define TMC5160_AMAX 0x26 +#define TMC5160_VMAX 0x27 +#define TMC5160_DMAX 0x28 +#define TMC5160_D1 0x2A +#define TMC5160_VSTOP 0x2B +#define TMC5160_TZEROWAIT 0x2C +#define TMC5160_XTARGET 0x2D + +#define TMC5160_VDCMIN 0x33 +#define TMC5160_SWMODE 0x34 +#define TMC5160_RAMPSTAT 0x35 +#define TMC5160_XLATCH 0x36 +#define TMC5160_ENCMODE 0x38 +#define TMC5160_XENC 0x39 +#define TMC5160_ENC_CONST 0x3A +#define TMC5160_ENC_STATUS 0x3B +#define TMC5160_ENC_LATCH 0x3C +#define TMC5160_ENC_DEVIATION 0x3D + +#define TMC5160_MSLUT0 0x60 +#define TMC5160_MSLUT1 0x61 +#define TMC5160_MSLUT2 0x62 +#define TMC5160_MSLUT3 0x63 +#define TMC5160_MSLUT4 0x64 +#define TMC5160_MSLUT5 0x65 +#define TMC5160_MSLUT6 0x66 +#define TMC5160_MSLUT7 0x67 +#define TMC5160_MSLUTSEL 0x68 +#define TMC5160_MSLUTSTART 0x69 +#define TMC5160_MSCNT 0x6A +#define TMC5160_MSCURACT 0x6B +#define TMC5160_CHOPCONF 0x6C +#define TMC5160_COOLCONF 0x6D +#define TMC5160_DCCTRL 0x6E +#define TMC5160_DRVSTATUS 0x6F +#define TMC5160_PWMCONF 0x70 +#define TMC5160_PWMSCALE 0x71 +#define TMC5160_PWM_AUTO 0x72 +#define TMC5160_LOST_STEPS 0x73 + + +#define TMC5160_RAMPMODE_POSITIONING_MODE 0 +#define TMC5160_RAMPMODE_POSITIVE_VELOCITY_MODE 1 +#define TMC5160_RAMPMODE_NEGATIVE_VELOCITY_MODE 2 +#define TMC5160_RAMPMODE_HOLD_MODE 3 + +#define TMC5160_SW_MODE_SG_STOP_ENABLE BIT(10) + +#define TMC5160_SG_MIN_VALUE -64 +#define TMC5160_SG_MAX_VALUE 63 + +#define TMC5160_COOLCONF_SG2_THRESHOLD_VALUE_SHIFT 16 + +#define TMC5160_IHOLD_MASK GENMASK(4, 0) +#define TMC5160_IHOLD_SHIFT 0 +#define TMC5160_IHOLD(n) (((n) << TMC5160_IHOLD_SHIFT) & TMC5160_IHOLD_MASK) + +#define TMC5160_IRUN_MASK GENMASK(12, 8) +#define TMC5160_IRUN_SHIFT 8 +#define TMC5160_IRUN(n) (((n) << TMC5160_IRUN_SHIFT) & TMC5160_IRUN_MASK) + +#define TMC5160_IHOLDDELAY_MASK GENMASK(19, 16) +#define TMC5160_IHOLDDELAY_SHIFT 16 +#define TMC5160_IHOLDDELAY(n) (((n) << TMC5160_IHOLDDELAY_SHIFT) & TMC5160_IHOLDDELAY_MASK) + +#define TMC5160_CHOPCONF_DRV_ENABLE_MASK GENMASK(3, 0) +#define TMC5160_CHOPCONF_MRES_MASK GENMASK(27, 24) +#define TMC5160_CHOPCONF_MRES_SHIFT 24 + +#define TMC5160_CLOCK_FREQ_SHIFT 24 + +#endif + /** * @} */ diff --git a/dts/bindings/stepper/adi/adi,tmc5160.yaml b/dts/bindings/stepper/adi/adi,tmc5160.yaml new file mode 100644 index 0000000000000..a13684c08826b --- /dev/null +++ b/dts/bindings/stepper/adi/adi,tmc5160.yaml @@ -0,0 +1,113 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 Stefano Cottafavi +# SPDX-License-Identifier: Apache-2.0 + +description: | + Analog Devices TMC5160 Stepper Motor Controller + + Example: + + &spi0 { + /* SPI bus options here, not shown */ + + tmc5160: tmc5160@0 { + compatible = "adi,tmc5160"; + reg = <0>; + spi-max-frequency = ; /* Maximum SPI bus frequency */ + + #address-cells = <1>; + #size-cells = <0>; + + clock-frequency = ; /* Internal/External Clock frequency */ + + motor: motor@0 { + status = "okay"; + reg = <0>; + + /* common stepper controller settings */ + invert-direction; + micro-step-res = <256>; + + /* ADI TMC stallguard settings specific to TMC5041 */ + activate-stallguard2; + stallguard-velocity-check-interval-ms=<100>; + stallguard2-threshold=<9>; + stallguard-threshold-velocity=<500000>; + + /* 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>; + vhigh = <90>; + vcoolthrs = <100>; + ihold = <1>; + irun = <2>; + iholddelay = <3>; + }; + }; + }; + + +compatible: "adi,tmc5160" + +include: + - name: spi-device.yaml + - name: adi,trinamic-gconf.yaml + property-allowlist: + - shaft + - test_mode + +properties: + "#address-cells": + default: 1 + const: 1 + + "#size-cells": + default: 0 + const: 0 + + clock-frequency: + type: int + required: true + description: | + The frequency of the clock signal provided to the TMC5160. + This is used for real world conversion. + + Hint: µstep velocity v[Hz] µsteps / s v[Hz] = v[5160] * ( fCLK[Hz]/2 / 2^23 ) + where v[5160] is the value written to the TMC5160. + +child-binding: + include: + - name: base.yaml + property-allowlist: + - reg + - name: stepper-controller.yaml + property-allowlist: + - invert-direction + - micro-step-res + - name: adi,trinamic-ramp-generator.yaml + property-allowlist: + - vstart + - a1 + - v1 + - amax + - vmax + - dmax + - d1 + - vstop + - tzerowait + - vhigh + - vcoolthrs + - 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/include/zephyr/drivers/stepper/stepper_trinamic.h b/include/zephyr/drivers/stepper/stepper_trinamic.h index d36707c14b0b0..f7613660c1eb6 100644 --- a/include/zephyr/drivers/stepper/stepper_trinamic.h +++ b/include/zephyr/drivers/stepper/stepper_trinamic.h @@ -131,6 +131,7 @@ struct tmc_ramp_generator_data { * * @return struct tmc_ramp_generator_data */ +#ifdef CONFIG_STEPPER_ADI_TMC5041 #define TMC_RAMP_DT_SPEC_GET(node) \ { \ .vstart = DT_PROP(node, vstart), \ @@ -148,6 +149,25 @@ struct tmc_ramp_generator_data { TMC5041_IHOLD(DT_PROP(node, ihold)) | \ TMC5041_IHOLDDELAY(DT_PROP(node, iholddelay))), \ } +#elif CONFIG_STEPPER_ADI_TMC5160 +#define TMC_RAMP_DT_SPEC_GET(node) \ + { \ + .vstart = DT_PROP(node, vstart), \ + .v1 = DT_PROP(node, v1), \ + .vmax = DT_PROP(node, vmax), \ + .a1 = DT_PROP(node, a1), \ + .amax = DT_PROP(node, amax), \ + .d1 = DT_PROP(node, d1), \ + .dmax = DT_PROP(node, dmax), \ + .vstop = DT_PROP(node, vstop), \ + .tzerowait = DT_PROP(node, tzerowait), \ + .vcoolthrs = DT_PROP(node, vcoolthrs), \ + .vhigh = DT_PROP(node, vhigh), \ + .iholdrun = (TMC5160_IRUN(DT_PROP(node, irun)) | \ + TMC5160_IHOLD(DT_PROP(node, ihold)) | \ + TMC5160_IHOLDDELAY(DT_PROP(node, iholddelay))), \ + } +#endif /** * @brief Configure Trinamic Stepper Ramp Generator @@ -159,8 +179,13 @@ struct tmc_ramp_generator_data { * @retval -ENOSYS If not implemented by device driver * @retval 0 Success */ +#ifdef CONFIG_STEPPER_ADI_TMC5041 int tmc5041_stepper_set_ramp(const struct device *dev, const struct tmc_ramp_generator_data *ramp_data); +#elif CONFIG_STEPPER_ADI_TMC5160 +int tmc5160_stepper_set_ramp(const struct device *dev, + const struct tmc_ramp_generator_data *ramp_data); +#endif /** * @} From 25e35e97500fcda8eefa9ecd437298678df26800 Mon Sep 17 00:00:00 2001 From: Stefano Cottafavi Date: Wed, 6 Nov 2024 00:25:25 +0100 Subject: [PATCH 2/3] made generic (tmc51xx), removed child nodes, added SG --- drivers/stepper/adi_tmc/CMakeLists.txt | 2 +- drivers/stepper/adi_tmc/Kconfig | 26 +- .../adi_tmc/adi_tmc5160_stepper_controller.c | 670 ---------------- .../adi_tmc/adi_tmc51xx_stepper_controller.c | 727 ++++++++++++++++++ drivers/stepper/adi_tmc/adi_tmc_reg.h | 237 +++--- drivers/stepper/adi_tmc/adi_tmc_spi.c | 4 +- dts/bindings/stepper/adi/adi,tmc5160.yaml | 113 --- dts/bindings/stepper/adi/adi,tmc51xx.yaml | 101 +++ .../zephyr/drivers/stepper/stepper_trinamic.h | 21 - 9 files changed, 984 insertions(+), 917 deletions(-) delete mode 100644 drivers/stepper/adi_tmc/adi_tmc5160_stepper_controller.c create mode 100644 drivers/stepper/adi_tmc/adi_tmc51xx_stepper_controller.c delete mode 100644 dts/bindings/stepper/adi/adi,tmc5160.yaml create mode 100644 dts/bindings/stepper/adi/adi,tmc51xx.yaml diff --git a/drivers/stepper/adi_tmc/CMakeLists.txt b/drivers/stepper/adi_tmc/CMakeLists.txt index 0a542e7a11b67..9412fb506a0a2 100644 --- a/drivers/stepper/adi_tmc/CMakeLists.txt +++ b/drivers/stepper/adi_tmc/CMakeLists.txt @@ -6,4 +6,4 @@ 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_TMC5041 adi_tmc5041_stepper_controller.c) -zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC5160 adi_tmc5160_stepper_controller.c) +zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC51XX adi_tmc51xx_stepper_controller.c) diff --git a/drivers/stepper/adi_tmc/Kconfig b/drivers/stepper/adi_tmc/Kconfig index 3f69ef396fdb0..ce1abdba16652 100644 --- a/drivers/stepper/adi_tmc/Kconfig +++ b/drivers/stepper/adi_tmc/Kconfig @@ -52,12 +52,30 @@ config STEPPER_ADI_TMC5041_RAMPSTAT_POLL_INTERVAL_IN_MSEC help The interval in ms to poll the ramp status on TMC5041. -config STEPPER_ADI_TMC5160 - bool "Activate trinamic tmc5160 stepper driver" - depends on DT_HAS_ADI_TMC5160_ENABLED && STEPPER_ADI_TMC +config STEPPER_ADI_TMC51XX + bool "Activate trinamic tmc5130/tmc5160 stepper driver" + depends on DT_HAS_ADI_TMC51XX_ENABLED && STEPPER_ADI_TMC select STEPPER_ADI_TMC_SPI default y help - Stepper driver for TMC5160. + Stepper driver for TMC5130/TMC5160. + +config STEPPER_ADI_TMC51XX_RAMPSTAT_POLL + bool "TMC51XX poll ramp status" + depends on STEPPER_ADI_TMC51XX + default y + help + When enabled, the ramp status will be polled on TMC51XX, to check for events: + - TMC51XX_POS_REACHED_EVENT + - TMC51XX_STOP_SG_EVENT + - TMC51XX_STOP_LEFT_EVENT + - TMC51XX_STOP_RIGHT_EVENT + +config STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC + int "TMC51XX poll ramp status interval in ms" + depends on STEPPER_ADI_TMC51XX_RAMPSTAT_POLL + default 100 + help + The interval in ms to poll the ramp status on TMC51XX. endif # STEPPER_ADI_TMC diff --git a/drivers/stepper/adi_tmc/adi_tmc5160_stepper_controller.c b/drivers/stepper/adi_tmc/adi_tmc5160_stepper_controller.c deleted file mode 100644 index c3992f5abfdd1..0000000000000 --- a/drivers/stepper/adi_tmc/adi_tmc5160_stepper_controller.c +++ /dev/null @@ -1,670 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2024 Stefano Cottafavi - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT adi_tmc5160 - -#include - -#include -#include - -#include "adi_tmc_reg.h" -#include "adi_tmc_spi.h" - -#include - -LOG_MODULE_REGISTER(tmc5160, CONFIG_STEPPER_LOG_LEVEL); - -struct tmc5160_data { - struct k_sem sem; -}; - -struct tmc5160_config { - const uint32_t gconf; - struct spi_dt_spec spi; - const uint32_t clock_frequency; -}; - -struct tmc5160_stepper_data { - struct k_work_delayable stallguard_dwork; - /* Work item to run the callback in a thread context. */ -#ifdef CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL - struct k_work_delayable rampstat_callback_dwork; -#endif - /* device pointer required to access config in k_work */ - const struct device *stepper; - stepper_event_callback_t callback; - void *event_cb_user_data; -}; - -struct tmc5160_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_TMC_RAMP_GEN - const struct tmc_ramp_generator_data default_ramp_config; -#endif -}; - -static int tmc5160_write(const struct device *dev, const uint8_t reg_addr, const uint32_t reg_val) -{ - const struct tmc5160_config *config = dev->config; - struct tmc5160_data *data = dev->data; - const struct spi_dt_spec bus = config->spi; - int err; - - k_sem_take(&data->sem, K_FOREVER); - - err = tmc_spi_write_register(&bus, TMC5160_WRITE_BIT, reg_addr, reg_val); - - k_sem_give(&data->sem); - - if (err) { - LOG_ERR("Failed to write register 0x%x with value 0x%x", reg_addr, reg_val); - return err; - } - return 0; -} - -static int tmc5160_read(const struct device *dev, const uint8_t reg_addr, uint32_t *reg_val) -{ - const struct tmc5160_config *config = dev->config; - struct tmc5160_data *data = dev->data; - const struct spi_dt_spec bus = config->spi; - int err; - - k_sem_take(&data->sem, K_FOREVER); - - err = tmc_spi_read_register(&bus, TMC5160_ADDRESS_MASK, reg_addr, reg_val); - - k_sem_give(&data->sem); - - if (err) { - LOG_ERR("Failed to read register 0x%x", reg_addr); - return err; - } - return 0; -} - -static void calculate_velocity_from_hz_to_fclk(const struct device *dev, const uint32_t velocity_hz, - uint32_t *const velocity_fclk) -{ - const struct tmc5160_config *config = dev->config; - - *velocity_fclk = - ((uint64_t)(velocity_hz) << TMC5160_CLOCK_FREQ_SHIFT) / config->clock_frequency; - LOG_DBG("Stepper motor controller %s velocity: %d Hz, velocity_fclk: %d", dev->name, - velocity_hz, *velocity_fclk); -} - -static int stallguard_enable(const struct device *dev, const bool enable) -{ - const struct tmc5160_stepper_config *config = dev->config; - uint32_t reg_value; - int err; - - err = tmc5160_read(config->controller, TMC5160_SWMODE, ®_value); - if (err) { - LOG_ERR("Failed to read SWMODE register"); - return -EIO; - } - - if (enable) { - reg_value |= TMC5160_SW_MODE_SG_STOP_ENABLE; - - int32_t actual_velocity; - - err = tmc5160_read(config->controller, TMC5160_VACTUAL, - &actual_velocity); - if (err) { - LOG_ERR("Failed to read VACTUAL register"); - return -EIO; - } - - actual_velocity = (actual_velocity << (31 - TMC_RAMP_VACTUAL_SHIFT)) >> - (31 - TMC_RAMP_VACTUAL_SHIFT); - LOG_DBG("actual velocity: %d", actual_velocity); - - if (abs(actual_velocity) < config->sg_threshold_velocity) { - return -EAGAIN; - } - } else { - reg_value &= ~TMC5160_SW_MODE_SG_STOP_ENABLE; - } - err = tmc5160_write(config->controller, TMC5160_SWMODE, reg_value); - if (err) { - LOG_ERR("Failed to write SWMODE register"); - return -EIO; - } - return 0; -} - -static void stallguard_work_handler(struct k_work *work) -{ - struct k_work_delayable *dwork = k_work_delayable_from_work(work); - struct tmc5160_stepper_data *stepper_data = - CONTAINER_OF(dwork, struct tmc5160_stepper_data, stallguard_dwork); - int err; - const struct tmc5160_stepper_config *stepper_config = stepper_data->stepper->config; - - err = stallguard_enable(stepper_data->stepper, true); - if (err == -EAGAIN) { - LOG_ERR("retrying stallguard activation"); - 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"); - return; - } -} - -static int tmc5160_stepper_set_event_callback(const struct device *dev, - stepper_event_callback_t callback, void *user_data) -{ - struct tmc5160_stepper_data *data = dev->data; - - data->callback = callback; - data->event_cb_user_data = user_data; - return 0; -} - -static int tmc5160_stepper_enable(const struct device *dev, const bool enable) -{ - LOG_DBG("Stepper motor controller %s %s", dev->name, enable ? "enabled" : "disabled"); - const struct tmc5160_stepper_config *config = dev->config; - uint32_t reg_value; - int err; - - err = tmc5160_read(config->controller, TMC5160_CHOPCONF, ®_value); - if (err != 0) { - return -EIO; - } - - if (enable) { - reg_value |= TMC5160_CHOPCONF_DRV_ENABLE_MASK; - } else { - reg_value &= ~TMC5160_CHOPCONF_DRV_ENABLE_MASK; - } - - err = tmc5160_write(config->controller, TMC5160_CHOPCONF, reg_value); - if (err != 0) { - return -EIO; - } - return 0; -} - -static int tmc5160_stepper_is_moving(const struct device *dev, bool *is_moving) -{ - const struct tmc5160_stepper_config *config = dev->config; - uint32_t reg_value; - int err; - - err = tmc5160_read(config->controller, TMC5160_DRVSTATUS, ®_value); - - if (err != 0) { - LOG_ERR("%s: Failed to read DRVSTATUS register", dev->name); - return -EIO; - } - - *is_moving = (FIELD_GET(TMC5160_DRV_STATUS_STST_BIT, reg_value) != 1U); - LOG_DBG("Stepper motor controller %s is moving: %d", dev->name, *is_moving); - return 0; -} - -static int tmc5160_stepper_move(const struct device *dev, const int32_t steps) -{ - const struct tmc5160_stepper_config *config = dev->config; - struct tmc5160_stepper_data *data = dev->data; - int err; - - if (config->is_sg_enabled) { - err = stallguard_enable(dev, false); - if (err != 0) { - return -EIO; - } - } - - int32_t position; - - err = stepper_get_actual_position(dev, &position); - if (err != 0) { - return -EIO; - } - int32_t target_position = position + steps; - - err = tmc5160_write(config->controller, TMC5160_RAMPMODE, - TMC5160_RAMPMODE_POSITIONING_MODE); - if (err != 0) { - return -EIO; - } - LOG_DBG("Stepper motor controller %s moved to %d by steps: %d", dev->name, target_position, - steps); - err = tmc5160_write(config->controller, TMC5160_XTARGET, target_position); - if (err != 0) { - return -EIO; - } - - if (config->is_sg_enabled) { - k_work_reschedule(&data->stallguard_dwork, - K_MSEC(config->sg_velocity_check_interval_ms)); - } -#ifdef CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL - if (data->callback) { - k_work_reschedule( - &data->rampstat_callback_dwork, - K_MSEC(CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); - } -#endif - return 0; -} - -static int tmc5160_stepper_set_max_velocity(const struct device *dev, uint32_t velocity) -{ - const struct tmc5160_stepper_config *config = dev->config; - uint32_t velocity_fclk; - int err; - - calculate_velocity_from_hz_to_fclk(config->controller, velocity, &velocity_fclk); - err = tmc5160_write(config->controller, TMC5160_VMAX, velocity_fclk); - if (err != 0) { - LOG_ERR("%s: Failed to set max velocity", dev->name); - return -EIO; - } - return 0; -} - -static int tmc5160_stepper_set_micro_step_res(const struct device *dev, - enum stepper_micro_step_resolution res) -{ - const struct tmc5160_stepper_config *config = dev->config; - uint32_t reg_value; - int err; - - err = tmc5160_read(config->controller, TMC5160_CHOPCONF, ®_value); - if (err != 0) { - return -EIO; - } - - reg_value &= ~TMC5160_CHOPCONF_MRES_MASK; - reg_value |= ((MICRO_STEP_RES_INDEX(STEPPER_MICRO_STEP_256) - LOG2(res)) - << TMC5160_CHOPCONF_MRES_SHIFT); - - err = tmc5160_write(config->controller, TMC5160_CHOPCONF, reg_value); - if (err != 0) { - return -EIO; - } - - LOG_DBG("Stepper motor controller %s set micro step resolution to 0x%x", dev->name, - reg_value); - return 0; -} - -static int tmc5160_stepper_get_micro_step_res(const struct device *dev, - enum stepper_micro_step_resolution *res) -{ - const struct tmc5160_stepper_config *config = dev->config; - uint32_t reg_value; - int err; - - err = tmc5160_read(config->controller, TMC5160_CHOPCONF, ®_value); - if (err != 0) { - return -EIO; - } - reg_value &= TMC5160_CHOPCONF_MRES_MASK; - reg_value >>= TMC5160_CHOPCONF_MRES_SHIFT; - *res = (1 << (MICRO_STEP_RES_INDEX(STEPPER_MICRO_STEP_256) - reg_value)); - LOG_DBG("Stepper motor controller %s get micro step resolution: %d", dev->name, *res); - return 0; -} - -static int tmc5160_stepper_set_actual_position(const struct device *dev, const int32_t position) -{ - const struct tmc5160_stepper_config *config = dev->config; - int err; - - err = tmc5160_write(config->controller, TMC5160_RAMPMODE, - TMC5160_RAMPMODE_HOLD_MODE); - if (err != 0) { - return -EIO; - } - - err = tmc5160_write(config->controller, TMC5160_XACTUAL, position); - if (err != 0) { - return -EIO; - } - LOG_DBG("Stepper motor controller %s set actual position to %d", dev->name, position); - return 0; -} - -static int tmc5160_stepper_get_actual_position(const struct device *dev, int32_t *position) -{ - const struct tmc5160_stepper_config *config = dev->config; - int err; - - err = tmc5160_read(config->controller, TMC5160_XACTUAL, position); - if (err != 0) { - return -EIO; - } - LOG_DBG("%s actual position: %d", dev->name, *position); - return 0; -} - -static int tmc5160_stepper_set_target_position(const struct device *dev, const int32_t position) -{ - LOG_DBG("Stepper motor controller %s set target position to %d", dev->name, position); - const struct tmc5160_stepper_config *config = dev->config; - struct tmc5160_stepper_data *data = dev->data; - int err; - - if (config->is_sg_enabled) { - stallguard_enable(dev, false); - } - - err = tmc5160_write(config->controller, TMC5160_RAMPMODE, - TMC5160_RAMPMODE_POSITIONING_MODE); - if (err != 0) { - return -EIO; - } - tmc5160_write(config->controller, TMC5160_XTARGET, position); - - if (config->is_sg_enabled) { - k_work_reschedule(&data->stallguard_dwork, - K_MSEC(config->sg_velocity_check_interval_ms)); - } -#ifdef CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL - if (data->callback) { - k_work_reschedule( - &data->rampstat_callback_dwork, - K_MSEC(CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); - } -#endif - return 0; -} - -static int tmc5160_stepper_enable_constant_velocity_mode(const struct device *dev, - const enum stepper_direction direction, - const uint32_t velocity) -{ - LOG_DBG("Stepper motor controller %s enable constant velocity mode", dev->name); - const struct tmc5160_stepper_config *config = dev->config; - struct tmc5160_stepper_data *data = dev->data; - uint32_t velocity_fclk; - int err; - - calculate_velocity_from_hz_to_fclk(config->controller, velocity, &velocity_fclk); - - if (config->is_sg_enabled) { - err = stallguard_enable(dev, false); - if (err != 0) { - return -EIO; - } - } - - switch (direction) { - case STEPPER_DIRECTION_POSITIVE: - err = tmc5160_write(config->controller, TMC5160_RAMPMODE, - TMC5160_RAMPMODE_POSITIVE_VELOCITY_MODE); - if (err != 0) { - return -EIO; - } - err = tmc5160_write(config->controller, TMC5160_VMAX, velocity_fclk); - if (err != 0) { - return -EIO; - } - break; - - case STEPPER_DIRECTION_NEGATIVE: - err = tmc5160_write(config->controller, TMC5160_RAMPMODE, - TMC5160_RAMPMODE_NEGATIVE_VELOCITY_MODE); - if (err != 0) { - return -EIO; - } - err = tmc5160_write(config->controller, TMC5160_VMAX, velocity_fclk); - if (err != 0) { - return -EIO; - } - break; - } - - if (config->is_sg_enabled) { - k_work_reschedule(&data->stallguard_dwork, - K_MSEC(config->sg_velocity_check_interval_ms)); - } -#ifdef CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL - if (data->callback) { - k_work_reschedule( - &data->rampstat_callback_dwork, - K_MSEC(CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); - } -#endif - return 0; -} - -#ifdef CONFIG_STEPPER_ADI_TMC_RAMP_GEN - -int tmc5160_stepper_set_ramp(const struct device *dev, - const struct tmc_ramp_generator_data *ramp_data) -{ - LOG_DBG("Stepper motor controller %s set ramp", dev->name); - const struct tmc5160_stepper_config *config = dev->config; - int err; - - err = tmc5160_write(config->controller, TMC5160_VSTART, ramp_data->vstart); - if (err != 0) { - return -EIO; - } - err = tmc5160_write(config->controller, TMC5160_A1, ramp_data->a1); - if (err != 0) { - return -EIO; - } - err = tmc5160_write(config->controller, TMC5160_AMAX, ramp_data->amax); - if (err != 0) { - return -EIO; - } - err = tmc5160_write(config->controller, TMC5160_D1, ramp_data->d1); - if (err != 0) { - return -EIO; - } - err = tmc5160_write(config->controller, TMC5160_DMAX, ramp_data->dmax); - if (err != 0) { - return -EIO; - } - err = tmc5160_write(config->controller, TMC5160_V1, ramp_data->v1); - if (err != 0) { - return -EIO; - } - err = tmc5160_write(config->controller, TMC5160_VMAX, ramp_data->vmax); - if (err != 0) { - return -EIO; - } - err = tmc5160_write(config->controller, TMC5160_VSTOP, ramp_data->vstop); - if (err != 0) { - return -EIO; - } - err = tmc5160_write(config->controller, TMC5160_TZEROWAIT, - ramp_data->tzerowait); - if (err != 0) { - return -EIO; - } - err = tmc5160_write(config->controller, TMC5160_THIGH, ramp_data->vhigh); - if (err != 0) { - return -EIO; - } - err = tmc5160_write(config->controller, TMC5160_TCOOLTHRS, - ramp_data->vcoolthrs); - if (err != 0) { - return -EIO; - } - err = tmc5160_write(config->controller, TMC5160_IHOLD_IRUN, - ramp_data->iholdrun); - if (err != 0) { - return -EIO; - } - return 0; -} - -#endif - -static int tmc5160_init(const struct device *dev) -{ - LOG_DBG("TMC5160 stepper motor controller %s initialized", dev->name); - struct tmc5160_data *data = dev->data; - const struct tmc5160_config *config = dev->config; - int err; - - k_sem_init(&data->sem, 1, 1); - - if (!spi_is_ready_dt(&config->spi)) { - LOG_ERR("SPI bus is not ready"); - return -ENODEV; - } - - /* Init non motor-index specific registers here. */ - LOG_DBG("GCONF: %d", config->gconf); - err = tmc5160_write(dev, TMC5160_GCONF, config->gconf); - if (err != 0) { - return -EIO; - } - - /* Read GSTAT register values to clear any errors SPI Datagram. */ - uint32_t gstat_value; - - err = tmc5160_read(dev, TMC5160_GSTAT, &gstat_value); - if (err != 0) { - return -EIO; - } - - LOG_DBG("Device %s initialized", dev->name); - return 0; -} - -static int tmc5160_stepper_init(const struct device *dev) -{ - const struct tmc5160_stepper_config *stepper_config = dev->config; - struct tmc5160_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 = tmc5160_write(stepper_config->controller, TMC5160_SWMODE, BIT(10)); - if (err != 0) { - return -EIO; - } - - 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, TMC5160_SG_MIN_VALUE, - TMC5160_SG_MAX_VALUE)) { - LOG_ERR("Stallguard threshold out of range"); - return -EINVAL; - } - - int32_t stall_guard_threshold = (int32_t)stepper_config->sg_threshold; - - err = tmc5160_write( - stepper_config->controller, TMC5160_COOLCONF, - stall_guard_threshold << TMC5160_COOLCONF_SG2_THRESHOLD_VALUE_SHIFT); - if (err != 0) { - return -EIO; - } - err = stallguard_enable(dev, true); - if (err == -EAGAIN) { - LOG_ERR("retrying stallguard activation"); - k_work_reschedule(&data->stallguard_dwork, - K_MSEC(stepper_config->sg_velocity_check_interval_ms)); - } - } - -#ifdef CONFIG_STEPPER_ADI_TMC_RAMP_GEN - err = tmc5160_stepper_set_ramp(dev, &stepper_config->default_ramp_config); - if (err != 0) { - return -EIO; - } -#endif - -#if CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL - k_work_init_delayable(&data->rampstat_callback_dwork, rampstat_work_handler); - k_work_reschedule(&data->rampstat_callback_dwork, - K_MSEC(CONFIG_STEPPER_ADI_TMC5160_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); -#endif - err = tmc5160_stepper_set_micro_step_res(dev, stepper_config->default_micro_step_res); - if (err != 0) { - return -EIO; - } - return 0; -} - -#define TMC5160_SHAFT_CONFIG(child) \ - (DT_PROP(child, invert_direction) << TMC5160_GCONF_SHAFT_SHIFT) | - -#define TMC5160_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_TMC_RAMP_GEN, (CHECK_RAMP_DT_DATA(child))); \ - static const struct tmc5160_stepper_config tmc5160_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_TMC_RAMP_GEN, \ - (.default_ramp_config = TMC_RAMP_DT_SPEC_GET(child))) }; - -#define TMC5160_STEPPER_DATA_DEFINE(child) \ - static struct tmc5160_stepper_data tmc5160_stepper_data_##child = { \ - .stepper = DEVICE_DT_GET(child),}; - -#define TMC5160_STEPPER_API_DEFINE(child) \ - static const struct stepper_driver_api tmc5160_stepper_api_##child = { \ - .enable = tmc5160_stepper_enable, \ - .is_moving = tmc5160_stepper_is_moving, \ - .move = tmc5160_stepper_move, \ - .set_max_velocity = tmc5160_stepper_set_max_velocity, \ - .set_micro_step_res = tmc5160_stepper_set_micro_step_res, \ - .get_micro_step_res = tmc5160_stepper_get_micro_step_res, \ - .set_actual_position = tmc5160_stepper_set_actual_position, \ - .get_actual_position = tmc5160_stepper_get_actual_position, \ - .set_target_position = tmc5160_stepper_set_target_position, \ - .enable_constant_velocity_mode = tmc5160_stepper_enable_constant_velocity_mode, \ - .set_event_callback = tmc5160_stepper_set_event_callback, }; - -#define TMC5160_STEPPER_DEFINE(child) \ - DEVICE_DT_DEFINE(child, tmc5160_stepper_init, NULL, &tmc5160_stepper_data_##child, \ - &tmc5160_stepper_config_##child, POST_KERNEL, \ - CONFIG_STEPPER_INIT_PRIORITY, &tmc5160_stepper_api_##child); - -#define TMC5160_DEFINE(inst) \ - BUILD_ASSERT(DT_INST_CHILD_NUM(inst) <= 1, "tmc5160 can drive one stepper at max"); \ - BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) > 0), \ - "clock frequency must be non-zero positive value"); \ - static struct tmc5160_data tmc5160_data_##inst; \ - static const struct tmc5160_config tmc5160_config_##inst = { \ - .gconf = ( \ - DT_INST_FOREACH_CHILD(inst, TMC5160_SHAFT_CONFIG) \ - (DT_INST_PROP(inst, test_mode) << TMC5160_GCONF_TEST_MODE_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),}; \ - DT_INST_FOREACH_CHILD(inst, TMC5160_STEPPER_CONFIG_DEFINE); \ - DT_INST_FOREACH_CHILD(inst, TMC5160_STEPPER_DATA_DEFINE); \ - DT_INST_FOREACH_CHILD(inst, TMC5160_STEPPER_API_DEFINE); \ - DT_INST_FOREACH_CHILD(inst, TMC5160_STEPPER_DEFINE); \ - DEVICE_DT_INST_DEFINE(inst, tmc5160_init, NULL, &tmc5160_data_##inst, \ - &tmc5160_config_##inst, POST_KERNEL, CONFIG_STEPPER_INIT_PRIORITY,\ - NULL); - -DT_INST_FOREACH_STATUS_OKAY(TMC5160_DEFINE) diff --git a/drivers/stepper/adi_tmc/adi_tmc51xx_stepper_controller.c b/drivers/stepper/adi_tmc/adi_tmc51xx_stepper_controller.c new file mode 100644 index 0000000000000..8d5ccdd72932f --- /dev/null +++ b/drivers/stepper/adi_tmc/adi_tmc51xx_stepper_controller.c @@ -0,0 +1,727 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 Stefano Cottafavi + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT adi_tmc51xx + +#include + +#include +#include + +#include "adi_tmc_reg.h" +#include "adi_tmc_spi.h" + +#include + +LOG_MODULE_REGISTER(tmc51xx, CONFIG_STEPPER_LOG_LEVEL); + +struct tmc51xx_data { + struct k_sem sem; + struct k_work_delayable stallguard_dwork; + /* Work item to run the callback in a thread context. */ +#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL + struct k_work_delayable rampstat_callback_dwork; +#endif + /* device pointer required to access config in k_work */ + const struct device *stepper; + stepper_event_callback_t callback; + void *event_cb_user_data; +}; + +struct tmc51xx_config { + const uint32_t gconf; + struct spi_dt_spec spi; + const uint32_t clock_frequency; + const uint16_t default_micro_step_res; + // StallGuard + const int8_t sg_threshold; + const bool is_sg_enabled; + const uint32_t sg_velocity_check_interval_ms; + const uint32_t sg_threshold_velocity; + // Ramp +#ifdef CONFIG_STEPPER_ADI_TMC_RAMP_GEN + const struct tmc_ramp_generator_data default_ramp_config; +#endif +}; + + +static int tmc51xx_write(const struct device *dev, const uint8_t reg_addr, const uint32_t reg_val) +{ + const struct tmc51xx_config *config = dev->config; + struct tmc51xx_data *data = dev->data; + const struct spi_dt_spec bus = config->spi; + int err; + + k_sem_take(&data->sem, K_FOREVER); + + err = tmc_spi_write_register(&bus, TMC51XX_WRITE_BIT, reg_addr, reg_val); + + k_sem_give(&data->sem); + + if (err) { + LOG_ERR("Failed to write register 0x%x with value 0x%x", reg_addr, reg_val); + return err; + } + return 0; +} + +static int tmc51xx_read(const struct device *dev, const uint8_t reg_addr, uint32_t *reg_val) +{ + const struct tmc51xx_config *config = dev->config; + struct tmc51xx_data *data = dev->data; + const struct spi_dt_spec bus = config->spi; + int err; + + k_sem_take(&data->sem, K_FOREVER); + + err = tmc_spi_read_register(&bus, TMC51XX_ADDRESS_MASK, reg_addr, reg_val); + + k_sem_give(&data->sem); + + if (err) { + LOG_ERR("Failed to read register 0x%x", reg_addr); + return err; + } + return 0; +} + +static void calculate_velocity_from_hz_to_fclk(const struct device *dev, const uint32_t velocity_hz, + uint32_t *const velocity_fclk) +{ + const struct tmc51xx_config *config = dev->config; + + *velocity_fclk = + ((uint64_t)(velocity_hz) << TMC51XX_CLOCK_FREQ_SHIFT) / config->clock_frequency; + LOG_DBG("Stepper motor controller %s velocity: %d Hz, velocity_fclk: %d", dev->name, + velocity_hz, *velocity_fclk); +} + +static int tmc51xx_stepper_set_event_callback(const struct device *dev, + stepper_event_callback_t callback, void *user_data) +{ + struct tmc51xx_data *data = dev->data; + + data->callback = callback; + data->event_cb_user_data = user_data; + return 0; +} + +static int stallguard_enable(const struct device *dev, const bool enable) +{ + const struct tmc51xx_config *config = dev->config; + uint32_t reg_value; + int err; + + err = tmc51xx_read(dev, TMC51XX_SWMODE, ®_value); + if (err) { + LOG_ERR("Failed to read SWMODE register"); + return -EIO; + } + + if (enable) { + reg_value |= TMC51XX_SW_MODE_SG_STOP_ENABLE; + + int32_t actual_velocity; + + err = tmc51xx_read(dev, TMC51XX_VACTUAL, + &actual_velocity); + if (err) { + LOG_ERR("Failed to read VACTUAL register"); + return -EIO; + } + + actual_velocity = (actual_velocity << (31 - TMC_RAMP_VACTUAL_SHIFT)) >> + (31 - TMC_RAMP_VACTUAL_SHIFT); + LOG_DBG("actual velocity: %d", actual_velocity); + + if (abs(actual_velocity) < config->sg_threshold_velocity) { + return -EAGAIN; + } + } else { + reg_value &= ~TMC51XX_SW_MODE_SG_STOP_ENABLE; + } + err = tmc51xx_write(dev, TMC51XX_SWMODE, reg_value); + if (err) { + LOG_ERR("Failed to write SWMODE register"); + return -EIO; + } + return 0; +} + +static void stallguard_work_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct tmc51xx_data *stepper_data = + CONTAINER_OF(dwork, struct tmc51xx_data, stallguard_dwork); + int err; + + const struct tmc51xx_config *stepper_config = stepper_data->stepper->config; + + err = stallguard_enable(stepper_data->stepper, true); + if (err == -EAGAIN) { + LOG_ERR("retrying stallguard activation"); + 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"); + return; + } +} + +#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL + +static void execute_callback(const struct device *dev, const enum stepper_event event) +{ + struct tmc51xx_data *data = dev->data; + + if (!data->callback) { + LOG_WRN_ONCE("No callback registered"); + return; + } + data->callback(dev, event, data->event_cb_user_data); +} + +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 = + CONTAINER_OF(dwork, struct tmc51xx_data, rampstat_callback_dwork); + + uint32_t drv_status; + int err; + + tmc51xx_read(stepper_data->stepper, TMC51XX_DRVSTATUS, &drv_status); + + LOG_DBG("ramp workhandler"); + + if (FIELD_GET(TMC51XX_DRV_STATUS_SG_STATUS_MASK, drv_status) == 1U) { + LOG_INF("%s: Stall detected", stepper_data->stepper->name); + err = tmc51xx_write(stepper_data->stepper, TMC51XX_RAMPMODE, + TMC51XX_RAMPMODE_HOLD_MODE); + if (err != 0) { + LOG_ERR("%s: Failed to stop motor", stepper_data->stepper->name); + return; + } + } + + uint32_t rampstat_value; + + err = tmc51xx_read(stepper_data->stepper, TMC51XX_RAMPSTAT, &rampstat_value); + if (err != 0) { + LOG_ERR("%s: Failed to read RAMPSTAT register", stepper_data->stepper->name); + return; + } + + const uint8_t ramp_stat_values = FIELD_GET(TMC51XX_RAMPSTAT_INT_MASK, rampstat_value); + + if (ramp_stat_values > 0) { + switch (ramp_stat_values) { + + case TMC51XX_STOP_LEFT_EVENT: + LOG_DBG("RAMPSTAT %s:Left end-stop detected", stepper_data->stepper->name); + execute_callback(stepper_data->stepper, + STEPPER_EVENT_LEFT_END_STOP_DETECTED); + break; + + case TMC51XX_STOP_RIGHT_EVENT: + LOG_DBG("RAMPSTAT %s:Right end-stop detected", stepper_data->stepper->name); + execute_callback(stepper_data->stepper, + STEPPER_EVENT_RIGHT_END_STOP_DETECTED); + break; + + case TMC51XX_POS_REACHED_EVENT: + LOG_DBG("RAMPSTAT %s:Position reached", stepper_data->stepper->name); + execute_callback(stepper_data->stepper, STEPPER_EVENT_STEPS_COMPLETED); + break; + + case TMC51XX_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); + break; + default: + LOG_ERR("Illegal ramp stat bit field"); + break; + } + } else { + k_work_reschedule( + &stepper_data->rampstat_callback_dwork, + K_MSEC(CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); + } +} + +#endif + + +static int tmc51xx_stepper_enable(const struct device *dev, const bool enable) +{ + LOG_DBG("Stepper motor controller %s %s", dev->name, enable ? "enabled" : "disabled"); + uint32_t reg_value; + int err; + + err = tmc51xx_read(dev, TMC51XX_CHOPCONF, ®_value); + if (err != 0) { + return -EIO; + } + + if (enable) { + reg_value |= TMC51XX_CHOPCONF_DRV_ENABLE_MASK; + } else { + reg_value &= ~TMC51XX_CHOPCONF_DRV_ENABLE_MASK; + } + + err = tmc51xx_write(dev, TMC51XX_CHOPCONF, reg_value); + if (err != 0) { + return -EIO; + } + return 0; +} + +static int tmc51xx_stepper_is_moving(const struct device *dev, bool *is_moving) +{ + uint32_t reg_value; + int err; + + err = tmc51xx_read(dev, TMC51XX_DRVSTATUS, ®_value); + + if (err != 0) { + LOG_ERR("%s: Failed to read DRVSTATUS register", dev->name); + return -EIO; + } + + *is_moving = (FIELD_GET(TMC51XX_DRV_STATUS_STST_BIT, reg_value) != 1U); + LOG_DBG("Stepper motor controller %s is moving: %d", dev->name, *is_moving); + return 0; +} + +static int tmc51xx_stepper_move(const struct device *dev, const int32_t steps) +{ + const struct tmc51xx_config *config = dev->config; + struct tmc51xx_data *data = dev->data; + int err; + + if (config->is_sg_enabled) { + err = stallguard_enable(dev, false); + if (err != 0) { + return -EIO; + } + } + + int32_t position; + + err = stepper_get_actual_position(dev, &position); + if (err != 0) { + return -EIO; + } + int32_t target_position = position + steps; + + err = tmc51xx_write(dev, TMC51XX_RAMPMODE, + TMC51XX_RAMPMODE_POSITIONING_MODE); + if (err != 0) { + return -EIO; + } + LOG_DBG("Stepper motor controller %s moved to %d by steps: %d", dev->name, target_position, + steps); + err = tmc51xx_write(dev, TMC51XX_XTARGET, target_position); + if (err != 0) { + return -EIO; + } + + if (config->is_sg_enabled) { + k_work_reschedule(&data->stallguard_dwork, + K_MSEC(config->sg_velocity_check_interval_ms)); + } +#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL + //if (data->callback) { + k_work_reschedule( + &data->rampstat_callback_dwork, + K_MSEC(CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); + //} +#endif + return 0; +} + +static int tmc51xx_stepper_set_max_velocity(const struct device *dev, uint32_t velocity) +{ + uint32_t velocity_fclk; + int err; + + calculate_velocity_from_hz_to_fclk(dev, velocity, &velocity_fclk); + err = tmc51xx_write(dev, TMC51XX_VMAX, velocity_fclk); + if (err != 0) { + LOG_ERR("%s: Failed to set max velocity", dev->name); + return -EIO; + } + return 0; +} + +static int tmc51xx_stepper_set_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution res) +{ + uint32_t reg_value; + int err; + + err = tmc51xx_read(dev, TMC51XX_CHOPCONF, ®_value); + if (err != 0) { + return -EIO; + } + + reg_value &= ~TMC51XX_CHOPCONF_MRES_MASK; + reg_value |= ((MICRO_STEP_RES_INDEX(STEPPER_MICRO_STEP_256) - LOG2(res)) + << TMC51XX_CHOPCONF_MRES_SHIFT); + + err = tmc51xx_write(dev, TMC51XX_CHOPCONF, reg_value); + if (err != 0) { + return -EIO; + } + + LOG_DBG("Stepper motor controller %s set micro step resolution to 0x%x", dev->name, + reg_value); + return 0; +} + +static int tmc51xx_stepper_get_micro_step_res(const struct device *dev, + enum stepper_micro_step_resolution *res) +{ + uint32_t reg_value; + int err; + + err = tmc51xx_read(dev, TMC51XX_CHOPCONF, ®_value); + if (err != 0) { + return -EIO; + } + reg_value &= TMC51XX_CHOPCONF_MRES_MASK; + reg_value >>= TMC51XX_CHOPCONF_MRES_SHIFT; + *res = (1 << (MICRO_STEP_RES_INDEX(STEPPER_MICRO_STEP_256) - reg_value)); + LOG_DBG("Stepper motor controller %s get micro step resolution: %d", dev->name, *res); + return 0; +} + +static int tmc51xx_stepper_set_actual_position(const struct device *dev, const int32_t position) +{ + int err; + + err = tmc51xx_write(dev, TMC51XX_RAMPMODE, + TMC51XX_RAMPMODE_HOLD_MODE); + if (err != 0) { + return -EIO; + } + + err = tmc51xx_write(dev, TMC51XX_XACTUAL, position); + if (err != 0) { + return -EIO; + } + LOG_DBG("Stepper motor controller %s set actual position to %d", dev->name, position); + return 0; +} + +static int tmc51xx_stepper_get_actual_position(const struct device *dev, int32_t *position) +{ + int err; + + err = tmc51xx_read(dev, TMC51XX_XACTUAL, position); + if (err != 0) { + return -EIO; + } + LOG_DBG("%s actual position: %d", dev->name, *position); + return 0; +} + +static int tmc51xx_stepper_set_target_position(const struct device *dev, const int32_t position) +{ + LOG_DBG("Stepper motor controller %s set target position to %d", dev->name, position); + const struct tmc51xx_config *config = dev->config; + struct tmc51xx_data *data = dev->data; + int err; + + if (config->is_sg_enabled) { + stallguard_enable(dev, false); + } + + err = tmc51xx_write(dev, TMC51XX_RAMPMODE, + TMC51XX_RAMPMODE_POSITIONING_MODE); + if (err != 0) { + return -EIO; + } + tmc51xx_write(dev, TMC51XX_XTARGET, position); + + if (config->is_sg_enabled) { + k_work_reschedule(&data->stallguard_dwork, + K_MSEC(config->sg_velocity_check_interval_ms)); + } +#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL + if (data->callback) { + k_work_reschedule( + &data->rampstat_callback_dwork, + K_MSEC(CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); + } +#endif + return 0; +} + +static int tmc51xx_stepper_enable_constant_velocity_mode(const struct device *dev, + const enum stepper_direction direction, + const uint32_t velocity) +{ + LOG_DBG("Stepper motor controller %s enable constant velocity mode", dev->name); + const struct tmc51xx_config *config = dev->config; + struct tmc51xx_data *data = dev->data; + uint32_t velocity_fclk; + int err; + + calculate_velocity_from_hz_to_fclk(dev, velocity, &velocity_fclk); + + if (config->is_sg_enabled) { + err = stallguard_enable(dev, false); + if (err != 0) { + return -EIO; + } + } + + switch (direction) { + case STEPPER_DIRECTION_POSITIVE: + err = tmc51xx_write(dev, TMC51XX_RAMPMODE, + TMC51XX_RAMPMODE_POSITIVE_VELOCITY_MODE); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_VMAX, velocity_fclk); + if (err != 0) { + return -EIO; + } + break; + + case STEPPER_DIRECTION_NEGATIVE: + err = tmc51xx_write(dev, TMC51XX_RAMPMODE, + TMC51XX_RAMPMODE_NEGATIVE_VELOCITY_MODE); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_VMAX, velocity_fclk); + if (err != 0) { + return -EIO; + } + break; + } + + if (config->is_sg_enabled) { + k_work_reschedule(&data->stallguard_dwork, + K_MSEC(config->sg_velocity_check_interval_ms)); + } +#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL + if (data->callback) { + k_work_reschedule( + &data->rampstat_callback_dwork, + K_MSEC(CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); + } +#endif + return 0; +} + +#ifdef CONFIG_STEPPER_ADI_TMC_RAMP_GEN + +int tmc51xx_stepper_set_ramp(const struct device *dev, + const struct tmc_ramp_generator_data *ramp_data) +{ + LOG_DBG("Stepper motor controller %s set ramp", dev->name); + int err; + + err = tmc51xx_write(dev, TMC51XX_VSTART, ramp_data->vstart); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_A1, ramp_data->a1); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_AMAX, ramp_data->amax); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_D1, ramp_data->d1); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_DMAX, ramp_data->dmax); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_V1, ramp_data->v1); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_VMAX, ramp_data->vmax); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_VSTOP, ramp_data->vstop); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_TZEROWAIT, ramp_data->tzerowait); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_THIGH, ramp_data->vhigh); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_TCOOLTHRS, ramp_data->vcoolthrs); + if (err != 0) { + return -EIO; + } + err = tmc51xx_write(dev, TMC51XX_IHOLD_IRUN, ramp_data->iholdrun); + if (err != 0) { + return -EIO; + } + return 0; +} + +#endif + +static int tmc51xx_init(const struct device *dev) +{ + LOG_DBG("TMC51XX stepper motor controller %s initialized", dev->name); + struct tmc51xx_data *data = dev->data; + const struct tmc51xx_config *config = dev->config; + int err; + + k_sem_init(&data->sem, 1, 1); + + if (!spi_is_ready_dt(&config->spi)) { + LOG_ERR("SPI bus is not ready"); + return -ENODEV; + } + + /* Init configuration register */ + err = tmc51xx_write(dev, TMC51XX_GCONF, config->gconf); + if (err != 0) { + return -EIO; + } + + /* Re-write GSTAT to clear (error) status flags */ + err = tmc51xx_write(dev, TMC51XX_GSTAT, 0x07); + if (err != 0) { + return -EIO; + } + + err = tmc51xx_stepper_set_micro_step_res(dev, config->default_micro_step_res); + if (err != 0) { + return -EIO; + } + + if (config->is_sg_enabled) { + k_work_init_delayable(&data->stallguard_dwork, stallguard_work_handler); + + err = tmc51xx_write(dev, TMC51XX_SWMODE, 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, TMC51XX_SG_MIN_VALUE, TMC51XX_SG_MAX_VALUE)) { + LOG_ERR("Stallguard threshold out of range"); + return -EINVAL; + } + + int32_t stall_guard_threshold = (int32_t)config->sg_threshold; + + err = tmc51xx_write(dev, TMC51XX_COOLCONF, + stall_guard_threshold << TMC51XX_COOLCONF_SG2_THRESHOLD_VALUE_SHIFT); + if (err != 0) { + return -EIO; + } + err = stallguard_enable(dev, true); + if (err == -EAGAIN) { + LOG_ERR("retrying stallguard activation"); + k_work_reschedule(&data->stallguard_dwork, + K_MSEC(config->sg_velocity_check_interval_ms)); + } + } + +#ifdef CONFIG_STEPPER_ADI_TMC_RAMP_GEN + err = tmc51xx_stepper_set_ramp(dev, &config->default_ramp_config); + if (err != 0) { + return -EIO; + } +#endif + +#if CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL + k_work_init_delayable(&data->rampstat_callback_dwork, rampstat_work_handler); + k_work_reschedule(&data->rampstat_callback_dwork, + K_MSEC(CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); +#endif + + LOG_DBG("Device %s initialized", dev->name); + + return 0; +} + +#define TMC_RAMP_DT_SPEC_GET(inst) \ + { \ + .vstart = DT_INST_PROP(inst, vstart), \ + .v1 = DT_INST_PROP(inst, v1), \ + .vmax = DT_INST_PROP(inst, vmax), \ + .a1 = DT_INST_PROP(inst, a1), \ + .amax = DT_INST_PROP(inst, amax), \ + .d1 = DT_INST_PROP(inst, d1), \ + .dmax = DT_INST_PROP(inst, dmax), \ + .vstop = DT_INST_PROP(inst, vstop), \ + .tzerowait = DT_INST_PROP(inst, tzerowait), \ + .vcoolthrs = DT_INST_PROP(inst, vcoolthrs), \ + .vhigh = DT_INST_PROP(inst, vhigh), \ + .iholdrun = (TMC51XX_IRUN(DT_INST_PROP(inst, irun)) | \ + TMC51XX_IHOLD(DT_INST_PROP(inst, ihold)) | \ + TMC51XX_IHOLDDELAY(DT_INST_PROP(inst, iholddelay))), \ + } + +#define TMC51XX_STEPPER_API_DEFINE(inst) \ + static const struct stepper_driver_api tmc51xx_api_##inst = { \ + .enable = tmc51xx_stepper_enable, \ + .is_moving = tmc51xx_stepper_is_moving, \ + .move = tmc51xx_stepper_move, \ + .set_max_velocity = tmc51xx_stepper_set_max_velocity, \ + .set_micro_step_res = tmc51xx_stepper_set_micro_step_res, \ + .get_micro_step_res = tmc51xx_stepper_get_micro_step_res, \ + .set_actual_position = tmc51xx_stepper_set_actual_position, \ + .get_actual_position = tmc51xx_stepper_get_actual_position, \ + .set_target_position = tmc51xx_stepper_set_target_position, \ + .enable_constant_velocity_mode = tmc51xx_stepper_enable_constant_velocity_mode, \ + .set_event_callback = tmc51xx_stepper_set_event_callback, \ + }; + +#define TMC51XX_DEFINE(inst) \ + BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) > 0), \ + "clock frequency must be non-zero positive value"); \ + COND_CODE_1(DT_INST_PROP_EXISTS(inst, stallguard_threshold_velocity), \ + BUILD_ASSERT(DT_INST_PROP(inst, stallguard_threshold_velocity), \ + "stallguard threshold velocity must be a positive value"), ()); \ + IF_ENABLED(CONFIG_STEPPER_ADI_TMC_RAMP_GEN, (CHECK_RAMP_DT_DATA(inst))); \ + static struct tmc51xx_data tmc51xx_data_##inst = { \ + .stepper = DEVICE_DT_INST_GET(inst), }; \ + static const struct tmc51xx_config tmc51xx_config_##inst = { \ + .gconf = ( \ + (DT_INST_PROP(inst, invert_direction) << TMC51XX_GCONF_SHAFT_SHIFT) | \ + (DT_INST_PROP(inst, test_mode) << TMC51XX_GCONF_TEST_MODE_SHIFT)), \ + .default_micro_step_res = DT_INST_PROP(inst, micro_step_res), \ + .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), \ + .is_sg_enabled = DT_INST_PROP(inst, activate_stallguard2), \ + COND_CODE_1(DT_INST_PROP(inst, activate_stallguard2),( \ + .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), ), ()) \ + IF_ENABLED(CONFIG_STEPPER_ADI_TMC_RAMP_GEN, \ + (.default_ramp_config = TMC_RAMP_DT_SPEC_GET(inst))) }; \ + TMC51XX_STEPPER_API_DEFINE(inst) \ + DEVICE_DT_INST_DEFINE(inst, tmc51xx_init, NULL, &tmc51xx_data_##inst, \ + &tmc51xx_config_##inst, POST_KERNEL, CONFIG_STEPPER_INIT_PRIORITY,\ + &tmc51xx_api_##inst); + +DT_INST_FOREACH_STATUS_OKAY(TMC51XX_DEFINE) diff --git a/drivers/stepper/adi_tmc/adi_tmc_reg.h b/drivers/stepper/adi_tmc/adi_tmc_reg.h index 17a7f159c80e2..91521e5f7f178 100644 --- a/drivers/stepper/adi_tmc/adi_tmc_reg.h +++ b/drivers/stepper/adi_tmc/adi_tmc_reg.h @@ -137,119 +137,142 @@ extern "C" { #endif -#ifdef CONFIG_STEPPER_ADI_TMC5160 +#ifdef CONFIG_STEPPER_ADI_TMC51XX /** - * @name TMC5160 module registers - * @anchor TMC5160_REGISTERS + * @name TMC51XX module registers + * @anchor TMC51XX_REGISTERS * * @{ */ -#define TMC5160_GCONF_TEST_MODE_SHIFT 17 -#define TMC5160_GCONF_SHAFT_SHIFT 4 - -#define TMC5160_DRV_STATUS_STST_BIT BIT(31) - -#define TMC5160_WRITE_BIT 0x80U -#define TMC5160_ADDRESS_MASK 0x7FU - -#define TMC5160_GCONF 0x00 -#define TMC5160_GSTAT 0x01 -#define TMC5160_IFCNT 0x02 -#define TMC5160_SLAVECONF 0x03 -#define TMC5160_INP_OUT 0x04 -#define TMC5160_X_COMPARE 0x05 -#define TMC5160_OTP_PROG 0x06 -#define TMC5160_OTP_READ 0x07 -#define TMC5160_FACTORY_CONF 0x08 -#define TMC5160_SHORT_CONF 0x09 -#define TMC5160_DRV_CONF 0x0A -#define TMC5160_GLOBAL_SCALER 0x0B -#define TMC5160_OFFSET_READ 0x0C -#define TMC5160_IHOLD_IRUN 0x10 -#define TMC5160_TPOWERDOWN 0x11 -#define TMC5160_TSTEP 0x12 -#define TMC5160_TPWMTHRS 0x13 -#define TMC5160_TCOOLTHRS 0x14 -#define TMC5160_THIGH 0x15 - -#define TMC5160_RAMPMODE 0x20 -#define TMC5160_XACTUAL 0x21 -#define TMC5160_VACTUAL 0x22 -#define TMC5160_VSTART 0x23 -#define TMC5160_A1 0x24 -#define TMC5160_V1 0x25 -#define TMC5160_AMAX 0x26 -#define TMC5160_VMAX 0x27 -#define TMC5160_DMAX 0x28 -#define TMC5160_D1 0x2A -#define TMC5160_VSTOP 0x2B -#define TMC5160_TZEROWAIT 0x2C -#define TMC5160_XTARGET 0x2D - -#define TMC5160_VDCMIN 0x33 -#define TMC5160_SWMODE 0x34 -#define TMC5160_RAMPSTAT 0x35 -#define TMC5160_XLATCH 0x36 -#define TMC5160_ENCMODE 0x38 -#define TMC5160_XENC 0x39 -#define TMC5160_ENC_CONST 0x3A -#define TMC5160_ENC_STATUS 0x3B -#define TMC5160_ENC_LATCH 0x3C -#define TMC5160_ENC_DEVIATION 0x3D - -#define TMC5160_MSLUT0 0x60 -#define TMC5160_MSLUT1 0x61 -#define TMC5160_MSLUT2 0x62 -#define TMC5160_MSLUT3 0x63 -#define TMC5160_MSLUT4 0x64 -#define TMC5160_MSLUT5 0x65 -#define TMC5160_MSLUT6 0x66 -#define TMC5160_MSLUT7 0x67 -#define TMC5160_MSLUTSEL 0x68 -#define TMC5160_MSLUTSTART 0x69 -#define TMC5160_MSCNT 0x6A -#define TMC5160_MSCURACT 0x6B -#define TMC5160_CHOPCONF 0x6C -#define TMC5160_COOLCONF 0x6D -#define TMC5160_DCCTRL 0x6E -#define TMC5160_DRVSTATUS 0x6F -#define TMC5160_PWMCONF 0x70 -#define TMC5160_PWMSCALE 0x71 -#define TMC5160_PWM_AUTO 0x72 -#define TMC5160_LOST_STEPS 0x73 - - -#define TMC5160_RAMPMODE_POSITIONING_MODE 0 -#define TMC5160_RAMPMODE_POSITIVE_VELOCITY_MODE 1 -#define TMC5160_RAMPMODE_NEGATIVE_VELOCITY_MODE 2 -#define TMC5160_RAMPMODE_HOLD_MODE 3 - -#define TMC5160_SW_MODE_SG_STOP_ENABLE BIT(10) - -#define TMC5160_SG_MIN_VALUE -64 -#define TMC5160_SG_MAX_VALUE 63 - -#define TMC5160_COOLCONF_SG2_THRESHOLD_VALUE_SHIFT 16 - -#define TMC5160_IHOLD_MASK GENMASK(4, 0) -#define TMC5160_IHOLD_SHIFT 0 -#define TMC5160_IHOLD(n) (((n) << TMC5160_IHOLD_SHIFT) & TMC5160_IHOLD_MASK) - -#define TMC5160_IRUN_MASK GENMASK(12, 8) -#define TMC5160_IRUN_SHIFT 8 -#define TMC5160_IRUN(n) (((n) << TMC5160_IRUN_SHIFT) & TMC5160_IRUN_MASK) - -#define TMC5160_IHOLDDELAY_MASK GENMASK(19, 16) -#define TMC5160_IHOLDDELAY_SHIFT 16 -#define TMC5160_IHOLDDELAY(n) (((n) << TMC5160_IHOLDDELAY_SHIFT) & TMC5160_IHOLDDELAY_MASK) - -#define TMC5160_CHOPCONF_DRV_ENABLE_MASK GENMASK(3, 0) -#define TMC5160_CHOPCONF_MRES_MASK GENMASK(27, 24) -#define TMC5160_CHOPCONF_MRES_SHIFT 24 - -#define TMC5160_CLOCK_FREQ_SHIFT 24 +#define TMC51XX_GCONF_TEST_MODE_SHIFT 17 +#define TMC51XX_GCONF_SHAFT_SHIFT 4 + +#define TMC51XX_DRV_STATUS_STST_BIT BIT(31) + +#define TMC51XX_WRITE_BIT 0x80U +#define TMC51XX_ADDRESS_MASK 0x7FU + +#define TMC51XX_GCONF 0x00 +#define TMC51XX_GSTAT 0x01 +#define TMC51XX_IFCNT 0x02 +#define TMC51XX_SLAVECONF 0x03 +#define TMC51XX_INP_OUT 0x04 +#define TMC51XX_X_COMPARE 0x05 +#define TMC51XX_OTP_PROG 0x06 +#define TMC51XX_OTP_READ 0x07 +#define TMC51XX_FACTORY_CONF 0x08 +#define TMC51XX_SHORT_CONF 0x09 +#define TMC51XX_DRV_CONF 0x0A +#define TMC51XX_GLOBAL_SCALER 0x0B +#define TMC51XX_OFFSET_READ 0x0C +#define TMC51XX_IHOLD_IRUN 0x10 +#define TMC51XX_TPOWERDOWN 0x11 +#define TMC51XX_TSTEP 0x12 +#define TMC51XX_TPWMTHRS 0x13 +#define TMC51XX_TCOOLTHRS 0x14 +#define TMC51XX_THIGH 0x15 + +#define TMC51XX_RAMPMODE 0x20 +#define TMC51XX_XACTUAL 0x21 +#define TMC51XX_VACTUAL 0x22 +#define TMC51XX_VSTART 0x23 +#define TMC51XX_A1 0x24 +#define TMC51XX_V1 0x25 +#define TMC51XX_AMAX 0x26 +#define TMC51XX_VMAX 0x27 +#define TMC51XX_DMAX 0x28 +#define TMC51XX_D1 0x2A +#define TMC51XX_VSTOP 0x2B +#define TMC51XX_TZEROWAIT 0x2C +#define TMC51XX_XTARGET 0x2D + +#define TMC51XX_VDCMIN 0x33 +#define TMC51XX_SWMODE 0x34 +#define TMC51XX_RAMPSTAT 0x35 +#define TMC51XX_XLATCH 0x36 +#define TMC51XX_ENCMODE 0x38 +#define TMC51XX_XENC 0x39 +#define TMC51XX_ENC_CONST 0x3A +#define TMC51XX_ENC_STATUS 0x3B +#define TMC51XX_ENC_LATCH 0x3C +#define TMC51XX_ENC_DEVIATION 0x3D + +#define TMC51XX_MSLUT0 0x60 +#define TMC51XX_MSLUT1 0x61 +#define TMC51XX_MSLUT2 0x62 +#define TMC51XX_MSLUT3 0x63 +#define TMC51XX_MSLUT4 0x64 +#define TMC51XX_MSLUT5 0x65 +#define TMC51XX_MSLUT6 0x66 +#define TMC51XX_MSLUT7 0x67 +#define TMC51XX_MSLUTSEL 0x68 +#define TMC51XX_MSLUTSTART 0x69 +#define TMC51XX_MSCNT 0x6A +#define TMC51XX_MSCURACT 0x6B +#define TMC51XX_CHOPCONF 0x6C +#define TMC51XX_COOLCONF 0x6D +#define TMC51XX_DCCTRL 0x6E +#define TMC51XX_DRVSTATUS 0x6F +#define TMC51XX_PWMCONF 0x70 +#define TMC51XX_PWMSCALE 0x71 +#define TMC51XX_PWM_AUTO 0x72 +#define TMC51XX_LOST_STEPS 0x73 + + +#define TMC51XX_RAMPMODE_POSITIONING_MODE 0 +#define TMC51XX_RAMPMODE_POSITIVE_VELOCITY_MODE 1 +#define TMC51XX_RAMPMODE_NEGATIVE_VELOCITY_MODE 2 +#define TMC51XX_RAMPMODE_HOLD_MODE 3 + +#define TMC51XX_SW_MODE_SG_STOP_ENABLE BIT(10) + +#define TMC51XX_RAMPSTAT_INT_MASK GENMASK(7, 4) +#define TMC51XX_RAMPSTAT_INT_SHIFT 4 + +#define TMC51XX_RAMPSTAT_POS_REACHED_EVENT_MASK BIT(7) +#define TMC51XX_POS_REACHED_EVENT \ + (TMC51XX_RAMPSTAT_POS_REACHED_EVENT_MASK >> TMC51XX_RAMPSTAT_INT_SHIFT) + +#define TMC51XX_RAMPSTAT_STOP_SG_EVENT_MASK BIT(6) +#define TMC51XX_STOP_SG_EVENT (TMC51XX_RAMPSTAT_STOP_SG_EVENT_MASK >> TMC51XX_RAMPSTAT_INT_SHIFT) + +#define TMC51XX_RAMPSTAT_STOP_RIGHT_EVENT_MASK BIT(5) +#define TMC51XX_STOP_RIGHT_EVENT \ + (TMC51XX_RAMPSTAT_STOP_RIGHT_EVENT_MASK >> TMC51XX_RAMPSTAT_INT_SHIFT) + +#define TMC51XX_RAMPSTAT_STOP_LEFT_EVENT_MASK BIT(4) +#define TMC51XX_STOP_LEFT_EVENT \ + (TMC51XX_RAMPSTAT_STOP_LEFT_EVENT_MASK >> TMC51XX_RAMPSTAT_INT_SHIFT) + +#define TMC51XX_DRV_STATUS_STST_BIT BIT(31) +#define TMC51XX_DRV_STATUS_SG_RESULT_MASK GENMASK(9, 0) +#define TMC51XX_DRV_STATUS_SG_STATUS_MASK BIT(24) +#define TMC51XX_DRV_STATUS_SG_STATUS_SHIFT 24 + +#define TMC51XX_SG_MIN_VALUE -64 +#define TMC51XX_SG_MAX_VALUE 63 + +#define TMC51XX_COOLCONF_SG2_THRESHOLD_VALUE_SHIFT 16 + +#define TMC51XX_IHOLD_MASK GENMASK(4, 0) +#define TMC51XX_IHOLD_SHIFT 0 +#define TMC51XX_IHOLD(n) (((n) << TMC51XX_IHOLD_SHIFT) & TMC51XX_IHOLD_MASK) + +#define TMC51XX_IRUN_MASK GENMASK(12, 8) +#define TMC51XX_IRUN_SHIFT 8 +#define TMC51XX_IRUN(n) (((n) << TMC51XX_IRUN_SHIFT) & TMC51XX_IRUN_MASK) + +#define TMC51XX_IHOLDDELAY_MASK GENMASK(19, 16) +#define TMC51XX_IHOLDDELAY_SHIFT 16 +#define TMC51XX_IHOLDDELAY(n) (((n) << TMC51XX_IHOLDDELAY_SHIFT) & TMC51XX_IHOLDDELAY_MASK) + +#define TMC51XX_CHOPCONF_DRV_ENABLE_MASK GENMASK(3, 0) +#define TMC51XX_CHOPCONF_MRES_MASK GENMASK(27, 24) +#define TMC51XX_CHOPCONF_MRES_SHIFT 24 + +#define TMC51XX_CLOCK_FREQ_SHIFT 24 #endif diff --git a/drivers/stepper/adi_tmc/adi_tmc_spi.c b/drivers/stepper/adi_tmc/adi_tmc_spi.c index 7aa3bed69d56f..03ac6d884b88e 100644 --- a/drivers/stepper/adi_tmc/adi_tmc_spi.c +++ b/drivers/stepper/adi_tmc/adi_tmc_spi.c @@ -19,11 +19,13 @@ static void parse_tmc_spi_status(const uint8_t status_byte) LOG_WRN("spi dataframe: reset_flag detected"); } if ((status_byte & BIT_MASK(1)) != 0) { - LOG_WRN("spi dataframe: driver_error(1) detected"); + LOG_WRN("spi dataframe: driver_error/driver_error(1) detected"); } +#ifdef CONFIG_STEPPER_ADI_TMC5041 if ((status_byte & BIT_MASK(2)) != 0) { LOG_WRN("spi dataframe: driver_error(2) detected"); } +#endif } static void print_tx_rx_buffer(const uint8_t *const tx_buffer, const uint8_t *const rx_buffer) diff --git a/dts/bindings/stepper/adi/adi,tmc5160.yaml b/dts/bindings/stepper/adi/adi,tmc5160.yaml deleted file mode 100644 index a13684c08826b..0000000000000 --- a/dts/bindings/stepper/adi/adi,tmc5160.yaml +++ /dev/null @@ -1,113 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2024 Stefano Cottafavi -# SPDX-License-Identifier: Apache-2.0 - -description: | - Analog Devices TMC5160 Stepper Motor Controller - - Example: - - &spi0 { - /* SPI bus options here, not shown */ - - tmc5160: tmc5160@0 { - compatible = "adi,tmc5160"; - reg = <0>; - spi-max-frequency = ; /* Maximum SPI bus frequency */ - - #address-cells = <1>; - #size-cells = <0>; - - clock-frequency = ; /* Internal/External Clock frequency */ - - motor: motor@0 { - status = "okay"; - reg = <0>; - - /* common stepper controller settings */ - invert-direction; - micro-step-res = <256>; - - /* ADI TMC stallguard settings specific to TMC5041 */ - activate-stallguard2; - stallguard-velocity-check-interval-ms=<100>; - stallguard2-threshold=<9>; - stallguard-threshold-velocity=<500000>; - - /* 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>; - vhigh = <90>; - vcoolthrs = <100>; - ihold = <1>; - irun = <2>; - iholddelay = <3>; - }; - }; - }; - - -compatible: "adi,tmc5160" - -include: - - name: spi-device.yaml - - name: adi,trinamic-gconf.yaml - property-allowlist: - - shaft - - test_mode - -properties: - "#address-cells": - default: 1 - const: 1 - - "#size-cells": - default: 0 - const: 0 - - clock-frequency: - type: int - required: true - description: | - The frequency of the clock signal provided to the TMC5160. - This is used for real world conversion. - - Hint: µstep velocity v[Hz] µsteps / s v[Hz] = v[5160] * ( fCLK[Hz]/2 / 2^23 ) - where v[5160] is the value written to the TMC5160. - -child-binding: - include: - - name: base.yaml - property-allowlist: - - reg - - name: stepper-controller.yaml - property-allowlist: - - invert-direction - - micro-step-res - - name: adi,trinamic-ramp-generator.yaml - property-allowlist: - - vstart - - a1 - - v1 - - amax - - vmax - - dmax - - d1 - - vstop - - tzerowait - - vhigh - - vcoolthrs - - 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/adi/adi,tmc51xx.yaml b/dts/bindings/stepper/adi/adi,tmc51xx.yaml new file mode 100644 index 0000000000000..ed2d80401d81a --- /dev/null +++ b/dts/bindings/stepper/adi/adi,tmc51xx.yaml @@ -0,0 +1,101 @@ +# SPDX-FileCopyrightText: Copyright (c) 2024 Stefano Cottafavi +# SPDX-License-Identifier: Apache-2.0 + +description: | + Analog Devices TMC5130/TMC5160 Stepper Motor Controller + + Example: + + &spi0 { + /* SPI bus options here, not shown */ + + tmc5160: tmc5160@0 { + compatible = "adi,tmc51xx"; + reg = <0>; + spi-max-frequency = ; /* Maximum SPI bus frequency */ + + #address-cells = <1>; + #size-cells = <0>; + + clock-frequency = ; /* Internal/External Clock frequency */ + + invert-direction; + micro-step-res = <256>; + + /* ADI TMC stallguard settings specific to TMC5041 */ + activate-stallguard2; + stallguard-velocity-check-interval-ms=<100>; + stallguard2-threshold=<9>; + stallguard-threshold-velocity=<500000>; + + /* 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>; + vhigh = <90>; + vcoolthrs = <100>; + ihold = <1>; + irun = <2>; + iholddelay = <3>; + }; + }; + + +compatible: "adi,tmc51xx" + +include: + - name: spi-device.yaml + - name: adi,trinamic-gconf.yaml + property-allowlist: + - shaft + - test_mode + - name: stepper-controller.yaml + property-allowlist: + - invert-direction + - micro-step-res + - name: adi,trinamic-ramp-generator.yaml + property-allowlist: + - vstart + - a1 + - v1 + - amax + - vmax + - dmax + - d1 + - vstop + - tzerowait + - vhigh + - vcoolthrs + - 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": + default: 1 + const: 1 + + "#size-cells": + default: 0 + const: 0 + + clock-frequency: + type: int + required: true + description: | + The frequency of the clock signal provided to the TMC5160. + This is used for real world conversion. + + Hint: µstep velocity v[Hz] µsteps / s v[Hz] = v[5160] * ( fCLK[Hz]/2 / 2^23 ) + where v[5160] is the value written to the TMC5160. diff --git a/include/zephyr/drivers/stepper/stepper_trinamic.h b/include/zephyr/drivers/stepper/stepper_trinamic.h index f7613660c1eb6..ce759d48f87be 100644 --- a/include/zephyr/drivers/stepper/stepper_trinamic.h +++ b/include/zephyr/drivers/stepper/stepper_trinamic.h @@ -149,24 +149,6 @@ struct tmc_ramp_generator_data { TMC5041_IHOLD(DT_PROP(node, ihold)) | \ TMC5041_IHOLDDELAY(DT_PROP(node, iholddelay))), \ } -#elif CONFIG_STEPPER_ADI_TMC5160 -#define TMC_RAMP_DT_SPEC_GET(node) \ - { \ - .vstart = DT_PROP(node, vstart), \ - .v1 = DT_PROP(node, v1), \ - .vmax = DT_PROP(node, vmax), \ - .a1 = DT_PROP(node, a1), \ - .amax = DT_PROP(node, amax), \ - .d1 = DT_PROP(node, d1), \ - .dmax = DT_PROP(node, dmax), \ - .vstop = DT_PROP(node, vstop), \ - .tzerowait = DT_PROP(node, tzerowait), \ - .vcoolthrs = DT_PROP(node, vcoolthrs), \ - .vhigh = DT_PROP(node, vhigh), \ - .iholdrun = (TMC5160_IRUN(DT_PROP(node, irun)) | \ - TMC5160_IHOLD(DT_PROP(node, ihold)) | \ - TMC5160_IHOLDDELAY(DT_PROP(node, iholddelay))), \ - } #endif /** @@ -182,9 +164,6 @@ struct tmc_ramp_generator_data { #ifdef CONFIG_STEPPER_ADI_TMC5041 int tmc5041_stepper_set_ramp(const struct device *dev, const struct tmc_ramp_generator_data *ramp_data); -#elif CONFIG_STEPPER_ADI_TMC5160 -int tmc5160_stepper_set_ramp(const struct device *dev, - const struct tmc_ramp_generator_data *ramp_data); #endif /** From f75282fa555089bb747fb79f6e36f7175c93609c Mon Sep 17 00:00:00 2001 From: Stefano Cottafavi Date: Fri, 8 Nov 2024 20:39:40 +0100 Subject: [PATCH 3/3] review fix WIP, sign off Signed-off-by: Stefano Cottafavi --- .../adi_tmc/adi_tmc51xx_stepper_controller.c | 146 ++++++++--------- drivers/stepper/adi_tmc/adi_tmc_reg.h | 149 +++++++++--------- drivers/stepper/adi_tmc/adi_tmc_spi.c | 2 +- scripts/ci/check_compliance.py | 2 +- 4 files changed, 143 insertions(+), 156 deletions(-) diff --git a/drivers/stepper/adi_tmc/adi_tmc51xx_stepper_controller.c b/drivers/stepper/adi_tmc/adi_tmc51xx_stepper_controller.c index 8d5ccdd72932f..2bcc972c5fa53 100644 --- a/drivers/stepper/adi_tmc/adi_tmc51xx_stepper_controller.c +++ b/drivers/stepper/adi_tmc/adi_tmc51xx_stepper_controller.c @@ -14,7 +14,6 @@ #include "adi_tmc_spi.h" #include - LOG_MODULE_REGISTER(tmc51xx, CONFIG_STEPPER_LOG_LEVEL); struct tmc51xx_data { @@ -35,18 +34,17 @@ struct tmc51xx_config { struct spi_dt_spec spi; const uint32_t clock_frequency; const uint16_t default_micro_step_res; - // StallGuard + /* StallGuard */ const int8_t sg_threshold; const bool is_sg_enabled; const uint32_t sg_velocity_check_interval_ms; const uint32_t sg_threshold_velocity; - // Ramp + /* Ramp */ #ifdef CONFIG_STEPPER_ADI_TMC_RAMP_GEN const struct tmc_ramp_generator_data default_ramp_config; #endif }; - static int tmc51xx_write(const struct device *dev, const uint8_t reg_addr, const uint32_t reg_val) { const struct tmc51xx_config *config = dev->config; @@ -125,8 +123,7 @@ static int stallguard_enable(const struct device *dev, const bool enable) int32_t actual_velocity; - err = tmc51xx_read(dev, TMC51XX_VACTUAL, - &actual_velocity); + err = tmc51xx_read(dev, TMC51XX_VACTUAL, &actual_velocity); if (err) { LOG_ERR("Failed to read VACTUAL register"); return -EIO; @@ -255,7 +252,6 @@ static void rampstat_work_handler(struct k_work *work) #endif - static int tmc51xx_stepper_enable(const struct device *dev, const bool enable) { LOG_DBG("Stepper motor controller %s %s", dev->name, enable ? "enabled" : "disabled"); @@ -318,8 +314,7 @@ static int tmc51xx_stepper_move(const struct device *dev, const int32_t steps) } int32_t target_position = position + steps; - err = tmc51xx_write(dev, TMC51XX_RAMPMODE, - TMC51XX_RAMPMODE_POSITIONING_MODE); + err = tmc51xx_write(dev, TMC51XX_RAMPMODE, TMC51XX_RAMPMODE_POSITIONING_MODE); if (err != 0) { return -EIO; } @@ -335,11 +330,11 @@ static int tmc51xx_stepper_move(const struct device *dev, const int32_t steps) K_MSEC(config->sg_velocity_check_interval_ms)); } #ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL - //if (data->callback) { + if (data->callback) { k_work_reschedule( &data->rampstat_callback_dwork, K_MSEC(CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); - //} + } #endif return 0; } @@ -404,8 +399,7 @@ static int tmc51xx_stepper_set_actual_position(const struct device *dev, const i { int err; - err = tmc51xx_write(dev, TMC51XX_RAMPMODE, - TMC51XX_RAMPMODE_HOLD_MODE); + err = tmc51xx_write(dev, TMC51XX_RAMPMODE, TMC51XX_RAMPMODE_HOLD_MODE); if (err != 0) { return -EIO; } @@ -441,8 +435,7 @@ static int tmc51xx_stepper_set_target_position(const struct device *dev, const i stallguard_enable(dev, false); } - err = tmc51xx_write(dev, TMC51XX_RAMPMODE, - TMC51XX_RAMPMODE_POSITIONING_MODE); + err = tmc51xx_write(dev, TMC51XX_RAMPMODE, TMC51XX_RAMPMODE_POSITIONING_MODE); if (err != 0) { return -EIO; } @@ -483,8 +476,7 @@ static int tmc51xx_stepper_enable_constant_velocity_mode(const struct device *de switch (direction) { case STEPPER_DIRECTION_POSITIVE: - err = tmc51xx_write(dev, TMC51XX_RAMPMODE, - TMC51XX_RAMPMODE_POSITIVE_VELOCITY_MODE); + err = tmc51xx_write(dev, TMC51XX_RAMPMODE, TMC51XX_RAMPMODE_POSITIVE_VELOCITY_MODE); if (err != 0) { return -EIO; } @@ -495,8 +487,7 @@ static int tmc51xx_stepper_enable_constant_velocity_mode(const struct device *de break; case STEPPER_DIRECTION_NEGATIVE: - err = tmc51xx_write(dev, TMC51XX_RAMPMODE, - TMC51XX_RAMPMODE_NEGATIVE_VELOCITY_MODE); + err = tmc51xx_write(dev, TMC51XX_RAMPMODE, TMC51XX_RAMPMODE_NEGATIVE_VELOCITY_MODE); if (err != 0) { return -EIO; } @@ -631,7 +622,8 @@ static int tmc51xx_init(const struct device *dev) int32_t stall_guard_threshold = (int32_t)config->sg_threshold; err = tmc51xx_write(dev, TMC51XX_COOLCONF, - stall_guard_threshold << TMC51XX_COOLCONF_SG2_THRESHOLD_VALUE_SHIFT); + stall_guard_threshold + << TMC51XX_COOLCONF_SG2_THRESHOLD_VALUE_SHIFT); if (err != 0) { return -EIO; } @@ -661,67 +653,63 @@ static int tmc51xx_init(const struct device *dev) return 0; } -#define TMC_RAMP_DT_SPEC_GET(inst) \ - { \ - .vstart = DT_INST_PROP(inst, vstart), \ - .v1 = DT_INST_PROP(inst, v1), \ - .vmax = DT_INST_PROP(inst, vmax), \ - .a1 = DT_INST_PROP(inst, a1), \ - .amax = DT_INST_PROP(inst, amax), \ - .d1 = DT_INST_PROP(inst, d1), \ - .dmax = DT_INST_PROP(inst, dmax), \ - .vstop = DT_INST_PROP(inst, vstop), \ - .tzerowait = DT_INST_PROP(inst, tzerowait), \ - .vcoolthrs = DT_INST_PROP(inst, vcoolthrs), \ - .vhigh = DT_INST_PROP(inst, vhigh), \ - .iholdrun = (TMC51XX_IRUN(DT_INST_PROP(inst, irun)) | \ - TMC51XX_IHOLD(DT_INST_PROP(inst, ihold)) | \ - TMC51XX_IHOLDDELAY(DT_INST_PROP(inst, iholddelay))), \ - } - -#define TMC51XX_STEPPER_API_DEFINE(inst) \ - static const struct stepper_driver_api tmc51xx_api_##inst = { \ - .enable = tmc51xx_stepper_enable, \ - .is_moving = tmc51xx_stepper_is_moving, \ - .move = tmc51xx_stepper_move, \ - .set_max_velocity = tmc51xx_stepper_set_max_velocity, \ - .set_micro_step_res = tmc51xx_stepper_set_micro_step_res, \ - .get_micro_step_res = tmc51xx_stepper_get_micro_step_res, \ - .set_actual_position = tmc51xx_stepper_set_actual_position, \ - .get_actual_position = tmc51xx_stepper_get_actual_position, \ - .set_target_position = tmc51xx_stepper_set_target_position, \ - .enable_constant_velocity_mode = tmc51xx_stepper_enable_constant_velocity_mode, \ - .set_event_callback = tmc51xx_stepper_set_event_callback, \ +#define TMC_RAMP_DT_SPEC_GET(inst) \ + { \ + .vstart = DT_INST_PROP(inst, vstart), .v1 = DT_INST_PROP(inst, v1), \ + .vmax = DT_INST_PROP(inst, vmax), .a1 = DT_INST_PROP(inst, a1), \ + .amax = DT_INST_PROP(inst, amax), .d1 = DT_INST_PROP(inst, d1), \ + .dmax = DT_INST_PROP(inst, dmax), .vstop = DT_INST_PROP(inst, vstop), \ + .tzerowait = DT_INST_PROP(inst, tzerowait), \ + .vcoolthrs = DT_INST_PROP(inst, vcoolthrs), .vhigh = DT_INST_PROP(inst, vhigh), \ + .iholdrun = (TMC51XX_IRUN(DT_INST_PROP(inst, irun)) | \ + TMC51XX_IHOLD(DT_INST_PROP(inst, ihold)) | \ + TMC51XX_IHOLDDELAY(DT_INST_PROP(inst, iholddelay))), \ + } + +#define TMC51XX_STEPPER_API_DEFINE(inst) \ + static const struct stepper_driver_api tmc51xx_api_##inst = { \ + .enable = tmc51xx_stepper_enable, \ + .is_moving = tmc51xx_stepper_is_moving, \ + .move = tmc51xx_stepper_move, \ + .set_max_velocity = tmc51xx_stepper_set_max_velocity, \ + .set_micro_step_res = tmc51xx_stepper_set_micro_step_res, \ + .get_micro_step_res = tmc51xx_stepper_get_micro_step_res, \ + .set_actual_position = tmc51xx_stepper_set_actual_position, \ + .get_actual_position = tmc51xx_stepper_get_actual_position, \ + .set_target_position = tmc51xx_stepper_set_target_position, \ + .enable_constant_velocity_mode = tmc51xx_stepper_enable_constant_velocity_mode, \ + .set_event_callback = tmc51xx_stepper_set_event_callback, \ }; -#define TMC51XX_DEFINE(inst) \ - BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) > 0), \ - "clock frequency must be non-zero positive value"); \ - COND_CODE_1(DT_INST_PROP_EXISTS(inst, stallguard_threshold_velocity), \ - BUILD_ASSERT(DT_INST_PROP(inst, stallguard_threshold_velocity), \ - "stallguard threshold velocity must be a positive value"), ()); \ - IF_ENABLED(CONFIG_STEPPER_ADI_TMC_RAMP_GEN, (CHECK_RAMP_DT_DATA(inst))); \ - static struct tmc51xx_data tmc51xx_data_##inst = { \ - .stepper = DEVICE_DT_INST_GET(inst), }; \ - static const struct tmc51xx_config tmc51xx_config_##inst = { \ - .gconf = ( \ - (DT_INST_PROP(inst, invert_direction) << TMC51XX_GCONF_SHAFT_SHIFT) | \ - (DT_INST_PROP(inst, test_mode) << TMC51XX_GCONF_TEST_MODE_SHIFT)), \ - .default_micro_step_res = DT_INST_PROP(inst, micro_step_res), \ - .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), \ - .is_sg_enabled = DT_INST_PROP(inst, activate_stallguard2), \ - COND_CODE_1(DT_INST_PROP(inst, activate_stallguard2),( \ - .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), ), ()) \ - IF_ENABLED(CONFIG_STEPPER_ADI_TMC_RAMP_GEN, \ - (.default_ramp_config = TMC_RAMP_DT_SPEC_GET(inst))) }; \ - TMC51XX_STEPPER_API_DEFINE(inst) \ - DEVICE_DT_INST_DEFINE(inst, tmc51xx_init, NULL, &tmc51xx_data_##inst, \ - &tmc51xx_config_##inst, POST_KERNEL, CONFIG_STEPPER_INIT_PRIORITY,\ +#define TMC51XX_DEFINE(inst) \ + BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) > 0), \ + "clock frequency must be non-zero positive value"); \ + COND_CODE_1(DT_INST_PROP_EXISTS(inst, stallguard_threshold_velocity), \ + BUILD_ASSERT(DT_INST_PROP(inst, stallguard_threshold_velocity), \ + "stallguard threshold velocity must be a positive value"), ()); \ + IF_ENABLED(CONFIG_STEPPER_ADI_TMC_RAMP_GEN, (CHECK_RAMP_DT_DATA(inst))); \ + static struct tmc51xx_data tmc51xx_data_##inst = { \ + .stepper = DEVICE_DT_INST_GET(inst), \ + }; \ + static const struct tmc51xx_config tmc51xx_config_##inst = { \ + .gconf = ((DT_INST_PROP(inst, invert_direction) << TMC51XX_GCONF_SHAFT_SHIFT) | \ + (DT_INST_PROP(inst, test_mode) << TMC51XX_GCONF_TEST_MODE_SHIFT)), \ + .default_micro_step_res = DT_INST_PROP(inst, micro_step_res), \ + .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), \ + .is_sg_enabled = DT_INST_PROP(inst, activate_stallguard2), \ + COND_CODE_1(DT_INST_PROP(inst, activate_stallguard2), ( \ + .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),), ()) IF_ENABLED(CONFIG_STEPPER_ADI_TMC_RAMP_GEN, \ + (.default_ramp_config = TMC_RAMP_DT_SPEC_GET(inst))) }; \ + TMC51XX_STEPPER_API_DEFINE(inst) \ + DEVICE_DT_INST_DEFINE(inst, tmc51xx_init, NULL, &tmc51xx_data_##inst, \ + &tmc51xx_config_##inst, POST_KERNEL, CONFIG_STEPPER_INIT_PRIORITY, \ &tmc51xx_api_##inst); DT_INST_FOREACH_STATUS_OKAY(TMC51XX_DEFINE) diff --git a/drivers/stepper/adi_tmc/adi_tmc_reg.h b/drivers/stepper/adi_tmc/adi_tmc_reg.h index 91521e5f7f178..0d0c219d6301b 100644 --- a/drivers/stepper/adi_tmc/adi_tmc_reg.h +++ b/drivers/stepper/adi_tmc/adi_tmc_reg.h @@ -97,7 +97,7 @@ extern "C" { (TMC5041_RAMPSTAT_POS_REACHED_EVENT_MASK >> TMC5041_RAMPSTAT_INT_SHIFT) #define TMC5041_RAMPSTAT_STOP_SG_EVENT_MASK BIT(6) -#define TMC5041_STOP_SG_EVENT (TMC5041_RAMPSTAT_STOP_SG_EVENT_MASK >> TMC5041_RAMPSTAT_INT_SHIFT) +#define TMC5041_STOP_SG_EVENT (TMC5041_RAMPSTAT_STOP_SG_EVENT_MASK >> TMC5041_RAMPSTAT_INT_SHIFT) #define TMC5041_RAMPSTAT_STOP_RIGHT_EVENT_MASK BIT(5) #define TMC5041_STOP_RIGHT_EVENT \ @@ -147,79 +147,78 @@ extern "C" { */ #define TMC51XX_GCONF_TEST_MODE_SHIFT 17 -#define TMC51XX_GCONF_SHAFT_SHIFT 4 - -#define TMC51XX_DRV_STATUS_STST_BIT BIT(31) - -#define TMC51XX_WRITE_BIT 0x80U -#define TMC51XX_ADDRESS_MASK 0x7FU - -#define TMC51XX_GCONF 0x00 -#define TMC51XX_GSTAT 0x01 -#define TMC51XX_IFCNT 0x02 -#define TMC51XX_SLAVECONF 0x03 -#define TMC51XX_INP_OUT 0x04 -#define TMC51XX_X_COMPARE 0x05 -#define TMC51XX_OTP_PROG 0x06 -#define TMC51XX_OTP_READ 0x07 -#define TMC51XX_FACTORY_CONF 0x08 -#define TMC51XX_SHORT_CONF 0x09 -#define TMC51XX_DRV_CONF 0x0A -#define TMC51XX_GLOBAL_SCALER 0x0B -#define TMC51XX_OFFSET_READ 0x0C -#define TMC51XX_IHOLD_IRUN 0x10 -#define TMC51XX_TPOWERDOWN 0x11 -#define TMC51XX_TSTEP 0x12 -#define TMC51XX_TPWMTHRS 0x13 -#define TMC51XX_TCOOLTHRS 0x14 -#define TMC51XX_THIGH 0x15 - -#define TMC51XX_RAMPMODE 0x20 -#define TMC51XX_XACTUAL 0x21 -#define TMC51XX_VACTUAL 0x22 -#define TMC51XX_VSTART 0x23 -#define TMC51XX_A1 0x24 -#define TMC51XX_V1 0x25 -#define TMC51XX_AMAX 0x26 -#define TMC51XX_VMAX 0x27 -#define TMC51XX_DMAX 0x28 -#define TMC51XX_D1 0x2A -#define TMC51XX_VSTOP 0x2B -#define TMC51XX_TZEROWAIT 0x2C -#define TMC51XX_XTARGET 0x2D - -#define TMC51XX_VDCMIN 0x33 -#define TMC51XX_SWMODE 0x34 -#define TMC51XX_RAMPSTAT 0x35 -#define TMC51XX_XLATCH 0x36 -#define TMC51XX_ENCMODE 0x38 -#define TMC51XX_XENC 0x39 -#define TMC51XX_ENC_CONST 0x3A -#define TMC51XX_ENC_STATUS 0x3B -#define TMC51XX_ENC_LATCH 0x3C -#define TMC51XX_ENC_DEVIATION 0x3D - -#define TMC51XX_MSLUT0 0x60 -#define TMC51XX_MSLUT1 0x61 -#define TMC51XX_MSLUT2 0x62 -#define TMC51XX_MSLUT3 0x63 -#define TMC51XX_MSLUT4 0x64 -#define TMC51XX_MSLUT5 0x65 -#define TMC51XX_MSLUT6 0x66 -#define TMC51XX_MSLUT7 0x67 -#define TMC51XX_MSLUTSEL 0x68 -#define TMC51XX_MSLUTSTART 0x69 -#define TMC51XX_MSCNT 0x6A -#define TMC51XX_MSCURACT 0x6B -#define TMC51XX_CHOPCONF 0x6C -#define TMC51XX_COOLCONF 0x6D -#define TMC51XX_DCCTRL 0x6E -#define TMC51XX_DRVSTATUS 0x6F -#define TMC51XX_PWMCONF 0x70 -#define TMC51XX_PWMSCALE 0x71 -#define TMC51XX_PWM_AUTO 0x72 -#define TMC51XX_LOST_STEPS 0x73 - +#define TMC51XX_GCONF_SHAFT_SHIFT 4 + +#define TMC51XX_DRV_STATUS_STST_BIT BIT(31) + +#define TMC51XX_WRITE_BIT 0x80U +#define TMC51XX_ADDRESS_MASK 0x7FU + +#define TMC51XX_GCONF 0x00 +#define TMC51XX_GSTAT 0x01 +#define TMC51XX_IFCNT 0x02 +#define TMC51XX_SLAVECONF 0x03 +#define TMC51XX_INP_OUT 0x04 +#define TMC51XX_X_COMPARE 0x05 +#define TMC51XX_OTP_PROG 0x06 +#define TMC51XX_OTP_READ 0x07 +#define TMC51XX_FACTORY_CONF 0x08 +#define TMC51XX_SHORT_CONF 0x09 +#define TMC51XX_DRV_CONF 0x0A +#define TMC51XX_GLOBAL_SCALER 0x0B +#define TMC51XX_OFFSET_READ 0x0C +#define TMC51XX_IHOLD_IRUN 0x10 +#define TMC51XX_TPOWERDOWN 0x11 +#define TMC51XX_TSTEP 0x12 +#define TMC51XX_TPWMTHRS 0x13 +#define TMC51XX_TCOOLTHRS 0x14 +#define TMC51XX_THIGH 0x15 + +#define TMC51XX_RAMPMODE 0x20 +#define TMC51XX_XACTUAL 0x21 +#define TMC51XX_VACTUAL 0x22 +#define TMC51XX_VSTART 0x23 +#define TMC51XX_A1 0x24 +#define TMC51XX_V1 0x25 +#define TMC51XX_AMAX 0x26 +#define TMC51XX_VMAX 0x27 +#define TMC51XX_DMAX 0x28 +#define TMC51XX_D1 0x2A +#define TMC51XX_VSTOP 0x2B +#define TMC51XX_TZEROWAIT 0x2C +#define TMC51XX_XTARGET 0x2D + +#define TMC51XX_VDCMIN 0x33 +#define TMC51XX_SWMODE 0x34 +#define TMC51XX_RAMPSTAT 0x35 +#define TMC51XX_XLATCH 0x36 +#define TMC51XX_ENCMODE 0x38 +#define TMC51XX_XENC 0x39 +#define TMC51XX_ENC_CONST 0x3A +#define TMC51XX_ENC_STATUS 0x3B +#define TMC51XX_ENC_LATCH 0x3C +#define TMC51XX_ENC_DEVIATION 0x3D + +#define TMC51XX_MSLUT0 0x60 +#define TMC51XX_MSLUT1 0x61 +#define TMC51XX_MSLUT2 0x62 +#define TMC51XX_MSLUT3 0x63 +#define TMC51XX_MSLUT4 0x64 +#define TMC51XX_MSLUT5 0x65 +#define TMC51XX_MSLUT6 0x66 +#define TMC51XX_MSLUT7 0x67 +#define TMC51XX_MSLUTSEL 0x68 +#define TMC51XX_MSLUTSTART 0x69 +#define TMC51XX_MSCNT 0x6A +#define TMC51XX_MSCURACT 0x6B +#define TMC51XX_CHOPCONF 0x6C +#define TMC51XX_COOLCONF 0x6D +#define TMC51XX_DCCTRL 0x6E +#define TMC51XX_DRVSTATUS 0x6F +#define TMC51XX_PWMCONF 0x70 +#define TMC51XX_PWMSCALE 0x71 +#define TMC51XX_PWM_AUTO 0x72 +#define TMC51XX_LOST_STEPS 0x73 #define TMC51XX_RAMPMODE_POSITIONING_MODE 0 #define TMC51XX_RAMPMODE_POSITIVE_VELOCITY_MODE 1 @@ -236,7 +235,7 @@ extern "C" { (TMC51XX_RAMPSTAT_POS_REACHED_EVENT_MASK >> TMC51XX_RAMPSTAT_INT_SHIFT) #define TMC51XX_RAMPSTAT_STOP_SG_EVENT_MASK BIT(6) -#define TMC51XX_STOP_SG_EVENT (TMC51XX_RAMPSTAT_STOP_SG_EVENT_MASK >> TMC51XX_RAMPSTAT_INT_SHIFT) +#define TMC51XX_STOP_SG_EVENT (TMC51XX_RAMPSTAT_STOP_SG_EVENT_MASK >> TMC51XX_RAMPSTAT_INT_SHIFT) #define TMC51XX_RAMPSTAT_STOP_RIGHT_EVENT_MASK BIT(5) #define TMC51XX_STOP_RIGHT_EVENT \ diff --git a/drivers/stepper/adi_tmc/adi_tmc_spi.c b/drivers/stepper/adi_tmc/adi_tmc_spi.c index 03ac6d884b88e..fd8d589ff07d0 100644 --- a/drivers/stepper/adi_tmc/adi_tmc_spi.c +++ b/drivers/stepper/adi_tmc/adi_tmc_spi.c @@ -19,7 +19,7 @@ static void parse_tmc_spi_status(const uint8_t status_byte) LOG_WRN("spi dataframe: reset_flag detected"); } if ((status_byte & BIT_MASK(1)) != 0) { - LOG_WRN("spi dataframe: driver_error/driver_error(1) detected"); + LOG_WRN("spi dataframe: driver_error detected"); } #ifdef CONFIG_STEPPER_ADI_TMC5041 if ((status_byte & BIT_MASK(2)) != 0) { diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 63e7fb948b73c..0a0b906d796d9 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -285,7 +285,7 @@ class ClangFormatCheck(ComplianceTest): path_hint = "" def run(self): - exe = f"clang-format-diff.{'exe' if platform.system() == 'Windows' else 'py'}" + exe = f"clang-format-diff{'exe' if platform.system() == 'Windows' else ''}" for file in get_files(): if Path(file).suffix not in ['.c', '.h']: