1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2025 Jilay Sandeep Pandya.
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #include <zephyr/device.h>
7 #include <zephyr/drivers/gpio.h>
8 #include <zephyr/drivers/stepper.h>
9 #include <zephyr/input/input.h>
10 #include <zephyr/kernel.h>
11 
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(stepper_generic, CONFIG_STEPPER_LOG_LEVEL);
14 
15 static const struct device *stepper = DEVICE_DT_GET(DT_ALIAS(stepper));
16 static const struct device *stepper_drv = DEVICE_DT_GET(DT_ALIAS(stepper_drv));
17 
18 enum stepper_mode {
19 	STEPPER_MODE_ENABLE,
20 	STEPPER_MODE_PING_PONG_RELATIVE,
21 	STEPPER_MODE_PING_PONG_ABSOLUTE,
22 	STEPPER_MODE_ROTATE_CW,
23 	STEPPER_MODE_ROTATE_CCW,
24 	STEPPER_MODE_STOP,
25 	STEPPER_MODE_DISABLE,
26 };
27 
28 static atomic_t stepper_mode = ATOMIC_INIT(STEPPER_MODE_DISABLE);
29 
30 static int32_t ping_pong_target_position = CONFIG_STEPS_PER_REV * CONFIG_PING_PONG_N_REV *
31 					   DT_PROP_OR(DT_ALIAS(stepper_drv), micro_step_res, 1);
32 
33 static K_SEM_DEFINE(stepper_generic_sem, 0, 1);
34 
stepper_callback(const struct device * dev,const enum stepper_event event,void * user_data)35 static void stepper_callback(const struct device *dev, const enum stepper_event event,
36 			     void *user_data)
37 {
38 	switch (event) {
39 	case STEPPER_EVENT_STEPS_COMPLETED:
40 		k_sem_give(&stepper_generic_sem);
41 		break;
42 	default:
43 		break;
44 	}
45 }
46 
button_pressed(struct input_event * event,void * user_data)47 static void button_pressed(struct input_event *event, void *user_data)
48 {
49 	ARG_UNUSED(user_data);
50 
51 	if (event->value == 0 && event->type == INPUT_EV_KEY) {
52 		return;
53 	}
54 	enum stepper_mode mode = atomic_get(&stepper_mode);
55 
56 	if (mode == STEPPER_MODE_DISABLE) {
57 		atomic_set(&stepper_mode, STEPPER_MODE_ENABLE);
58 	} else {
59 		atomic_inc(&stepper_mode);
60 	}
61 	k_sem_give(&stepper_generic_sem);
62 }
63 
64 INPUT_CALLBACK_DEFINE(NULL, button_pressed, NULL);
65 
main(void)66 int main(void)
67 {
68 	LOG_INF("Starting generic stepper sample");
69 	if (!device_is_ready(stepper)) {
70 		LOG_ERR("Device %s is not ready", stepper->name);
71 		return -ENODEV;
72 	}
73 	LOG_DBG("stepper is %p, name is %s", stepper, stepper->name);
74 
75 	stepper_set_event_callback(stepper, stepper_callback, NULL);
76 	stepper_set_reference_position(stepper, 0);
77 	stepper_set_microstep_interval(stepper, CONFIG_STEP_INTERVAL_NS);
78 
79 	for (;;) {
80 		k_sem_take(&stepper_generic_sem, K_FOREVER);
81 		switch (atomic_get(&stepper_mode)) {
82 		case STEPPER_MODE_ENABLE:
83 			stepper_drv_enable(stepper_drv);
84 			LOG_INF("mode: enable");
85 			break;
86 		case STEPPER_MODE_PING_PONG_RELATIVE:
87 			ping_pong_target_position *= -1;
88 			stepper_move_by(stepper, ping_pong_target_position);
89 			LOG_INF("mode: ping pong relative");
90 			break;
91 		case STEPPER_MODE_PING_PONG_ABSOLUTE:
92 			ping_pong_target_position *= -1;
93 			stepper_move_to(stepper, ping_pong_target_position);
94 			LOG_INF("mode: ping pong absolute");
95 			break;
96 		case STEPPER_MODE_ROTATE_CW:
97 			stepper_run(stepper, STEPPER_DIRECTION_POSITIVE);
98 			LOG_INF("mode: rotate cw");
99 			break;
100 		case STEPPER_MODE_ROTATE_CCW:
101 			stepper_run(stepper, STEPPER_DIRECTION_NEGATIVE);
102 			LOG_INF("mode: rotate ccw");
103 			break;
104 		case STEPPER_MODE_STOP:
105 			stepper_stop(stepper);
106 			LOG_INF("mode: stop");
107 			break;
108 		case STEPPER_MODE_DISABLE:
109 			stepper_drv_disable(stepper_drv);
110 			LOG_INF("mode: disable");
111 			break;
112 		default:
113 			break;
114 		}
115 	}
116 	return 0;
117 }
118 
monitor_thread(void)119 static void monitor_thread(void)
120 {
121 	for (;;) {
122 		int32_t actual_position;
123 
124 		stepper_get_actual_position(stepper, &actual_position);
125 		LOG_DBG("Actual position: %d", actual_position);
126 		k_sleep(K_MSEC(CONFIG_MONITOR_THREAD_TIMEOUT_MS));
127 	}
128 }
129 
130 K_THREAD_DEFINE(monitor_tid, CONFIG_MONITOR_THREAD_STACK_SIZE, monitor_thread, NULL, NULL, NULL, 5,
131 		0, 0);
132