diff --git a/drivers/stepper/adi_tmc/CMakeLists.txt b/drivers/stepper/adi_tmc/CMakeLists.txt index c16479183f72..dbf4121447d9 100644 --- a/drivers/stepper/adi_tmc/CMakeLists.txt +++ b/drivers/stepper/adi_tmc/CMakeLists.txt @@ -4,7 +4,8 @@ zephyr_library() zephyr_library_property(ALLOW_EMPTY TRUE) -zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC_SPI adi_tmc_spi.c) zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC2209 tmc22xx.c) zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC50XX tmc50xx.c) -zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC51XX tmc51xx.c) +add_subdirectory_ifdef(CONFIG_STEPPER_ADI_TMC51XX tmc51xx) + +add_subdirectory_ifdef(CONFIG_STEPPER_ADI_TMC bus) diff --git a/drivers/stepper/adi_tmc/Kconfig b/drivers/stepper/adi_tmc/Kconfig index e8a86e6a4393..0221fbc187a8 100644 --- a/drivers/stepper/adi_tmc/Kconfig +++ b/drivers/stepper/adi_tmc/Kconfig @@ -17,6 +17,13 @@ config STEPPER_ADI_TMC_SPI help A Trinamic Stepper Controller with SPI is enabled +config STEPPER_ADI_TMC_UART + bool "Use Trinamic Stepper Controller with single wire UART" + depends on STEPPER_ADI_TMC + select UART + help + A Trinamic Stepper Controller with single wire UART is enabled + comment "Trinamic Stepper Drivers" rsource "Kconfig.tmc22xx" diff --git a/drivers/stepper/adi_tmc/Kconfig.tmc51xx b/drivers/stepper/adi_tmc/Kconfig.tmc51xx index 99e88ac11434..41ef6d7ea5d1 100644 --- a/drivers/stepper/adi_tmc/Kconfig.tmc51xx +++ b/drivers/stepper/adi_tmc/Kconfig.tmc51xx @@ -4,7 +4,8 @@ config STEPPER_ADI_TMC51XX bool "Activate trinamic tmc51xx stepper driver" depends on DT_HAS_ADI_TMC51XX_ENABLED && STEPPER_ADI_TMC - select STEPPER_ADI_TMC_SPI + select STEPPER_ADI_TMC_UART if $(dt_compat_on_bus,$(DT_COMPAT_ADI_TMC51XX),uart) + select STEPPER_ADI_TMC_SPI if $(dt_compat_on_bus,$(DT_COMPAT_ADI_TMC51XX),spi) default y module = TMC51XX diff --git a/drivers/stepper/adi_tmc/adi_tmc_reg.h b/drivers/stepper/adi_tmc/adi_tmc_reg.h index a245e3b37e64..0fa7dfa50024 100644 --- a/drivers/stepper/adi_tmc/adi_tmc_reg.h +++ b/drivers/stepper/adi_tmc/adi_tmc_reg.h @@ -1,5 +1,5 @@ /** - * @file drivers/stepper/adi/tmc_reg.h + * @file drivers/stepper/adi_tmc/adi_tmc_reg.h * * @brief TMC Registers * @@ -56,13 +56,19 @@ extern "C" { #define TMC5XXX_CHOPCONF_MRES_MASK GENMASK(27, 24) #define TMC5XXX_CHOPCONF_MRES_SHIFT 24 -#define TMC5XXX_RAMPSTAT_INT_MASK GENMASK(7, 4) +#define TMC5XXX_RAMPSTAT_INT_MASK GENMASK(9, 4) #define TMC5XXX_RAMPSTAT_INT_SHIFT 4 +#define TMC5XXX_RAMPSTAT_POS_REACHED_MASK BIT(9) +#define TMC5XXX_POS_REACHED \ + (TMC5XXX_RAMPSTAT_POS_REACHED_MASK >> TMC5XXX_RAMPSTAT_INT_SHIFT) + #define TMC5XXX_RAMPSTAT_POS_REACHED_EVENT_MASK BIT(7) #define TMC5XXX_POS_REACHED_EVENT \ (TMC5XXX_RAMPSTAT_POS_REACHED_EVENT_MASK >> TMC5XXX_RAMPSTAT_INT_SHIFT) +#define TMC5XXX_POS_REACHED_AND_EVENT (TMC5XXX_POS_REACHED | TMC5XXX_POS_REACHED_EVENT) + #define TMC5XXX_RAMPSTAT_STOP_SG_EVENT_MASK BIT(6) #define TMC5XXX_STOP_SG_EVENT \ (TMC5XXX_RAMPSTAT_STOP_SG_EVENT_MASK >> TMC5XXX_RAMPSTAT_INT_SHIFT) diff --git a/drivers/stepper/adi_tmc/bus/CMakeLists.txt b/drivers/stepper/adi_tmc/bus/CMakeLists.txt new file mode 100644 index 000000000000..fc10daf070d1 --- /dev/null +++ b/drivers/stepper/adi_tmc/bus/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_include_directories(include) + +zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC_SPI adi_tmc_spi.c) +zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC_UART adi_tmc_uart.c) diff --git a/drivers/stepper/adi_tmc/adi_tmc_spi.c b/drivers/stepper/adi_tmc/bus/adi_tmc_spi.c similarity index 98% rename from drivers/stepper/adi_tmc/adi_tmc_spi.c rename to drivers/stepper/adi_tmc/bus/adi_tmc_spi.c index f9a29f2129e8..ef75fe166a78 100644 --- a/drivers/stepper/adi_tmc/adi_tmc_spi.c +++ b/drivers/stepper/adi_tmc/bus/adi_tmc_spi.c @@ -4,7 +4,7 @@ */ #include -#include "adi_tmc_spi.h" +#include #define BUFFER_SIZE 5U diff --git a/drivers/stepper/adi_tmc/bus/adi_tmc_uart.c b/drivers/stepper/adi_tmc/bus/adi_tmc_uart.c new file mode 100644 index 000000000000..873ae36524b4 --- /dev/null +++ b/drivers/stepper/adi_tmc/bus/adi_tmc_uart.c @@ -0,0 +1,163 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(tmc_uart, CONFIG_STEPPER_LOG_LEVEL); + +/* TMC UART standard datagram size */ +#define ADI_TMC_UART_DATAGRAM_SIZE 8 +/* TMC UART read request datagram size */ +#define ADI_TMC_UART_READ_REQ_DATAGRAM_SIZE 4 +/* TMC UART protocol constants */ +#define ADI_TMC_UART_SYNC_BYTE 0x05 +#define ADI_TMC_UART_WRITE_BIT 0x80 + +uint8_t tmc_uart_calc_crc(const uint8_t *datagram, uint8_t len) +{ + uint8_t crc = 0; + + for (uint8_t i = 0; i < len; i++) { + uint8_t current_byte = datagram[i]; + + for (uint8_t j = 0; j < 8; j++) { + if ((crc >> 7) ^ (current_byte & 0x01)) { + crc = (crc << 1) ^ 0x07; + } else { + crc = (crc << 1) & 0xFF; + } + current_byte = current_byte >> 1; + } + } + + return crc; +} + +static int tmc_uart_send_byte_with_echo(const struct device *uart, uint8_t byte) +{ + uint8_t echo_byte; + int err; + + uart_poll_out(uart, byte); + + /* Wait for echo with timeout */ + k_timepoint_t end = sys_timepoint_calc(K_MSEC(5)); /* 5ms timeout for echo */ + + do { + err = uart_poll_in(uart, &echo_byte); + if (err >= 0 && echo_byte == byte) { + /* Received matching echo */ + return 0; + } + } while (err == -1 && !sys_timepoint_expired(end)); + + LOG_ERR("Echo mismatch or timeout: sent 0x%02X", byte); + return -EIO; +} + +int tmc_uart_write_register(const struct device *uart, uint8_t device_addr, + uint8_t register_address, uint32_t data) +{ + uint8_t buffer[ADI_TMC_UART_DATAGRAM_SIZE]; + int err = 0; + + /* Format the UART TMC datagram */ + buffer[0] = ADI_TMC_UART_SYNC_BYTE; /* Sync byte */ + buffer[1] = device_addr; /* Device address */ + buffer[2] = register_address | ADI_TMC_UART_WRITE_BIT; /* Register address with write bit */ + sys_put_be32(data, &buffer[3]); /* Write data */ + buffer[7] = tmc_uart_calc_crc(buffer, ADI_TMC_UART_DATAGRAM_SIZE - 1U); /* CRC */ + + /* Send datagram byte by byte using polling */ + for (size_t i = 0; i < ADI_TMC_UART_DATAGRAM_SIZE; i++) { + err = tmc_uart_send_byte_with_echo(uart, buffer[i]); + if (err) { + LOG_ERR("Failed to send byte %d: 0x%02X", i, buffer[i]); + return err; + } + } + + return 0; +} + +int tmc_uart_read_register(const struct device *uart, uint8_t device_addr, uint8_t register_address, + uint32_t *data) +{ + uint8_t write_buffer[ADI_TMC_UART_READ_REQ_DATAGRAM_SIZE]; + uint8_t read_buffer[ADI_TMC_UART_DATAGRAM_SIZE]; + struct uart_config uart_cfg; + + int err = 0; + + /* Get current UART configuration */ + err = uart_config_get(uart, &uart_cfg); + if (err) { + LOG_ERR("Failed to get UART configuration: %d", err); + return -EIO; + } + + /* Calculate delay based on UART baudrate (SENDDELAY: default=8 bit times))*/ + uint32_t delay_us = (8 * 1000000) / uart_cfg.baudrate; + + /* Format the UART TMC datagram for read */ + write_buffer[0] = ADI_TMC_UART_SYNC_BYTE; /* Sync byte */ + write_buffer[1] = device_addr; /* Device address */ + write_buffer[2] = register_address; /* Register address */ + write_buffer[3] = tmc_uart_calc_crc(write_buffer, 3); + + /* Send read request byte by byte and wait for each echo */ + for (size_t i = 0; i < ADI_TMC_UART_READ_REQ_DATAGRAM_SIZE; i++) { + err = tmc_uart_send_byte_with_echo(uart, write_buffer[i]); + if (err) { + LOG_ERR("Failed to send byte %d: 0x%02X", i, write_buffer[i]); + return -EIO; + } + } + + /* Small delay to allow device to prepare response */ + k_busy_wait(delay_us); + + /* Receive response with timeout */ + for (size_t i = 0; i < sizeof(read_buffer) && (err == 0); i++) { + k_timepoint_t end = sys_timepoint_calc(K_MSEC(1000)); + + do { + err = uart_poll_in(uart, &read_buffer[i]); + } while (err == -1 && !sys_timepoint_expired(end)); + + if (err == -1) { + LOG_ERR("Timeout waiting for byte %d for register 0x%x", i, + register_address); + return -EAGAIN; + } + if (err < 0) { + LOG_ERR("Error %d receiving byte %d for register 0x%x", err, i, + register_address); + return -EIO; + } + } + + /* Print the received bytes */ + LOG_HEXDUMP_DBG(read_buffer, ADI_TMC_UART_DATAGRAM_SIZE, "Received bytes:"); + + /* Validate CRC */ + uint8_t crc = tmc_uart_calc_crc(read_buffer, ADI_TMC_UART_DATAGRAM_SIZE - 1U); + + if (crc != read_buffer[7]) { + LOG_ERR("CRC mismatch for register 0x%x: got 0x%x, expected 0x%x", register_address, + read_buffer[7], crc); + return -EIO; + } + + /* Construct a 32-bit register value from received bytes */ + *data = sys_get_be32(&read_buffer[3]); + + return 0; +} diff --git a/drivers/stepper/adi_tmc/bus/include/adi_tmc_bus.h b/drivers/stepper/adi_tmc/bus/include/adi_tmc_bus.h new file mode 100644 index 000000000000..ed72a3ea6b60 --- /dev/null +++ b/drivers/stepper/adi_tmc/bus/include/adi_tmc_bus.h @@ -0,0 +1,59 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_STEPPER_ADI_TMC_BUS_H_ +#define ZEPHYR_DRIVERS_STEPPER_ADI_TMC_BUS_H_ + +#include +#include +#include + +/* Communication interface types */ +#define TMC_COMM_SPI 0 +#define TMC_COMM_UART 1 + +union tmc_bus { + struct spi_dt_spec spi; + const struct device *uart; +}; + +/** + * @brief Function pointer type for bus check function. + * @param bus Pointer to the bus structure. + * @param comm_type Communication type (SPI or UART). + * @return 0 if bus is ready, negative error code otherwise. + */ +typedef int (*tmc_bus_check_fn)(const union tmc_bus *bus, uint8_t comm_type); + +/** + * @brief Function pointer type for register read function. + * @param dev Pointer to the device structure. + * @param reg Register address to read. + * @param val Pointer to store the read value. + * @return 0 on success, negative error code otherwise. + */ +typedef int (*tmc_reg_read_fn)(const struct device *dev, uint8_t reg, uint32_t *val); + +/** + * @brief Function pointer type for register write function. + * @param dev Pointer to the device structure. + * @param reg Register address to write. + * @param val Value to write to the register. + * @return 0 on success, negative error code otherwise. + */ +typedef int (*tmc_reg_write_fn)(const struct device *dev, uint8_t reg, uint32_t val); + +/** + * @brief Structure for bus I/O operations. + * Contains function pointers for bus check, register read, and register write. + */ +struct tmc_bus_io { + tmc_bus_check_fn check; /* Function to check if the bus is ready */ + tmc_reg_read_fn read; /* Function to read a register */ + tmc_reg_write_fn write; /* Function to write to a register */ +}; + +#endif /* ZEPHYR_DRIVERS_STEPPER_ADI_TMC_BUS_H_ */ diff --git a/drivers/stepper/adi_tmc/adi_tmc_spi.h b/drivers/stepper/adi_tmc/bus/include/adi_tmc_spi.h similarity index 85% rename from drivers/stepper/adi_tmc/adi_tmc_spi.h rename to drivers/stepper/adi_tmc/bus/include/adi_tmc_spi.h index c228b6192d41..a49a0a6ba593 100644 --- a/drivers/stepper/adi_tmc/adi_tmc_spi.h +++ b/drivers/stepper/adi_tmc/bus/include/adi_tmc_spi.h @@ -1,5 +1,5 @@ /** - * @file drivers/stepper/adi/stepper.h + * @file drivers/stepper/adi_tmc/bus/include/adi_tmc_spi.h * * @brief Private API for Trinamic SPI bus * @@ -10,8 +10,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_DRIVERS_STEPPER_ADI_TMC_SPI_H_ -#define ZEPHYR_DRIVERS_STEPPER_ADI_TMC_SPI_H_ +#ifndef ZEPHYR_DRIVERS_STEPPER_ADI_TMC_BUS_SPI_H_ +#define ZEPHYR_DRIVERS_STEPPER_ADI_TMC_BUS_SPI_H_ #ifdef __cplusplus extern "C" { @@ -60,4 +60,4 @@ int tmc_spi_write_register(const struct spi_dt_spec *bus, const uint8_t write_bi } #endif -#endif /* ZEPHYR_DRIVERS_STEPPER_ADI_TMC_SPI_H_ */ +#endif /* ZEPHYR_DRIVERS_STEPPER_ADI_TMC_BUS_SPI_H_ */ diff --git a/drivers/stepper/adi_tmc/bus/include/adi_tmc_uart.h b/drivers/stepper/adi_tmc/bus/include/adi_tmc_uart.h new file mode 100644 index 000000000000..db1888d6cf81 --- /dev/null +++ b/drivers/stepper/adi_tmc/bus/include/adi_tmc_uart.h @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_STEPPER_ADI_TMC_BUS_UART_H_ +#define ZEPHYR_DRIVERS_STEPPER_ADI_TMC_BUS_UART_H_ + +#include + +/** + * @brief Calculate CRC for TMC UART datagram + * + * @param datagram Pointer to datagram buffer + * @param len Length of datagram + * @return uint8_t CRC value + */ +uint8_t tmc_uart_calc_crc(const uint8_t *datagram, uint8_t len); + +/** + * @brief Read register via UART single-wire interface + * + * @param uart Pointer to UART device specification + * @param device_addr Secondary address of TMC device + * @param register_address Register address to read + * @param data Pointer to store read data + * @return int 0 on success, negative errno on failure + */ +int tmc_uart_read_register(const struct device *uart, uint8_t device_addr, uint8_t register_address, + uint32_t *data); + +/** + * @brief Write register via UART single-wire interface + * + * @param uart Pointer to UART device specification + * @param device_addr Secondary address of the TMC device + * @param register_address Register address to write + * @param data Data to write to register + * @return int 0 on success, negative errno on failure + */ +int tmc_uart_write_register(const struct device *uart, uint8_t device_addr, + uint8_t register_address, uint32_t data); + +#endif /* ZEPHYR_DRIVERS_STEPPER_ADI_TMC_BUS_UART_H_ */ diff --git a/drivers/stepper/adi_tmc/tmc50xx.c b/drivers/stepper/adi_tmc/tmc50xx.c index b9eaafa70be9..f9e83c91192a 100644 --- a/drivers/stepper/adi_tmc/tmc50xx.c +++ b/drivers/stepper/adi_tmc/tmc50xx.c @@ -11,7 +11,7 @@ #include #include -#include "adi_tmc_spi.h" +#include #include "adi_tmc5xxx_common.h" #include @@ -276,6 +276,8 @@ static void rampstat_work_handler(struct k_work *work) break; case TMC5XXX_POS_REACHED_EVENT: + case TMC5XXX_POS_REACHED: + case TMC5XXX_POS_REACHED_AND_EVENT: LOG_DBG("RAMPSTAT %s:Position reached", stepper_data->stepper->name); execute_callback(stepper_data->stepper, STEPPER_EVENT_STEPS_COMPLETED); break; diff --git a/drivers/stepper/adi_tmc/tmc51xx/CMakeLists.txt b/drivers/stepper/adi_tmc/tmc51xx/CMakeLists.txt new file mode 100644 index 000000000000..027a7be4b51f --- /dev/null +++ b/drivers/stepper/adi_tmc/tmc51xx/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC51XX tmc51xx.c tmc51xx_spi.c tmc51xx_uart.c) diff --git a/drivers/stepper/adi_tmc/tmc51xx.c b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.c similarity index 75% rename from drivers/stepper/adi_tmc/tmc51xx.c rename to drivers/stepper/adi_tmc/tmc51xx/tmc51xx.c index 7cb1867d31f4..54d5cffcbc48 100644 --- a/drivers/stepper/adi_tmc/tmc51xx.c +++ b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.c @@ -4,45 +4,23 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT adi_tmc51xx - #include #include -#include -#include "adi_tmc_spi.h" -#include "adi_tmc5xxx_common.h" +#include +#include "tmc51xx.h" +#include "../adi_tmc5xxx_common.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. */ - struct k_work_delayable rampstat_callback_dwork; - struct gpio_callback diag0_cb; - /* device pointer required to access config in k_work */ - const struct device *stepper; - stepper_event_callback_t callback; - void *event_cb_user_data; -}; +static inline int tmc51xx_bus_check(const struct device *dev) +{ + const struct tmc51xx_config *config = dev->config; -struct tmc51xx_config { - const uint32_t gconf; - struct spi_dt_spec spi; - const uint32_t clock_frequency; - const uint16_t default_micro_step_res; - const int8_t sg_threshold; - const bool is_sg_enabled; - const uint32_t sg_velocity_check_interval_ms; - const uint32_t sg_threshold_velocity; -#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN - const struct tmc_ramp_generator_data default_ramp_config; -#endif - struct gpio_dt_spec diag0_gpio; -}; + return config->bus_io->check(&config->bus, config->comm_type); +} static int read_actual_position(const struct device *dev, int32_t *position); static void rampstat_work_handler(struct k_work *work); @@ -54,12 +32,11 @@ static int tmc51xx_write(const struct device *dev, const uint8_t reg_addr, const { 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, TMC5XXX_WRITE_BIT, reg_addr, reg_val); + err = config->bus_io->write(dev, reg_addr, reg_val); k_sem_give(&data->sem); @@ -74,12 +51,11 @@ static int tmc51xx_read(const struct device *dev, const uint8_t reg_addr, uint32 { 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, TMC5XXX_ADDRESS_MASK, reg_addr, reg_val); + err = config->bus_io->read(dev, reg_addr, reg_val); k_sem_give(&data->sem); @@ -94,14 +70,16 @@ 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; - const struct tmc51xx_config *config = dev->config; - int err; + __maybe_unused const struct tmc51xx_config *config = dev->config; + + __maybe_unused int err; data->callback = callback; data->event_cb_user_data = user_data; /* Configure DIAG0 GPIO interrupt pin */ - if (config->diag0_gpio.port) { + IF_ENABLED(TMC51XX_BUS_SPI, ({ + if ((config->comm_type == TMC_COMM_SPI) && config->diag0_gpio.port) { LOG_INF("Configuring DIAG0 GPIO interrupt pin"); if (!gpio_is_ready_dt(&config->diag0_gpio)) { LOG_ERR("DIAG0 interrupt GPIO not ready"); @@ -138,7 +116,7 @@ static int tmc51xx_stepper_set_event_callback(const struct device *dev, if (err != 0) { return -EIO; } - } + }})) return 0; } @@ -201,7 +179,7 @@ static int stallguard_enable(const struct device *dev, const bool enable) static void stallguard_work_handler(struct k_work *work) { struct k_work_delayable *dwork = k_work_delayable_from_work(work); - struct tmc51xx_data *stepper_data = + struct tmc51xx_data const *stepper_data = CONTAINER_OF(dwork, struct tmc51xx_data, stallguard_dwork); const struct device *dev = stepper_data->stepper; const struct tmc51xx_config *config = dev->config; @@ -267,7 +245,7 @@ static void rampstat_work_handler(struct k_work *work) struct tmc51xx_data *stepper_data = CONTAINER_OF(dwork, struct tmc51xx_data, rampstat_callback_dwork); const struct device *dev = stepper_data->stepper; - const struct tmc51xx_config *config = dev->config; + __maybe_unused const struct tmc51xx_config *config = dev->config; __ASSERT_NO_MSG(dev); @@ -314,6 +292,8 @@ static void rampstat_work_handler(struct k_work *work) break; case TMC5XXX_POS_REACHED_EVENT: + case TMC5XXX_POS_REACHED: + case TMC5XXX_POS_REACHED_AND_EVENT: LOG_DBG("RAMPSTAT %s:Position reached", dev->name); stepper_trigger_callback(dev, STEPPER_EVENT_STEPS_COMPLETED); break; @@ -324,23 +304,30 @@ static void rampstat_work_handler(struct k_work *work) stepper_trigger_callback(dev, STEPPER_EVENT_STALL_DETECTED); break; default: - LOG_ERR("Illegal ramp stat bit field"); + LOG_ERR("Illegal ramp stat bit field 0x%x", ramp_stat_values); break; } } else { - /* Only reschedule polling if DIAG0 interrupt is not configured */ - if (!config->diag0_gpio.port) { + /* For SPI with DIAG0 pin, we use interrupt-driven approach */ + IF_ENABLED(TMC51XX_BUS_SPI, ({ + if (config->comm_type == TMC_COMM_SPI && config->diag0_gpio.port) { + /* Using interrupt-driven approach - no polling needed */ + return; + } + })) + + /* For UART or SPI without DIAG0, reschedule RAMPSTAT polling */ #ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC - k_work_reschedule( - &stepper_data->rampstat_callback_dwork, - K_MSEC(CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); + k_work_reschedule( + &stepper_data->rampstat_callback_dwork, + K_MSEC(CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC)); #endif /* CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC */ - } } } -static void tmc51xx_diag0_gpio_callback_handler(const struct device *port, struct gpio_callback *cb, - gpio_port_pins_t pins) +static void __maybe_unused tmc51xx_diag0_gpio_callback_handler(const struct device *port, + struct gpio_callback *cb, + gpio_port_pins_t pins) { ARG_UNUSED(port); ARG_UNUSED(pins); @@ -482,9 +469,27 @@ static int tmc51xx_stepper_set_reference_position(const struct device *dev, cons static int read_actual_position(const struct device *dev, int32_t *position) { + const struct tmc51xx_config *config = dev->config; + int err; uint32_t raw_value; + /* Check if device is using UART and is currently moving */ + if (config->comm_type == TMC_COMM_UART) { + bool is_moving; + + err = tmc51xx_stepper_is_moving(dev, &is_moving); + if (err != 0) { + return -EIO; + } + + if (is_moving) { + LOG_WRN("%s: Reading position while moving over UART is not supported", + dev->name); + return -ENOTSUP; + } + } + err = tmc51xx_read(dev, TMC51XX_XACTUAL, &raw_value); if (err != 0) { return -EIO; @@ -530,7 +535,16 @@ static int tmc51xx_stepper_move_to(const struct device *dev, const int32_t micro k_work_reschedule(&data->stallguard_dwork, K_MSEC(config->sg_velocity_check_interval_ms)); } - if (data->callback && !config->diag0_gpio.port) { + if (data->callback) { + /* For SPI with DIAG0 pin, we use interrupt-driven approach */ + IF_ENABLED(TMC51XX_BUS_SPI, ({ + if (config->comm_type == TMC_COMM_SPI && config->diag0_gpio.port) { + /* Using interrupt-driven approach - no polling needed */ + return 0; + } + })) + + /* For UART or SPI without DIAG0, reschedule RAMPSTAT polling */ #ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC k_work_reschedule( &data->rampstat_callback_dwork, @@ -545,7 +559,7 @@ static int tmc51xx_stepper_move_by(const struct device *dev, const int32_t micro int err; int32_t position; - err = stepper_get_actual_position(dev, &position); + err = tmc51xx_stepper_get_actual_position(dev, &position); if (err != 0) { return -EIO; } @@ -590,7 +604,16 @@ static int tmc51xx_stepper_run(const struct device *dev, const enum stepper_dire k_work_reschedule(&data->stallguard_dwork, K_MSEC(config->sg_velocity_check_interval_ms)); } - if (data->callback && !config->diag0_gpio.port) { + if (data->callback) { + /* For SPI with DIAG0 pin, we use interrupt-driven approach */ + IF_ENABLED(TMC51XX_BUS_SPI, ({ + if (config->comm_type == TMC_COMM_SPI && config->diag0_gpio.port) { + /* Using interrupt-driven approach - no polling needed */ + return 0; + } + })) + + /* For UART or SPI without DIAG0, reschedule RAMPSTAT polling */ #ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC k_work_reschedule( &data->rampstat_callback_dwork, @@ -678,10 +701,27 @@ static int tmc51xx_init(const struct device *dev) k_sem_init(&data->sem, 1, 1); - if (!spi_is_ready_dt(&config->spi)) { - LOG_ERR("SPI bus is not ready"); - return -ENODEV; + err = tmc51xx_bus_check(dev); + if (err < 0) { + LOG_ERR("Bus not ready for '%s'", dev->name); + return err; + } + +#if TMC51XX_BUS_UART + /* Initialize SW_SEL GPIO if using UART and GPIO is specified */ + if (config->comm_type == TMC_COMM_UART && config->sw_sel_gpio.port) { + if (!gpio_is_ready_dt(&config->sw_sel_gpio)) { + LOG_ERR("SW_SEL GPIO not ready"); + return -ENODEV; + } + + err = gpio_pin_configure_dt(&config->sw_sel_gpio, GPIO_OUTPUT_ACTIVE); + if (err < 0) { + LOG_ERR("Failed to configure SW_SEL GPIO"); + return err; + } } +#endif LOG_DBG("GCONF: %d", config->gconf); err = tmc51xx_write(dev, TMC5XXX_GCONF, config->gconf); @@ -760,36 +800,51 @@ static DEVICE_API(stepper, tmc51xx_api) = { .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"); \ - static struct tmc51xx_data tmc51xx_data_##inst = { \ - .stepper = DEVICE_DT_GET(DT_DRV_INST(inst))}; \ - COND_CODE_1(DT_PROP_EXISTS(inst, stallguard_threshold_velocity), \ - BUILD_ASSERT(DT_PROP(inst, stallguard_threshold_velocity), \ - "stallguard threshold velocity must be a positive value"), ()); \ - IF_ENABLED(CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN, (CHECK_RAMP_DT_DATA(inst))); \ - static const struct tmc51xx_config tmc51xx_config_##inst = { \ - .gconf = ((DT_INST_PROP(inst, en_pwm_mode) << TMC51XX_GCONF_EN_PWM_MODE_SHIFT) | \ - (DT_INST_PROP(inst, test_mode) << TMC51XX_GCONF_TEST_MODE_SHIFT) | \ - (DT_INST_PROP(inst, invert_direction) << TMC51XX_GCONF_SHAFT_SHIFT) | \ - (DT_INST_NODE_HAS_PROP(inst, diag0_gpios) \ - ? BIT(TMC51XX_GCONF_DIAG0_INT_PUSHPULL_SHIFT) \ - : 0)), \ - .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), \ - .default_micro_step_res = DT_INST_PROP(inst, micro_step_res), \ - .sg_threshold = DT_INST_PROP(inst, stallguard2_threshold), \ - .sg_threshold_velocity = DT_INST_PROP(inst, stallguard_threshold_velocity), \ - .sg_velocity_check_interval_ms = \ - DT_INST_PROP(inst, stallguard_velocity_check_interval_ms), \ - .is_sg_enabled = DT_INST_PROP(inst, activate_stallguard2), \ - IF_ENABLED(CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN, \ - (.default_ramp_config = TMC_RAMP_DT_SPEC_GET_TMC51XX(inst))), \ - .diag0_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, diag0_gpios, {0})}; \ +/* Initializes a struct tmc51xx_config for an instance on a SPI bus. */ +#define TMC51XX_CONFIG_SPI(inst) \ + .comm_type = TMC_COMM_SPI, \ + .bus.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), \ + .bus_io = &tmc51xx_spi_bus_io, \ + .diag0_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, diag0_gpios, {0}) + +/* Initializes a struct tmc51xx_config for an instance on a UART bus. */ +#define TMC51XX_CONFIG_UART(inst) \ + .comm_type = TMC_COMM_UART, .bus.uart = DEVICE_DT_GET(DT_INST_BUS(inst)), \ + .bus_io = &tmc51xx_uart_bus_io, .uart_addr = DT_INST_PROP_OR(inst, uart_device_addr, 1U), \ + .sw_sel_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, sw_sel_gpios, {0}) + +/* Device initialization macros */ +#define TMC51XX_DEFINE(inst) \ + BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) > 0), \ + "clock frequency must be non-zero positive value"); \ + static struct tmc51xx_data tmc51xx_data_##inst = { \ + .stepper = DEVICE_DT_GET(DT_DRV_INST(inst))}; \ + COND_CODE_1(DT_PROP_EXISTS(inst, stallguard_threshold_velocity), \ + BUILD_ASSERT(DT_PROP(inst, stallguard_threshold_velocity), \ + "stallguard threshold velocity must be a positive value"), ()); \ + IF_ENABLED(CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN, (CHECK_RAMP_DT_DATA(inst))); \ + static const struct tmc51xx_config tmc51xx_config_##inst = {COND_CODE_1 \ + (DT_INST_ON_BUS(inst, spi), \ + (TMC51XX_CONFIG_SPI(inst)), \ + (TMC51XX_CONFIG_UART(inst))), \ + .gconf = ((DT_INST_PROP(inst, en_pwm_mode) << TMC51XX_GCONF_EN_PWM_MODE_SHIFT) | \ + (DT_INST_PROP(inst, test_mode) << TMC51XX_GCONF_TEST_MODE_SHIFT) | \ + (DT_INST_PROP(inst, invert_direction) << TMC51XX_GCONF_SHAFT_SHIFT) | \ + (DT_INST_NODE_HAS_PROP(inst, diag0_gpios) \ + ? BIT(TMC51XX_GCONF_DIAG0_INT_PUSHPULL_SHIFT) \ + : 0)), \ + .clock_frequency = DT_INST_PROP(inst, clock_frequency), \ + .default_micro_step_res = DT_INST_PROP(inst, micro_step_res), \ + .sg_threshold = DT_INST_PROP(inst, stallguard2_threshold), \ + .sg_threshold_velocity = DT_INST_PROP(inst, stallguard_threshold_velocity), \ + .sg_velocity_check_interval_ms = \ + DT_INST_PROP(inst, stallguard_velocity_check_interval_ms), \ + .is_sg_enabled = DT_INST_PROP(inst, activate_stallguard2), \ + IF_ENABLED(CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN, \ + (.default_ramp_config = TMC_RAMP_DT_SPEC_GET_TMC51XX(inst)))}; \ DEVICE_DT_INST_DEFINE(inst, tmc51xx_init, NULL, &tmc51xx_data_##inst, \ &tmc51xx_config_##inst, POST_KERNEL, CONFIG_STEPPER_INIT_PRIORITY, \ &tmc51xx_api); diff --git a/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.h b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.h new file mode 100644 index 000000000000..43c26255dfd8 --- /dev/null +++ b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.h @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_STEPPER_ADI_TMC51XX_H +#define ZEPHYR_DRIVERS_STEPPER_ADI_TMC51XX_H + +#include +#include + +#include + +#define DT_DRV_COMPAT adi_tmc51xx + +/* Check for supported bus types */ +#define TMC51XX_BUS_SPI DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) +#define TMC51XX_BUS_UART DT_ANY_INST_ON_BUS_STATUS_OKAY(uart) + +/* Common configuration structure for TMC51xx */ +struct tmc51xx_config { + union tmc_bus bus; + const struct tmc_bus_io *bus_io; + uint8_t comm_type; + const uint32_t gconf; + const uint32_t clock_frequency; + const uint16_t default_micro_step_res; + const int8_t sg_threshold; + const bool is_sg_enabled; + const uint32_t sg_velocity_check_interval_ms; + const uint32_t sg_threshold_velocity; +#ifdef CONFIG_STEPPER_ADI_TMC51XX_RAMP_GEN + const struct tmc_ramp_generator_data default_ramp_config; +#endif +#if TMC51XX_BUS_UART + const struct gpio_dt_spec sw_sel_gpio; + uint8_t uart_addr; +#endif +#if TMC51XX_BUS_SPI + struct gpio_dt_spec diag0_gpio; +#endif +}; + +struct tmc51xx_data { + struct k_sem sem; + struct k_work_delayable stallguard_dwork; + struct k_work_delayable rampstat_callback_dwork; + struct gpio_callback diag0_cb; + const struct device *stepper; + stepper_event_callback_t callback; + void *event_cb_user_data; +}; + +#if TMC51XX_BUS_SPI +/* SPI bus I/O operations for TMC51xx devices */ +extern const struct tmc_bus_io tmc51xx_spi_bus_io; +#endif + +#if TMC51XX_BUS_UART +/* UART bus I/O operations for TMC51xx devices */ +extern const struct tmc_bus_io tmc51xx_uart_bus_io; +#endif + +#endif /* ZEPHYR_DRIVERS_STEPPER_ADI_TMC51XX_H */ diff --git a/drivers/stepper/adi_tmc/tmc51xx/tmc51xx_spi.c b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx_spi.c new file mode 100644 index 000000000000..5a4871bd860a --- /dev/null +++ b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx_spi.c @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +#include "tmc51xx.h" +#include "../adi_tmc_reg.h" + +#if TMC51XX_BUS_SPI +LOG_MODULE_DECLARE(tmc51xx, CONFIG_STEPPER_LOG_LEVEL); + +static int tmc51xx_bus_check_spi(const union tmc_bus *bus, uint8_t comm_type) +{ + if (comm_type != TMC_COMM_SPI) { + return -ENOTSUP; + } + return spi_is_ready_dt(&bus->spi) ? 0 : -ENODEV; +} + +static int tmc51xx_reg_write_spi(const struct device *dev, const uint8_t reg_addr, + const uint32_t reg_val) +{ + const struct tmc51xx_config *config = dev->config; + int err; + + err = tmc_spi_write_register(&config->bus.spi, TMC5XXX_WRITE_BIT, reg_addr, reg_val); + + if (err < 0) { + LOG_ERR("Failed to write register 0x%x with value 0x%x", reg_addr, reg_val); + } + return err; +} + +static int tmc51xx_reg_read_spi(const struct device *dev, const uint8_t reg_addr, uint32_t *reg_val) +{ + const struct tmc51xx_config *config = dev->config; + int err; + + err = tmc_spi_read_register(&config->bus.spi, TMC5XXX_ADDRESS_MASK, reg_addr, reg_val); + + if (err < 0) { + LOG_ERR("Failed to read register 0x%x", reg_addr); + } + return err; +} + +const struct tmc_bus_io tmc51xx_spi_bus_io = { + .check = tmc51xx_bus_check_spi, + .read = tmc51xx_reg_read_spi, + .write = tmc51xx_reg_write_spi, +}; +#endif /* TMC51XX_BUS_SPI */ diff --git a/drivers/stepper/adi_tmc/tmc51xx/tmc51xx_uart.c b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx_uart.c new file mode 100644 index 000000000000..bc523bfe7335 --- /dev/null +++ b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx_uart.c @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "tmc51xx.h" +#include +#include + +#if TMC51XX_BUS_UART +LOG_MODULE_DECLARE(tmc51xx, CONFIG_STEPPER_LOG_LEVEL); + +static int tmc51xx_bus_check_uart(const union tmc_bus *bus, uint8_t comm_type) +{ + if (comm_type != TMC_COMM_UART) { + return -ENOTSUP; + } + return device_is_ready(bus->uart) ? 0 : -ENODEV; +} + +static int tmc51xx_reg_write_uart(const struct device *dev, const uint8_t reg_addr, + const uint32_t reg_val) +{ + const struct tmc51xx_config *config = dev->config; + int err; + + /* Route to the adi_tmc_uart.h implementation */ + err = tmc_uart_write_register(config->bus.uart, config->uart_addr, reg_addr, reg_val); + + if (err < 0) { + LOG_ERR("Failed to write register 0x%x with value 0x%x", reg_addr, reg_val); + } + /* Wait for the write to complete */ + k_sleep(K_MSEC(1)); + return err; +} + +static int tmc51xx_reg_read_uart(const struct device *dev, const uint8_t reg_addr, + uint32_t *reg_val) +{ + const struct tmc51xx_config *config = dev->config; + int err; + + /* Route to the adi_tmc_uart.h implementation */ + err = tmc_uart_read_register(config->bus.uart, config->uart_addr, reg_addr, reg_val); + + if (err < 0) { + LOG_ERR("Failed to read register 0x%x", reg_addr); + } + /* Wait for the read to complete */ + k_sleep(K_MSEC(1)); + return err; +} + +const struct tmc_bus_io tmc51xx_uart_bus_io = { + .check = tmc51xx_bus_check_uart, + .read = tmc51xx_reg_read_uart, + .write = tmc51xx_reg_write_uart, +}; +#endif /* TMC51XX_BUS_UART */ diff --git a/dts/bindings/stepper/adi/adi,tmc51xx-base.yaml b/dts/bindings/stepper/adi/adi,tmc51xx-base.yaml new file mode 100644 index 000000000000..dbdd40065c4a --- /dev/null +++ b/dts/bindings/stepper/adi/adi,tmc51xx-base.yaml @@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Prevas A/S +# SPDX-License-Identifier: Apache-2.0 + +description: | + Common properties for Analog Devices TMC51XX Stepper Motor Controller + +include: + - name: adi,trinamic-gconf.yaml + property-allowlist: + - en-pwm-mode + - test-mode + - name: stepper-controller.yaml + - name: adi,trinamic-ramp-generator.yaml + property-allowlist: + - vstart + - a1 + - v1 + - amax + - vmax + - dmax + - d1 + - vstop + - tzerowait + - thigh + - tcoolthrs + - tpwmthrs + - tpowerdown + - ihold + - irun + - iholddelay + - name: adi,trinamic-stallguard.yaml + property-allowlist: + - activate-stallguard2 + - stallguard2-threshold + - stallguard-threshold-velocity + - stallguard-velocity-check-interval-ms + +properties: + "#address-cells": + 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 TMC51XX. + This is used for real world conversion. + + Hint: µstep velocity v[Hz] µsteps / s v[Hz] = v[51xx] * ( fCLK[Hz]/2 / 2^23 ) + where v[51xx] is the value written to the TMC51XX. diff --git a/dts/bindings/stepper/adi/adi,tmc51xx-spi.yaml b/dts/bindings/stepper/adi/adi,tmc51xx-spi.yaml new file mode 100644 index 000000000000..f9213a95c11c --- /dev/null +++ b/dts/bindings/stepper/adi/adi,tmc51xx-spi.yaml @@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty +# SPDX-License-Identifier: Apache-2.0 + +description: | + Analog Devices TMC51XX Stepper Motor Controller (SPI mode) + + Example: + + &spi0 { + tmc51xx: tmc51xx@0 { + compatible = "adi,tmc51xx"; + reg = <0>; + spi-max-frequency = ; + diag0-gpios = <&gpio0 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* Diag0 pin */ + + #address-cells = <1>; + #size-cells = <0>; + + /* Common settings from base binding */ + clock-frequency = ; /* Internal/External Clock frequency */ + en-pwm-mode; + invert-direction; + micro-step-res = <256>; + + /* ADI TMC ramp generator as well as current settings */ + vstart = <0>; + vstop = <10>; + a1 = <1000>; + v1 = <50000>; + d1 = <1400>; + vmax = <200000>; + amax = <50000>; + dmax = <700>; + tzerowait = <100>; + ihold = <10>; + irun = <31>; + iholddelay = <6>; + }; + }; + +compatible: "adi,tmc51xx" + +include: [spi-device.yaml, "adi,tmc51xx-base.yaml"] + +properties: + reg: + required: true + + diag0-gpios: + type: phandle-array + description: | + Diagnostics output DIAG0 pin. This pin enables interrupt-based + rampstat handling, allowing the driver to respond to motor events + like position reached or stall detection without polling. + Should be configured as push-pull output (active high). diff --git a/dts/bindings/stepper/adi/adi,tmc51xx-uart.yaml b/dts/bindings/stepper/adi/adi,tmc51xx-uart.yaml new file mode 100644 index 000000000000..a6691ff36b06 --- /dev/null +++ b/dts/bindings/stepper/adi/adi,tmc51xx-uart.yaml @@ -0,0 +1,60 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty +# SPDX-License-Identifier: Apache-2.0 + +description: | + Analog Devices TMC51XX Stepper Motor Controller (UART single-wire mode) + + This binding supports the single-wire UART mode where: + - SWIOP is connected to the MCU's UART TX/RX pin + - SWION should be connected to half the IO level voltage (1.65V for 3.3V systems) + - SW_SEL must be HIGH (either via GPIO control or hardwired) + + Example: + + &uart2 { + current-speed = <115200>; + status = "okay"; + + tmc51xx: tmc51xx { + compatible = "adi,tmc51xx"; + sw-sel-gpios = <&gpiob 0x01 GPIO_ACTIVE_HIGH>; + + /* Common settings from base binding */ + clock-frequency = ; + en-pwm-mode; + invert-direction; + micro-step-res = <256>; + + /* ADI TMC ramp generator as well as current settings */ + vstart = <0>; + vstop = <10>; + a1 = <1000>; + v1 = <50000>; + d1 = <1400>; + vmax = <200000>; + amax = <50000>; + dmax = <700>; + tzerowait = <100>; + ihold = <10>; + irun = <31>; + iholddelay = <6>; + }; + }; + +compatible: "adi,tmc51xx" + +include: [uart-device.yaml, "adi,tmc51xx-base.yaml"] + +properties: + sw-sel-gpios: + type: phandle-array + description: | + GPIO connected to the SW_SEL pin of TMC51XX. + Must be set HIGH for UART mode operation. + If not provided, it's assumed SW_SEL is hardwired to VCC/HIGH. + + uart-device-addr: + type: int + description: | + UART device address for TMC51XX in UART mode. + Valid range: 0 - 253 diff --git a/dts/bindings/stepper/adi/adi,tmc51xx.yaml b/dts/bindings/stepper/adi/adi,tmc51xx.yaml deleted file mode 100644 index 003a91ea74a5..000000000000 --- a/dts/bindings/stepper/adi/adi,tmc51xx.yaml +++ /dev/null @@ -1,117 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025 Prevas A/S -# SPDX-License-Identifier: Apache-2.0 - -description: | - Analog Devices TMC51XX Stepper Motor Controller - - Example: - - &spi0 { - /* SPI bus options here, not shown */ - - /* Controller/driver for one 2-phase bipolar stepper motor */ - tmc51xx: tmc51xx@0 { - compatible = "adi,tmc51xx"; - reg = <0>; - spi-max-frequency = ; /* Maximum SPI bus frequency */ - diag0-gpios = <&gpio0 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* Diag0 pin */ - - #address-cells = <1>; - #size-cells = <0>; - - en-pwm-mode; test-mode; /* ADI TMC Global configuration flags */ - clock-frequency = ; /* Internal/External Clock frequency */ - - /* common stepper controller settings */ - invert-direction; - micro-step-res = <256>; - - /* ADI TMC stallguard settings specific to TMC51XX */ - 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>; - thigh = <90>; - tcoolthrs = <100>; - tpwmthrs = <110>; - tpowerdown = <120>; - ihold = <1>; - irun = <2>; - iholddelay = <3>; - }; - }; - - -compatible: "adi,tmc51xx" - -include: - - name: spi-device.yaml - - name: adi,trinamic-gconf.yaml - property-allowlist: - - en-pwm-mode - - test-mode - - name: stepper-controller.yaml - - name: base.yaml - property-allowlist: - - reg - - name: adi,trinamic-ramp-generator.yaml - property-allowlist: - - vstart - - a1 - - v1 - - amax - - vmax - - dmax - - d1 - - vstop - - tzerowait - - thigh - - tcoolthrs - - tpwmthrs - - tpowerdown - - ihold - - irun - - iholddelay - - name: adi,trinamic-stallguard.yaml - property-allowlist: - - activate-stallguard2 - - stallguard2-threshold - - stallguard-threshold-velocity - - stallguard-velocity-check-interval-ms - -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 TMC51XX. - This is used for real world conversion. - - Hint: µstep velocity v[Hz] µsteps / s v[Hz] = v[51xx] * ( fCLK[Hz]/2 / 2^23 ) - where v[51xx] is the value written to the TMC51XX. - - diag0-gpios: - type: phandle-array - description: | - Diagnostics output DIAG0 pin. This pin enables interrupt-based - rampstat handling, allowing the driver to respond to motor events - like position reached or stall detection without polling. - Should be configured as push-pull output (active high). diff --git a/tests/drivers/build_all/stepper/app.overlay b/tests/drivers/build_all/stepper/app.overlay index f199789db3a3..177d15926bcd 100644 --- a/tests/drivers/build_all/stepper/app.overlay +++ b/tests/drivers/build_all/stepper/app.overlay @@ -31,5 +31,13 @@ #include "spi.dtsi" }; + + test_uart: uart@55556666 { + compatible = "vnd,serial"; + reg = <0x55556666 0x1000>; + status = "okay"; + + #include "uart.dtsi" + }; }; }; diff --git a/tests/drivers/build_all/stepper/prj.conf b/tests/drivers/build_all/stepper/prj.conf index 95072495fa44..f466b1c2e849 100644 --- a/tests/drivers/build_all/stepper/prj.conf +++ b/tests/drivers/build_all/stepper/prj.conf @@ -4,5 +4,6 @@ CONFIG_LOG=y CONFIG_STEPPER_LOG_LEVEL_DBG=y CONFIG_GPIO=y CONFIG_SPI=y +CONFIG_SERIAL=y CONFIG_STEPPER=y CONFIG_EMUL=y diff --git a/tests/drivers/build_all/stepper/spi.dtsi b/tests/drivers/build_all/stepper/spi.dtsi index 1895ed382be9..0f6bfbc13db3 100644 --- a/tests/drivers/build_all/stepper/spi.dtsi +++ b/tests/drivers/build_all/stepper/spi.dtsi @@ -124,7 +124,7 @@ adi_tmc51xx_1: adi_tmc51xx@1 { adi_tmc51xx_2: adi_tmc51xx@2 { compatible = "adi,tmc51xx"; status = "okay"; - reg = <0x01>; + reg = <0x02>; spi-max-frequency = <8000000>; label = "tmc5160_2"; diff --git a/tests/drivers/build_all/stepper/uart.dtsi b/tests/drivers/build_all/stepper/uart.dtsi new file mode 100644 index 000000000000..e2116bae1f42 --- /dev/null +++ b/tests/drivers/build_all/stepper/uart.dtsi @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty + * SPDX-License-Identifier: Apache-2.0 + */ +/**************************************** + * PLEASE KEEP REG ADDRESSES SEQUENTIAL * + ***************************************/ + +adi_tmc51xx_uart: adi_tmc51xx { + compatible = "adi,tmc51xx"; + status = "okay"; + + label = "tmc5160_uart_1"; + + en-pwm-mode; test-mode; /* ADI TMC Global configuration flags */ + clock-frequency = <16000000>; /* Internal/External Clock frequency */ + + /* common stepper controller settings */ + invert-direction; + micro-step-res = <256>; + + /* ADI TMC stallguard settings specific to TMC5160 */ + activate-stallguard2; + stallguard-velocity-check-interval-ms = <100>; + stallguard2-threshold = <9>; + stallguard-threshold-velocity = <50000>; + + /* ADI TMC ramp generator as well as current settings */ + vstart = <10>; + a1 = <20>; + v1 = <30>; + d1 = <40>; + vmax = <50>; + amax = <60>; + dmax = <70>; + tzerowait = <80>; + thigh = <90>; + tcoolthrs = <100>; + tpwmthrs = <110>; + tpowerdown = <120>; + ihold = <1>; + irun = <2>; + iholddelay = <3>; +};