1 /* 2 * Copyright 2024 Fabian Blatz <fabianblatz@gmail.com> 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #ifndef ZEPHYR_DRIVER_STEPPER_STEP_DIR_STEPPER_COMMON_H_ 8 #define ZEPHYR_DRIVER_STEPPER_STEP_DIR_STEPPER_COMMON_H_ 9 10 /** 11 * @brief Stepper Driver APIs 12 * @defgroup step_dir_stepper Stepper Driver APIs 13 * @ingroup io_interfaces 14 * @{ 15 */ 16 17 #include <zephyr/device.h> 18 #include <zephyr/drivers/gpio.h> 19 #include <zephyr/drivers/stepper.h> 20 #include <zephyr/drivers/counter.h> 21 22 #include "step_dir_stepper_timing_source.h" 23 24 /** 25 * @brief Common step direction stepper config. 26 * 27 * This structure **must** be placed first in the driver's config structure. 28 */ 29 struct step_dir_stepper_common_config { 30 const struct gpio_dt_spec step_pin; 31 const struct gpio_dt_spec dir_pin; 32 bool dual_edge; 33 const struct stepper_timing_source_api *timing_source; 34 const struct device *counter; 35 bool invert_direction; 36 }; 37 38 /** 39 * @brief Initialize common step direction stepper config from devicetree instance. 40 * If the counter property is set, the timing source will be set to the counter timing 41 * source. 42 * 43 * @param node_id The devicetree node identifier. 44 */ 45 #define STEP_DIR_STEPPER_DT_COMMON_CONFIG_INIT(node_id) \ 46 { \ 47 .step_pin = GPIO_DT_SPEC_GET(node_id, step_gpios), \ 48 .dir_pin = GPIO_DT_SPEC_GET(node_id, dir_gpios), \ 49 .dual_edge = DT_PROP_OR(node_id, dual_edge_step, false), \ 50 .counter = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(node_id, counter)), \ 51 .invert_direction = DT_PROP(node_id, invert_direction), \ 52 .timing_source = COND_CODE_1(DT_NODE_HAS_PROP(node_id, counter), \ 53 (&step_counter_timing_source_api), \ 54 (&step_work_timing_source_api)), \ 55 } 56 57 /** 58 * @brief Initialize common step direction stepper config from devicetree instance. 59 * @param inst Instance. 60 */ 61 #define STEP_DIR_STEPPER_DT_INST_COMMON_CONFIG_INIT(inst) \ 62 STEP_DIR_STEPPER_DT_COMMON_CONFIG_INIT(DT_DRV_INST(inst)) 63 64 /** 65 * @brief Common step direction stepper data. 66 * 67 * This structure **must** be placed first in the driver's data structure. 68 */ 69 struct step_dir_stepper_common_data { 70 const struct device *dev; 71 struct k_spinlock lock; 72 enum stepper_direction direction; 73 enum stepper_run_mode run_mode; 74 uint64_t microstep_interval_ns; 75 atomic_t actual_position; 76 atomic_t step_count; 77 stepper_event_callback_t callback; 78 void *event_cb_user_data; 79 80 struct k_work_delayable stepper_dwork; 81 82 #ifdef CONFIG_STEP_DIR_STEPPER_COUNTER_TIMING 83 struct counter_top_cfg counter_top_cfg; 84 bool counter_running; 85 #endif /* CONFIG_STEP_DIR_STEPPER_COUNTER_TIMING */ 86 87 #ifdef CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS 88 struct k_work event_callback_work; 89 struct k_msgq event_msgq; 90 uint8_t event_msgq_buffer[CONFIG_STEPPER_STEP_DIR_EVENT_QUEUE_LEN * 91 sizeof(enum stepper_event)]; 92 #endif /* CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS */ 93 }; 94 95 /** 96 * @brief Initialize common step direction stepper data from devicetree instance. 97 * 98 * @param node_id The devicetree node identifier. 99 */ 100 #define STEP_DIR_STEPPER_DT_COMMON_DATA_INIT(node_id) \ 101 { \ 102 .dev = DEVICE_DT_GET(node_id), \ 103 } 104 105 /** 106 * @brief Initialize common step direction stepper data from devicetree instance. 107 * @param inst Instance. 108 */ 109 #define STEP_DIR_STEPPER_DT_INST_COMMON_DATA_INIT(inst) \ 110 STEP_DIR_STEPPER_DT_COMMON_DATA_INIT(DT_DRV_INST(inst)) 111 112 /** 113 * @brief Validate the offset of the common data structures. 114 * 115 * @param config Name of the config structure. 116 * @param data Name of the data structure. 117 */ 118 #define STEP_DIR_STEPPER_STRUCT_CHECK(config, data) \ 119 BUILD_ASSERT(offsetof(config, common) == 0, \ 120 "struct step_dir_stepper_common_config must be placed first"); \ 121 BUILD_ASSERT(offsetof(data, common) == 0, \ 122 "struct step_dir_stepper_common_data must be placed first"); 123 124 /** 125 * @brief Common function to initialize a step direction stepper device at init time. 126 * 127 * This function must be called at the end of the device init function. 128 * 129 * @param dev Step direction stepper device instance. 130 * 131 * @retval 0 If initialized successfully. 132 * @retval -errno Negative errno in case of failure. 133 */ 134 int step_dir_stepper_common_init(const struct device *dev); 135 136 /** 137 * @brief Move the stepper motor by a given number of micro_steps. 138 * 139 * @param dev Pointer to the device structure. 140 * @param micro_steps Number of micro_steps to move. Can be positive or negative. 141 * @return 0 on success, or a negative error code on failure. 142 */ 143 int step_dir_stepper_common_move_by(const struct device *dev, const int32_t micro_steps); 144 145 /** 146 * @brief Set the step interval of the stepper motor. 147 * 148 * @param dev Pointer to the device structure. 149 * @param microstep_interval_ns The step interval in nanoseconds. 150 * @return 0 on success, or a negative error code on failure. 151 */ 152 int step_dir_stepper_common_set_microstep_interval(const struct device *dev, 153 const uint64_t microstep_interval_ns); 154 155 /** 156 * @brief Set the reference position of the stepper motor. 157 * 158 * @param dev Pointer to the device structure. 159 * @param value The reference position value to set. 160 * @return 0 on success, or a negative error code on failure. 161 */ 162 int step_dir_stepper_common_set_reference_position(const struct device *dev, const int32_t value); 163 164 /** 165 * @brief Get the actual (reference) position of the stepper motor. 166 * 167 * @param dev Pointer to the device structure. 168 * @param value Pointer to a variable where the position value will be stored. 169 * @return 0 on success, or a negative error code on failure. 170 */ 171 int step_dir_stepper_common_get_actual_position(const struct device *dev, int32_t *value); 172 173 /** 174 * @brief Set the absolute target position of the stepper motor. 175 * 176 * @param dev Pointer to the device structure. 177 * @param value The target position to set. 178 * @return 0 on success, or a negative error code on failure. 179 */ 180 int step_dir_stepper_common_move_to(const struct device *dev, const int32_t value); 181 182 /** 183 * @brief Check if the stepper motor is still moving. 184 * 185 * @param dev Pointer to the device structure. 186 * @param is_moving Pointer to a boolean where the movement status will be stored. 187 * @return 0 on success, or a negative error code on failure. 188 */ 189 int step_dir_stepper_common_is_moving(const struct device *dev, bool *is_moving); 190 191 /** 192 * @brief Run the stepper with a given direction and step interval. 193 * 194 * @param dev Pointer to the device structure. 195 * @param direction The direction of movement (positive or negative). 196 * @return 0 on success, or a negative error code on failure. 197 */ 198 int step_dir_stepper_common_run(const struct device *dev, const enum stepper_direction direction); 199 200 /** 201 * @brief Stop the stepper motor. 202 * 203 * @param dev Pointer to the device structure. 204 * @return 0 on success, or a negative error code on failure. 205 */ 206 int step_dir_stepper_common_stop(const struct device *dev); 207 208 /** 209 * @brief Set a callback function for stepper motor events. 210 * 211 * This function sets a user-defined callback that will be invoked when a stepper motor event 212 * occurs. 213 * 214 * @param dev Pointer to the device structure. 215 * @param callback The callback function to set. 216 * @param user_data Pointer to user-defined data that will be passed to the callback. 217 * @return 0 on success, or a negative error code on failure. 218 */ 219 int step_dir_stepper_common_set_event_callback(const struct device *dev, 220 stepper_event_callback_t callback, void *user_data); 221 222 /** 223 * @brief Handle a timing signal and update the stepper position. 224 * @param dev Pointer to the device structure. 225 */ 226 void stepper_handle_timing_signal(const struct device *dev); 227 228 /** 229 * @brief Trigger callback function for stepper motor events. 230 * @param dev Pointer to the device structure. 231 * @param event The stepper_event to rigger the callback for. 232 */ 233 void stepper_trigger_callback(const struct device *dev, enum stepper_event event); 234 235 /** @} */ 236 237 #endif /* ZEPHYR_DRIVER_STEPPER_STEP_DIR_STEPPER_COMMON_H_ */ 238