1 /**
2  * @file drivers/stepper.h
3  *
4  * @brief Public API for Stepper Driver
5  *
6  */
7 
8 /*
9  * SPDX-FileCopyrightText: Copyright (c) 2024 Carl Zeiss Meditec AG
10  * SPDX-FileCopyrightText: Copyright (c) 2024 Jilay Sandeep Pandya
11  * SPDX-License-Identifier: Apache-2.0
12  */
13 
14 #ifndef ZEPHYR_INCLUDE_DRIVERS_STEPPER_H_
15 #define ZEPHYR_INCLUDE_DRIVERS_STEPPER_H_
16 
17 /**
18  * @brief Stepper Controller Interface
19  * @defgroup stepper_interface Stepper Controller Interface
20  * @ingroup io_interfaces
21  * @{
22  */
23 
24 #include <zephyr/kernel.h>
25 #include <zephyr/device.h>
26 #include <errno.h>
27 
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 #define MICRO_STEP_RES_INDEX(res) LOG2(res)
33 
34 /**
35  * @brief Stepper Motor micro step resolution options
36  */
37 enum stepper_micro_step_resolution {
38 	/** Full step resolution */
39 	STEPPER_MICRO_STEP_1 = 1,
40 	/** 2 micro steps per full step */
41 	STEPPER_MICRO_STEP_2 = 2,
42 	/** 4 micro steps per full step */
43 	STEPPER_MICRO_STEP_4 = 4,
44 	/** 8 micro steps per full step */
45 	STEPPER_MICRO_STEP_8 = 8,
46 	/** 16 micro steps per full step */
47 	STEPPER_MICRO_STEP_16 = 16,
48 	/** 32 micro steps per full step */
49 	STEPPER_MICRO_STEP_32 = 32,
50 	/** 64 micro steps per full step */
51 	STEPPER_MICRO_STEP_64 = 64,
52 	/** 128 micro steps per full step */
53 	STEPPER_MICRO_STEP_128 = 128,
54 	/** 256 micro steps per full step */
55 	STEPPER_MICRO_STEP_256 = 256,
56 };
57 
58 /**
59  * @brief Stepper Motor direction options
60  */
61 enum stepper_direction {
62 	/** Negative direction */
63 	STEPPER_DIRECTION_NEGATIVE = 0,
64 	/** Positive direction */
65 	STEPPER_DIRECTION_POSITIVE = 1,
66 };
67 
68 /**
69  * @brief Stepper Motor run mode options
70  */
71 enum stepper_run_mode {
72 	/** Hold Mode */
73 	STEPPER_RUN_MODE_HOLD = 0,
74 	/** Position Mode*/
75 	STEPPER_RUN_MODE_POSITION = 1,
76 	/** Velocity Mode */
77 	STEPPER_RUN_MODE_VELOCITY = 2,
78 };
79 
80 /**
81  * @brief Stepper Events
82  */
83 enum stepper_event {
84 	/** Steps set using move or set_target_position have been executed */
85 	STEPPER_EVENT_STEPS_COMPLETED = 0,
86 	/** Stall detected */
87 	STEPPER_EVENT_STALL_DETECTED = 1,
88 	/** Left end switch status changes to pressed */
89 	STEPPER_EVENT_LEFT_END_STOP_DETECTED = 2,
90 	/** Right end switch status changes to pressed */
91 	STEPPER_EVENT_RIGHT_END_STOP_DETECTED = 3,
92 };
93 
94 /**
95  * @cond INTERNAL_HIDDEN
96  *
97  * Stepper motor controller driver API definition and system call entry points.
98  *
99  */
100 
101 /**
102  * @brief enable or disable the stepper motor controller.
103  *
104  * @see stepper_enable() for details.
105  */
106 typedef int (*stepper_enable_t)(const struct device *dev, const bool enable);
107 
108 /**
109  * @brief Move the stepper motor relatively by a given number of micro_steps.
110  *
111  * @see stepper_move_by() for details.
112  */
113 typedef int (*stepper_move_by_t)(const struct device *dev, const int32_t micro_steps);
114 
115 /**
116  * @brief Set the max velocity in micro_steps per seconds.
117  *
118  * @see stepper_set_max_velocity() for details.
119  */
120 typedef int (*stepper_set_max_velocity_t)(const struct device *dev,
121 					  const uint32_t micro_steps_per_second);
122 
123 /**
124  * @brief Set the micro-step resolution
125  *
126  * @see stepper_set_micro_step_res() for details.
127  */
128 typedef int (*stepper_set_micro_step_res_t)(const struct device *dev,
129 					    const enum stepper_micro_step_resolution resolution);
130 
131 /**
132  * @brief Get the micro-step resolution
133  *
134  * @see stepper_get_micro_step_res() for details.
135  */
136 typedef int (*stepper_get_micro_step_res_t)(const struct device *dev,
137 					    enum stepper_micro_step_resolution *resolution);
138 /**
139  * @brief Set the reference position of the stepper
140  *
141  * @see stepper_set_actual_position() for details.
142  */
143 typedef int (*stepper_set_reference_position_t)(const struct device *dev, const int32_t value);
144 
145 /**
146  * @brief Get the actual a.k.a reference position of the stepper
147  *
148  * @see stepper_get_actual_position() for details.
149  */
150 typedef int (*stepper_get_actual_position_t)(const struct device *dev, int32_t *value);
151 
152 /**
153  * @brief Move the stepper motor absolutely by a given number of micro_steps.
154  *
155  * @see stepper_move_to() for details.
156  */
157 typedef int (*stepper_move_to_t)(const struct device *dev, const int32_t micro_steps);
158 
159 /**
160  * @brief Is the target position fo the stepper reached
161  *
162  * @see stepper_is_moving() for details.
163  */
164 typedef int (*stepper_is_moving_t)(const struct device *dev, bool *is_moving);
165 
166 /**
167  * @brief Run the stepper with a given velocity in a given direction
168  *
169  * @see stepper_run() for details.
170  */
171 typedef int (*stepper_run_t)(const struct device *dev, const enum stepper_direction direction,
172 			     const uint32_t value);
173 
174 /**
175  * @brief Callback function for stepper events
176  */
177 typedef void (*stepper_event_callback_t)(const struct device *dev, const enum stepper_event event,
178 					 void *user_data);
179 
180 /**
181  * @brief Set the callback function to be called when a stepper event occurs
182  *
183  * @see stepper_set_event_callback() for details.
184  */
185 typedef int (*stepper_set_event_callback_t)(const struct device *dev,
186 					    stepper_event_callback_t callback, void *user_data);
187 
188 /**
189  * @brief Stepper Motor Controller API
190  */
191 __subsystem struct stepper_driver_api {
192 	stepper_enable_t enable;
193 	stepper_move_by_t move_by;
194 	stepper_set_max_velocity_t set_max_velocity;
195 	stepper_set_micro_step_res_t set_micro_step_res;
196 	stepper_get_micro_step_res_t get_micro_step_res;
197 	stepper_set_reference_position_t set_reference_position;
198 	stepper_get_actual_position_t get_actual_position;
199 	stepper_move_to_t move_to;
200 	stepper_is_moving_t is_moving;
201 	stepper_run_t run;
202 	stepper_set_event_callback_t set_event_callback;
203 };
204 
205 /**
206  * @endcond
207  */
208 
209 /**
210  * @brief Enable or Disable Motor Controller
211  *
212  * @param dev pointer to the stepper motor controller instance
213  * @param enable Input enable or disable motor controller
214  *
215  * @retval -EIO Error during Enabling
216  * @retval 0 Success
217  */
218 __syscall int stepper_enable(const struct device *dev, const bool enable);
219 
z_impl_stepper_enable(const struct device * dev,const bool enable)220 static inline int z_impl_stepper_enable(const struct device *dev, const bool enable)
221 {
222 	const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api;
223 
224 	return api->enable(dev, enable);
225 }
226 
227 /**
228  * @brief Set the micro_steps to be moved from the current position i.e. relative movement
229  *
230  * @details The motor will move by the given number of micro_steps from the current position.
231  * This function is non-blocking.
232  *
233  * @param dev pointer to the stepper motor controller instance
234  * @param micro_steps target micro_steps to be moved from the current position
235  *
236  * @retval -ECANCELED If the stepper is disabled
237  * @retval -EIO General input / output error
238  * @retval	0 Success
239  */
240 __syscall int stepper_move_by(const struct device *dev, int32_t micro_steps);
241 
z_impl_stepper_move_by(const struct device * dev,const int32_t micro_steps)242 static inline int z_impl_stepper_move_by(const struct device *dev, const int32_t micro_steps)
243 {
244 	const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api;
245 
246 	return api->move_by(dev, micro_steps);
247 }
248 
249 /**
250  * @brief Set the target velocity to be reached by the motor
251  *
252  * @details For controllers such as DRV8825 where you
253  * toggle the STEP Pin, the pulse_length would have to be calculated based on this parameter in the
254  * driver. For controllers where velocity can be set, this parameter corresponds to max_velocity
255  * @note Setting max velocity does not set the motor into motion, a combination of set_max_velocity
256  * and move is required to set the motor into motion.
257  *
258  * @param dev pointer to the stepper motor controller instance
259  * @param micro_steps_per_second speed in micro_steps per second
260  *
261  * @retval -EIO General input / output error
262  * @retval -EINVAL If the requested velocity is not supported
263  * @retval 0 Success
264  */
265 __syscall int stepper_set_max_velocity(const struct device *dev, uint32_t micro_steps_per_second);
266 
z_impl_stepper_set_max_velocity(const struct device * dev,const uint32_t micro_steps_per_second)267 static inline int z_impl_stepper_set_max_velocity(const struct device *dev,
268 						  const uint32_t micro_steps_per_second)
269 {
270 	const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api;
271 
272 	return api->set_max_velocity(dev, micro_steps_per_second);
273 }
274 
275 /**
276  * @brief Set the microstep resolution in stepper motor controller
277  *
278  * @param dev pointer to the stepper motor controller instance
279  * @param resolution microstep resolution
280  *
281  * @retval -EIO General input / output error
282  * @retval -ENOSYS If not implemented by device driver
283  * @retval -ENOTSUP If the requested resolution is not supported
284  * @retval 0 Success
285  */
286 __syscall int stepper_set_micro_step_res(const struct device *dev,
287 					 enum stepper_micro_step_resolution resolution);
288 
z_impl_stepper_set_micro_step_res(const struct device * dev,enum stepper_micro_step_resolution resolution)289 static inline int z_impl_stepper_set_micro_step_res(const struct device *dev,
290 						    enum stepper_micro_step_resolution resolution)
291 {
292 	const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api;
293 
294 	if (api->set_micro_step_res == NULL) {
295 		return -ENOSYS;
296 	}
297 	return api->set_micro_step_res(dev, resolution);
298 }
299 
300 /**
301  * @brief Get the microstep resolution in stepper motor controller
302  *
303  * @param dev pointer to the stepper motor controller instance
304  * @param resolution microstep resolution
305  *
306  * @retval -EIO General input / output error
307  * @retval -ENOSYS If not implemented by device driver
308  * @retval 0 Success
309  */
310 __syscall int stepper_get_micro_step_res(const struct device *dev,
311 					 enum stepper_micro_step_resolution *resolution);
312 
z_impl_stepper_get_micro_step_res(const struct device * dev,enum stepper_micro_step_resolution * resolution)313 static inline int z_impl_stepper_get_micro_step_res(const struct device *dev,
314 						    enum stepper_micro_step_resolution *resolution)
315 {
316 	const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api;
317 
318 	if (api->get_micro_step_res == NULL) {
319 		return -ENOSYS;
320 	}
321 	return api->get_micro_step_res(dev, resolution);
322 }
323 
324 /**
325  * @brief Set the reference position of the stepper
326  *
327  * @param dev Pointer to the stepper motor controller instance.
328  * @param value The reference position to set in micro-steps.
329  *
330  * @retval -EIO General input / output error
331  * @retval -ENOSYS If not implemented by device driver
332  * @retval 0 Success
333  */
334 __syscall int stepper_set_reference_position(const struct device *dev, int32_t value);
335 
z_impl_stepper_set_reference_position(const struct device * dev,const int32_t value)336 static inline int z_impl_stepper_set_reference_position(const struct device *dev,
337 							const int32_t value)
338 {
339 	const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api;
340 
341 	if (api->set_reference_position == NULL) {
342 		return -ENOSYS;
343 	}
344 	return api->set_reference_position(dev, value);
345 }
346 
347 /**
348  * @brief Get the actual a.k.a reference position of the stepper
349  *
350  * @param dev pointer to the stepper motor controller instance
351  * @param value The actual position to get in micro_steps
352  *
353  * @retval -EIO General input / output error
354  * @retval -ENOSYS If not implemented by device driver
355  * @retval 0 Success
356  */
357 __syscall int stepper_get_actual_position(const struct device *dev, int32_t *value);
358 
z_impl_stepper_get_actual_position(const struct device * dev,int32_t * value)359 static inline int z_impl_stepper_get_actual_position(const struct device *dev, int32_t *value)
360 {
361 	const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api;
362 
363 	if (api->get_actual_position == NULL) {
364 		return -ENOSYS;
365 	}
366 	return api->get_actual_position(dev, value);
367 }
368 
369 /**
370  * @brief Set the absolute target position of the stepper
371  *
372  * @details The motor will move to the given micro_steps position from the reference position.
373  * This function is non-blocking.
374  *
375  * @param dev pointer to the stepper motor controller instance
376  * @param micro_steps target position to set in micro_steps
377  *
378  * @retval -ECANCELED If the stepper is disabled
379  * @retval -EIO General input / output error
380  * @retval -ENOSYS If not implemented by device driver
381  * @retval 0 Success
382  */
383 __syscall int stepper_move_to(const struct device *dev, int32_t micro_steps);
384 
z_impl_stepper_move_to(const struct device * dev,const int32_t micro_steps)385 static inline int z_impl_stepper_move_to(const struct device *dev, const int32_t micro_steps)
386 {
387 	const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api;
388 
389 	if (api->move_to == NULL) {
390 		return -ENOSYS;
391 	}
392 	return api->move_to(dev, micro_steps);
393 }
394 
395 /**
396  * @brief Check if the stepper motor is currently moving
397  *
398  * @param dev pointer to the stepper motor controller instance
399  * @param is_moving Pointer to a boolean to store the moving status of the stepper motor
400  *
401  * @retval -EIO General input / output error
402  * @retval -ENOSYS If not implemented by device driver
403  * @retval 0 Success
404  */
405 __syscall int stepper_is_moving(const struct device *dev, bool *is_moving);
406 
z_impl_stepper_is_moving(const struct device * dev,bool * is_moving)407 static inline int z_impl_stepper_is_moving(const struct device *dev, bool *is_moving)
408 {
409 	const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api;
410 
411 	if (api->is_moving == NULL) {
412 		return -ENOSYS;
413 	}
414 	return api->is_moving(dev, is_moving);
415 }
416 
417 /**
418  * @brief Run the stepper with a given velocity in a given direction
419  *
420  * @details If velocity > 0, motor shall be set into motion and run incessantly until and unless
421  * stalled or stopped using some other command, for instance, motor_enable(false).
422  * This function is non-blocking.
423  *
424  * @param dev pointer to the stepper motor controller instance
425  * @param direction The direction to set
426  * @param velocity The velocity to set in microsteps per second
427  *                 - > 0: Run the stepper with the given velocity in a given direction
428  *                 - 0: Stop the stepper
429  *
430  * @retval -ECANCELED If the stepper is disabled
431  * @retval -EIO General input / output error
432  * @retval -ENOSYS If not implemented by device driver
433  * @retval 0 Success
434  */
435 __syscall int stepper_run(const struct device *dev, enum stepper_direction direction,
436 			  uint32_t velocity);
437 
z_impl_stepper_run(const struct device * dev,const enum stepper_direction direction,const uint32_t velocity)438 static inline int z_impl_stepper_run(const struct device *dev,
439 				     const enum stepper_direction direction,
440 				     const uint32_t velocity)
441 {
442 	const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api;
443 
444 	if (api->run == NULL) {
445 		return -ENOSYS;
446 	}
447 	return api->run(dev, direction, velocity);
448 }
449 
450 /**
451  * @brief Set the callback function to be called when a stepper event occurs
452  *
453  * @param dev pointer to the stepper motor controller instance
454  * @param callback Callback function to be called when a stepper event occurs
455  * passing NULL will disable the callback
456  * @param user_data User data to be passed to the callback function
457  *
458  * @retval -ENOSYS If not implemented by device driver
459  * @retval 0 Success
460  */
461 __syscall int stepper_set_event_callback(const struct device *dev,
462 					 stepper_event_callback_t callback, void *user_data);
463 
z_impl_stepper_set_event_callback(const struct device * dev,stepper_event_callback_t callback,void * user_data)464 static inline int z_impl_stepper_set_event_callback(const struct device *dev,
465 						    stepper_event_callback_t callback,
466 						    void *user_data)
467 {
468 	const struct stepper_driver_api *api = (const struct stepper_driver_api *)dev->api;
469 
470 	if (api->set_event_callback == NULL) {
471 		return -ENOSYS;
472 	}
473 	return api->set_event_callback(dev, callback, user_data);
474 }
475 
476 /**
477  * @}
478  */
479 
480 #ifdef __cplusplus
481 }
482 #endif
483 
484 #include <zephyr/syscalls/stepper.h>
485 
486 #endif /* ZEPHYR_INCLUDE_DRIVERS_STEPPER_H_ */
487