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