Skip to content

Commit cf3dddf

Browse files
jilaypandyajhedberg
authored andcommitted
drivers: stepper: step_dir: fix 87698
During testing with teensy 4.0 it was discoverd that toggling at high frequencies led to missed steps. As per the datasheets of step-dir drivers an active edge needs to be maintained for a certain timerperiod, for a step to be executed. Instead of toggling pin twice instantaneously, the current fix halves the step period and the step-pin is toggled on the timeout of the respective timing source. rework stepper stepper stop set step pin to low if the driver does not support dual edge and increment/decrement the actual position by one Signed-off-by: Jilay Pandya <[email protected]>
1 parent 5cb7e92 commit cf3dddf

File tree

9 files changed

+111
-42
lines changed

9 files changed

+111
-42
lines changed

drivers/stepper/step_dir/step_dir_stepper_common.c

Lines changed: 77 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,6 @@
88
#include <zephyr/logging/log.h>
99
LOG_MODULE_REGISTER(step_dir_stepper, CONFIG_STEPPER_LOG_LEVEL);
1010

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-
int ret;
15-
16-
ret = gpio_pin_toggle_dt(&config->step_pin);
17-
if (ret < 0) {
18-
LOG_ERR("Failed to toggle step pin: %d", ret);
19-
return ret;
20-
}
21-
22-
if (!config->dual_edge) {
23-
ret = gpio_pin_toggle_dt(&config->step_pin);
24-
if (ret < 0) {
25-
LOG_ERR("Failed to toggle step pin: %d", ret);
26-
return ret;
27-
}
28-
}
29-
30-
return 0;
31-
}
32-
3311
static inline int update_dir_pin(const struct device *dev)
3412
{
3513
const struct step_dir_stepper_common_config *config = dev->config;
@@ -111,8 +89,38 @@ static void stepper_work_event_handler(struct k_work *work)
11189
}
11290
#endif /* CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS */
11391

