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