Skip to content

Commit ba2aee2

Browse files
faxe1008fabiobaltieri
authored andcommitted
drivers: stepper: Add step direction stepper common binding
Adds a step direction binding that can be used with any stepper that implements said control interface to cut down on boilerplate code. Signed-off-by: Fabian Blatz <[email protected]>
1 parent 51d59fa commit ba2aee2

File tree

5 files changed

+474
-1
lines changed

5 files changed

+474
-1
lines changed

drivers/stepper/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ zephyr_library_property(ALLOW_EMPTY TRUE)
1212

1313
zephyr_library_sources_ifdef(CONFIG_FAKE_STEPPER fake_stepper_controller.c)
1414
zephyr_library_sources_ifdef(CONFIG_GPIO_STEPPER gpio_stepper_controller.c)
15+
zephyr_library_sources_ifdef(CONFIG_STEP_DIR_STEPPER step_dir_stepper_common.c)
1516
zephyr_library_sources_ifdef(CONFIG_STEPPER_SHELL stepper_shell.c)

drivers/stepper/Kconfig

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,17 @@ config STEPPER_SHELL
2424
help
2525
Enable stepper shell for testing.
2626

27+
config STEP_DIR_STEPPER
28+
bool
29+
help
30+
Enable library used for step direction stepper drivers.
31+
2732
comment "Stepper Drivers"
2833

29-
rsource "adi_tmc/Kconfig"
34+
# zephyr-keep-sorted-start
3035
rsource "Kconfig.fake"
3136
rsource "Kconfig.gpio"
37+
rsource "adi_tmc/Kconfig"
38+
# zephyr-keep-sorted-stop
3239