114-
static void update_remaining_steps(struct step_dir_stepper_common_data *data)
92+
static int start_stepping(const struct device *dev)
11593
{
94+
const struct step_dir_stepper_common_config *config = dev->config;
95+
struct step_dir_stepper_common_data *data = dev->data;
96+
int ret;
97+
98+
ret = config->timing_source->update(dev, config->dual_edge
99+
? data->microstep_interval_ns
100+
: data->microstep_interval_ns / 2);
101+
if (ret < 0) {
102+
LOG_ERR("Failed to update timing source: %d", ret);
103+
return ret;
104+
}
105+
106+
ret = config->timing_source->start(dev);
107+
if (ret < 0) {
108+
LOG_ERR("Failed to start timing source: %d", ret);
109+
return ret;
110+
}
111+
112+
stepper_handle_timing_signal(dev);
113+
return ret;
114+
}
115+
116+
static void update_remaining_steps(const struct device *dev)
117+
{
118+
const struct step_dir_stepper_common_config *config = dev->config;
119+
struct step_dir_stepper_common_data *data = dev->data;
120+
121+
if (data->step_high && !config->dual_edge) {
122+
return;
123+
}
116124
if (atomic_get(&data->step_count) > 0) {
117125
atomic_dec(&data->step_count);
118126
} else if (atomic_get(&data->step_count) < 0) {
@@ -138,7 +146,7 @@ static void position_mode_task(const struct device *dev)
138146
struct step_dir_stepper_common_data *data = dev->data;
139147
const struct step_dir_stepper_common_config *config = dev->config;
140148

141-
update_remaining_steps(dev->data);
149+
update_remaining_steps(dev);
142150

143151
if (config->timing_source->needs_reschedule(dev) && atomic_get(&data->step_count) != 0) {
144152
(void)config->timing_source->start(dev);
@@ -159,13 +167,24 @@ static void velocity_mode_task(const struct device *dev)
159167

160168
void stepper_handle_timing_signal(const struct device *dev)
161169
{
170+
const struct step_dir_stepper_common_config *config = dev->config;
162171
struct step_dir_stepper_common_data *data = dev->data;
172+
int ret;
163173

164-
(void)step_dir_stepper_perform_step(dev);
165-
if (data->direction == STEPPER_DIRECTION_POSITIVE) {
166-
atomic_inc(&data->actual_position);
167-
} else {
168-
atomic_dec(&data->actual_position);
174+
atomic_val_t step_pin_status = atomic_xor(&data->step_high, 1) ^ 1;
175+
176+
ret = gpio_pin_set_dt(&config->step_pin, atomic_get(&step_pin_status));
177+
if (ret < 0) {
178+
LOG_ERR("Failed to set step pin: %d", ret);
179+
return;
180+
}
181+
182+
if (!atomic_get(&step_pin_status) || config->dual_edge) {
183+
if (data->direction == STEPPER_DIRECTION_POSITIVE) {
184+
atomic_inc(&data->actual_position);
185+
} else {
186+
atomic_dec(&data->actual_position);
187+
}
169188
}
170189

171190
switch (data->run_mode) {
@@ -218,7 +237,6 @@ int step_dir_stepper_common_init(const struct device *dev)
218237
CONFIG_STEPPER_STEP_DIR_EVENT_QUEUE_LEN);
219238
k_work_init(&data->event_callback_work, stepper_work_event_handler);
220239
#endif /* CONFIG_STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS */
221-
222240
return 0;
223241
}
224242

@@ -247,8 +265,8 @@ int step_dir_stepper_common_move_by(const struct device *dev, const int32_t micr
247265
if (ret < 0) {
248266
K_SPINLOCK_BREAK;
249267
}
250-
config->timing_source->update(dev, data->microstep_interval_ns);
251-
config->timing_source->start(dev);
268+
269+
ret = start_stepping(dev);
252270
}
253271

254272
return ret;
@@ -265,9 +283,21 @@ int step_dir_stepper_common_set_microstep_interval(const struct device *dev,
265283
return -EINVAL;
266284
}
267285

286+
if (config->dual_edge && (microstep_interval_ns < config->step_width_ns)) {
287+
LOG_ERR("Step interval too small for configured step width");
288+
return -EINVAL;
289+
}
290+
291+
if (microstep_interval_ns < 2 * config->step_width_ns) {
292+
LOG_ERR("Step interval too small for configured step width");
293+
return -EINVAL;
294+
}
295+
268296
K_SPINLOCK(&data->lock) {
269297
data->microstep_interval_ns = microstep_interval_ns;
270-
config->timing_source->update(dev, microstep_interval_ns);
298+
config->timing_source->update(dev, config->dual_edge
299+
? data->microstep_interval_ns
300+
: data->microstep_interval_ns / 2);
271301
}
272302

273303
return 0;
@@ -315,7 +345,6 @@ int step_dir_stepper_common_is_moving(const struct device *dev, bool *is_moving)
315345
int step_dir_stepper_common_run(const struct device *dev, const enum stepper_direction direction)
316346
{
317347
struct step_dir_stepper_common_data *data = dev->data;
318-
const struct step_dir_stepper_common_config *config = dev->config;
319348
int ret;
320349

321350
K_SPINLOCK(&data->lock) {
@@ -325,8 +354,8 @@ int step_dir_stepper_common_run(const struct device *dev, const enum stepper_dir
325354
if (ret < 0) {
326355
K_SPINLOCK_BREAK;
327356
}
328-
config->timing_source->update(dev, data->microstep_interval_ns);
329-
config->timing_source->start(dev);
357+
358+
ret = start_stepping(dev);
330359
}
331360

332361
return ret;
@@ -335,6 +364,7 @@ int step_dir_stepper_common_run(const struct device *dev, const enum stepper_dir
335364
int step_dir_stepper_common_stop(const struct device *dev)
336365
{
337366
const struct step_dir_stepper_common_config *config = dev->config;
367+
struct step_dir_stepper_common_data *data = dev->data;
338368
int ret;
339369

340370
ret = config->timing_source->stop(dev);
@@ -343,7 +373,18 @@ int step_dir_stepper_common_stop(const struct device *dev)
343373
return ret;
344374
}
345375

376+
if (!config->dual_edge && atomic_cas(&data->step_high, 1, 0)) {
377+
gpio_pin_set_dt(&config->step_pin, 0);
378+
/* If we are in the high state, we need to account for that step */
379+
if (data->direction == STEPPER_DIRECTION_POSITIVE) {
380+
atomic_inc(&data->actual_position);
381+
} else {
382+
atomic_dec(&data->actual_position);
383+
}
384+
}
385+
346386
stepper_trigger_callback(dev, STEPPER_EVENT_STOPPED);
387+
347388
return 0;
348389
}
349390

drivers/stepper/step_dir/step_dir_stepper_common.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
struct step_dir_stepper_common_config {
3030
const struct gpio_dt_spec step_pin;
3131
const struct gpio_dt_spec dir_pin;
32+
uint32_t step_width_ns;
3233
bool dual_edge;
3334
const struct stepper_timing_source_api *timing_source;
3435
const struct device *counter;
@@ -47,6 +48,7 @@ struct step_dir_stepper_common_config {
4748
.step_pin = GPIO_DT_SPEC_GET(node_id, step_gpios), \
4849
.dir_pin = GPIO_DT_SPEC_GET(node_id, dir_gpios), \
4950
.dual_edge = DT_PROP_OR(node_id, dual_edge_step, false), \
51+
.step_width_ns = DT_PROP(node_id, step_width_ns), \
5052
.counter = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(node_id, counter)), \
5153
.invert_direction = DT_PROP(node_id, invert_direction), \
5254
.timing_source = COND_CODE_1(DT_NODE_HAS_PROP(node_id, counter), \
@@ -78,7 +80,7 @@ struct step_dir_stepper_common_data {
7880
void *event_cb_user_data;
7981

8082
struct k_work_delayable stepper_dwork;
81-
83+
atomic_t step_high;
8284
#ifdef CONFIG_STEP_DIR_STEPPER_COUNTER_TIMING
8385
struct counter_top_cfg counter_top_cfg;
8486
bool counter_running;

dts/bindings/stepper/adi/adi,tmc2209.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,12 @@ compatible: "adi,tmc2209"
1919

2020
include:
2121
- name: stepper-controller.yaml
22+
- name: step-dir-timing.yaml
2223

2324
properties:
25+
step-width-ns:
26+
default: 100
27+
2428
msx-gpios:
2529
type: phandle-array
2630
description: |

dts/bindings/stepper/allegro/allegro,a4979.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,12 @@ compatible: "allegro,a4979"
2525

2626
include:
2727
- name: stepper-controller.yaml
28+
- name: step-dir-timing.yaml
2829

2930
properties:
31+
step-width-ns:
32+
default: 1000
33+
3034
m0-gpios:
3135
required: true
3236
type: phandle-array
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 Jilay Sandeep Pandya
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: Step/Dir Control Signal Timing
5+
6+
properties:
7+
step-width-ns:
8+
type: int
9+
description: |
10+
Minimum pulse width in nanoseconds for the step signal.

dts/bindings/stepper/ti/ti,drv84xx.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,12 @@ compatible: "ti,drv84xx"
3131

3232
include:
3333
- name: stepper-controller.yaml
34+
- name: step-dir-timing.yaml
3435

3536
properties:
37+
step-width-ns:
38+
default: 970
39+
3640
fault-gpios:
3741
type: phandle-array
3842
description: Fault pin.

include/zephyr/drivers/stepper.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,9 @@ static inline int z_impl_stepper_set_reference_position(const struct device *dev
354354
}
355355

356356
/**
357-
* @brief Get the actual a.k.a reference position of the stepper
357+
* @brief Get the actual step count for a given stepper.
358+
* @note This function does not guarantee that the returned position is the exact current
359+
* position. For precise positioning, encoders should be used in addition to the stepper driver.
358360
*
359361
* @param dev pointer to the stepper driver instance
360362
* @param value The actual position to get in micro-steps
@@ -432,7 +434,7 @@ static inline int z_impl_stepper_set_microstep_interval(const struct device *dev
432434
/**
433435
* @brief Set the micro-steps to be moved from the current position i.e. relative movement
434436
*
435-
* @details The stepper will move by the given number of micro-steps from the current position.
437+
* @note The stepper will move by the given number of micro-steps from the current position.
436438
* This function is non-blocking.
437439
*
438440
* @param dev pointer to the stepper driver instance
@@ -453,7 +455,7 @@ static inline int z_impl_stepper_move_by(const struct device *dev, const int32_t
453455
/**
454456
* @brief Set the absolute target position of the stepper
455457
*
456-
* @details The stepper will move to the given micro-steps position from the reference position.
458+
* @note The stepper will move to the given micro-steps position from the reference position.
457459
* This function is non-blocking.
458460
*
459461
* @param dev pointer to the stepper driver instance
@@ -478,7 +480,7 @@ static inline int z_impl_stepper_move_to(const struct device *dev, const int32_t
478480
/**
479481
* @brief Run the stepper with a given step interval in a given direction
480482
*
481-
* @details The stepper shall be set into motion and run continuously until
483+
* @note The stepper shall be set into motion and run continuously until
482484
* stalled or stopped using some other command, for instance, stepper_stop(). This
483485
* function is non-blocking.
484486
*
@@ -504,7 +506,7 @@ static inline int z_impl_stepper_run(const struct device *dev,
504506

505507
/**
506508
* @brief Stop the stepper
507-
* @details Cancel all active movements.
509+
* @note Cancel all active movements.
508510
*
509511
* @param dev pointer to the stepper driver instance
510512
*

tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209.overlay

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@
2121
en-gpios = <&gpio2 1 0>;
2222
msx-gpios = <&gpio3 0 0>, <&gpio4 1 0>;
2323
counter = <&counter0>;
24+
dual-edge-step;
2425
};
2526
};

tests/drivers/stepper/stepper_api/boards/native_sim_adi_tmc2209_work_q.overlay

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@
2020
step-gpios = <&gpio1 1 0>;
2121
en-gpios = <&gpio2 1 0>;
2222
msx-gpios = <&gpio3 0 0>, <&gpio4 1 0>;
23+
dual-edge-step;
2324
};
2425
};

0 commit comments

Comments
 (0)