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