3340
endif
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
/*
2+
* SPDX-FileCopyrightText: Copyright (c) 2024 Fabian Blatz <[email protected]>
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include "step_dir_stepper_common.h"
7+
8+
#include <zephyr/logging/log.h>
9+
LOG_MODULE_REGISTER(step_dir_stepper, CONFIG_STEPPER_LOG_LEVEL);
10+
11+
static inline int step_dir_stepper_perform_step(const struct device *dev)
12+
{
13+
const struct step_dir_stepper_common_config *config = dev->config;
14+
struct step_dir_stepper_common_data *data = dev->data;
15+
int ret;
16+
17+
switch (data->direction) {
18+
case STEPPER_DIRECTION_POSITIVE:
19+
ret = gpio_pin_set_dt(&config->dir_pin, 1);
20+
break;
21+
case STEPPER_DIRECTION_NEGATIVE:
22+
ret = gpio_pin_set_dt(&config->dir_pin, 0);
23+
break;
24+
default:
25+
LOG_ERR("Unsupported direction: %d", data->direction);
26+
return -ENOTSUP;
27+
}
28+
if (ret < 0) {
29+
LOG_ERR("Failed to set direction: %d", ret);
30+
return ret;
31+
}
32+
33+
ret = gpio_pin_toggle_dt(&config->step_pin);
34+
if (ret < 0) {
35+
LOG_ERR("Failed to toggle step pin: %d", ret);
36+
return ret;
37+
}
38+
39+
if (!config->dual_edge) {
40+
ret = gpio_pin_toggle_dt(&config->step_pin);
41+
if (ret < 0) {
42+
LOG_ERR("Failed to toggle step pin: %d", ret);
43+
return ret;
44+
}
45+
}
46+
47+
return 0;
48+
}
49+
50+
static void update_remaining_steps(struct step_dir_stepper_common_data *data)
51+
{
52+
if (data->step_count > 0) {
53+
data->step_count--;
54+
(void)k_work_reschedule(&data->stepper_dwork, K_USEC(data->delay_in_us));
55+
} else if (data->step_count < 0) {
56+
data->step_count++;
57+
(void)k_work_reschedule(&data->stepper_dwork, K_USEC(data->delay_in_us));
58+
} else {
59+
if (!data->callback) {
60+
LOG_WRN_ONCE("No callback set");
61+
return;
62+
}
63+
data->callback(data->dev, STEPPER_EVENT_STEPS_COMPLETED, data->event_cb_user_data);
64+
}
65+
}
66+
67+
static void update_direction_from_step_count(const struct device *dev)
68+
{
69+
struct step_dir_stepper_common_data *data = dev->data;
70+
71+
if (data->step_count > 0) {
72+
data->direction = STEPPER_DIRECTION_POSITIVE;
73+
} else if (data->step_count < 0) {
74+
data->direction = STEPPER_DIRECTION_NEGATIVE;
75+
} else {
76+
LOG_ERR("Step count is zero");
77+
}
78+
}
79+
80+
static void position_mode_task(const struct device *dev)
81+
{
82+
struct step_dir_stepper_common_data *data = dev->data;
83+
84+
if (data->step_count) {
85+
(void)step_dir_stepper_perform_step(dev);
86+
}
87+
update_remaining_steps(dev->data);
88+
}
89+
90+
static void velocity_mode_task(const struct device *dev)
91+
{
92+
struct step_dir_stepper_common_data *data = dev->data;
93+
94+
(void)step_dir_stepper_perform_step(dev);
95+
(void)k_work_reschedule(&data->stepper_dwork, K_USEC(data->delay_in_us));
96+
}
97+
98+
static void stepper_work_step_handler(struct k_work *work)
99+
{
100+
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
101+
struct step_dir_stepper_common_data *data =
102+
CONTAINER_OF(dwork, struct step_dir_stepper_common_data, stepper_dwork);
103+
104+
K_SPINLOCK(&data->lock) {
105+
switch (data->run_mode) {
106+
case STEPPER_RUN_MODE_POSITION:
107+
position_mode_task(data->dev);
108+
break;
109+
case STEPPER_RUN_MODE_VELOCITY:
110+
velocity_mode_task(data->dev);
111+
break;
112+
default:
113+
LOG_WRN("Unsupported run mode: %d", data->run_mode);
114+
break;
115+
}
116+
}
117+
}
118+
119+
int step_dir_stepper_common_init(const struct device *dev)
120+
{
121+
const struct step_dir_stepper_common_config *config = dev->config;
122+
struct step_dir_stepper_common_data *data = dev->data;
123+
int ret;
124+
125+
if (!gpio_is_ready_dt(&config->step_pin) || !gpio_is_ready_dt(&config->dir_pin)) {
126+
LOG_ERR("GPIO pins are not ready");
127+
return -ENODEV;
128+
}
129+
130+
ret = gpio_pin_configure_dt(&config->step_pin, GPIO_OUTPUT);
131+
if (ret < 0) {
132+
LOG_ERR("Failed to configure step pin: %d", ret);
133+
return ret;
134+
}
135+
136+
ret = gpio_pin_configure_dt(&config->dir_pin, GPIO_OUTPUT);
137+
if (ret < 0) {
138+
LOG_ERR("Failed to configure dir pin: %d", ret);
139+
return ret;
140+
}
141+
142+
k_work_init_delayable(&data->stepper_dwork, stepper_work_step_handler);
143+
144+
return 0;
145+
}
146+
147+
int step_dir_stepper_common_move_by(const struct device *dev, const int32_t micro_steps)
148+
{
149+
struct step_dir_stepper_common_data *data = dev->data;
150+
151+
if (data->delay_in_us == 0) {
152+
LOG_ERR("Velocity not set or invalid velocity set");
153+
return -EINVAL;
154+
}
155+
156+
K_SPINLOCK(&data->lock) {
157+
data->run_mode = STEPPER_RUN_MODE_POSITION;
158+
data->step_count = micro_steps;
159+
update_direction_from_step_count(dev);
160+
(void)k_work_reschedule(&data->stepper_dwork, K_NO_WAIT);
161+
}
162+
163+
return 0;
164+
}
165+
166+
int step_dir_stepper_common_set_max_velocity(const struct device *dev, const uint32_t velocity)
167+
{
168+
struct step_dir_stepper_common_data *data = dev->data;
169+
170+
if (velocity == 0) {
171+
LOG_ERR("Velocity cannot be zero");
172+
return -EINVAL;
173+
}
174+
175+
if (velocity > USEC_PER_SEC) {
176+
LOG_ERR("Velocity cannot be greater than %d micro steps per second", USEC_PER_SEC);
177+
return -EINVAL;
178+
}
179+
180+
K_SPINLOCK(&data->lock) {
181+
data->delay_in_us = USEC_PER_SEC / velocity;
182+
}
183+
184+
return 0;
185+
}
186+
187+
int step_dir_stepper_common_set_reference_position(const struct device *dev, const int32_t value)
188+
{
189+
struct step_dir_stepper_common_data *data = dev->data;
190+
191+
K_SPINLOCK(&data->lock) {
192+
data->actual_position = value;
193+
}
194+
195+
return 0;
196+
}
197+
198+
int step_dir_stepper_common_get_actual_position(const struct device *dev, int32_t *value)
199+
{
200+
struct step_dir_stepper_common_data *data = dev->data;
201+
202+
K_SPINLOCK(&data->lock) {
203+
*value = data->actual_position;
204+
}
205+
206+
return 0;
207+
}
208+
209+
int step_dir_stepper_common_move_to(const struct device *dev, const int32_t value)
210+
{
211+
struct step_dir_stepper_common_data *data = dev->data;
212+
213+
if (data->delay_in_us == 0) {
214+
LOG_ERR("Velocity not set or invalid velocity set");
215+
return -EINVAL;
216+
}
217+
218+
K_SPINLOCK(&data->lock) {
219+
data->run_mode = STEPPER_RUN_MODE_POSITION;
220+
data->step_count = value - data->actual_position;
221+
update_direction_from_step_count(dev);
222+
(void)k_work_reschedule(&data->stepper_dwork, K_NO_WAIT);
223+
}
224+
225+
return 0;
226+
}
227+
228+
int step_dir_stepper_common_is_moving(const struct device *dev, bool *is_moving)
229+
{
230+
struct step_dir_stepper_common_data *data = dev->data;
231+
232+
*is_moving = k_work_delayable_is_pending(&data->stepper_dwork);
233+
return 0;
234+
}
235+
236+
int step_dir_stepper_common_run(const struct device *dev, const enum stepper_direction direction,
237+
const uint32_t velocity)
238+
{
239+
struct step_dir_stepper_common_data *data = dev->data;
240+
241+
K_SPINLOCK(&data->lock) {
242+
data->run_mode = STEPPER_RUN_MODE_VELOCITY;
243+
data->direction = direction;
244+
if (value != 0) {
245+
data->delay_in_us = USEC_PER_SEC / velocity;
246+
(void)k_work_reschedule(&data->stepper_dwork, K_NO_WAIT);
247+
} else {
248+
(void)k_work_cancel_delayable(&data->stepper_dwork);
249+
}
250+
}
251+
252+
return 0;
253+
}
254+
255+
int step_dir_stepper_common_set_event_callback(const struct device *dev,
256+
stepper_event_callback_t callback, void *user_data)
257+
{
258+
struct step_dir_stepper_common_data *data = dev->data;
259+
260+
data->callback = callback;
261+
data->event_cb_user_data = user_data;
262+
return 0;
263+
}

0 commit comments

Comments
 (0)