12
12
#include <zephyr/drivers/stepper.h>
13
13
#include <zephyr/sys/__assert.h>
14
14
15
+ #ifdef CONFIG_STEPPER_RAMP
16
+ #include "ramp/ramp.h"
17
+ #endif
18
+
15
19
#include <zephyr/logging/log.h>
16
20
LOG_MODULE_REGISTER (gpio_stepper_motor_controller , CONFIG_STEPPER_LOG_LEVEL );
17
21
@@ -26,6 +30,9 @@ static const uint8_t
26
30
struct gpio_stepper_config {
27
31
const struct gpio_dt_spec * control_pins ;
28
32
bool invert_direction ;
33
+ #ifdef CONFIG_STEPPER_RAMP
34
+ const struct stepper_ramp_config ramp_config ;
35
+ #endif
29
36
};
30
37
31
38
struct gpio_stepper_data {
@@ -42,6 +49,9 @@ struct gpio_stepper_data {
42
49
bool is_enabled ;
43
50
stepper_event_callback_t callback ;
44
51
void * event_cb_user_data ;
52
+ #ifdef CONFIG_STEPPER_RAMP
53
+ struct stepper_ramp_common ramp_common ;
54
+ #endif
45
55
};
46
56
47
57
static int stepper_motor_set_coil_charge (const struct device * dev )
@@ -98,6 +108,24 @@ static void update_coil_charge(const struct device *dev)
98
108
const struct gpio_stepper_config * config = dev -> config ;
99
109
struct gpio_stepper_data * data = dev -> data ;
100
110
111
+ #ifdef CONFIG_STEPPER_RAMP
112
+ if (data -> ramp_common .ramp_data .current_ramp_state ==
113
+ STEPPER_RAMP_STATE_FORCED_DECELERATION ) {
114
+ if (data -> direction == STEPPER_DIRECTION_NEGATIVE ) {
115
+ config -> invert_direction ? decrement_coil_charge (dev )
116
+ : increment_coil_charge (dev );
117
+ data -> actual_position ++ ;
118
+ return ;
119
+ }
120
+ if (data -> direction == STEPPER_DIRECTION_POSITIVE ) {
121
+ config -> invert_direction ? increment_coil_charge (dev )
122
+ : decrement_coil_charge (dev );
123
+ data -> actual_position -- ;
124
+ return ;
125
+ }
126
+ }
127
+ #endif
128
+
101
129
if (data -> direction == STEPPER_DIRECTION_POSITIVE ) {
102
130
config -> invert_direction ? decrement_coil_charge (dev ) : increment_coil_charge (dev );
103
131
data -> actual_position ++ ;
@@ -109,6 +137,24 @@ static void update_coil_charge(const struct device *dev)
109
137
110
138
static void update_remaining_steps (struct gpio_stepper_data * data )
111
139
{
140
+ #ifdef CONFIG_STEPPER_RAMP
141
+ if (data -> step_count != 0 ) {
142
+ data -> delay_in_ns = trapezoidal_ramp_api .get_next_step_interval (& data -> ramp_common ,
143
+ data -> delay_in_ns );
144
+
145
+ if (data -> ramp_common .ramp_data .current_ramp_state ==
146
+ STEPPER_RAMP_STATE_FORCED_DECELERATION ) {
147
+ if (data -> step_count > 0 ) {
148
+ data -> step_count ++ ;
149
+ } else {
150
+ data -> step_count -- ;
151
+ }
152
+ (void )k_work_reschedule (& data -> stepper_dwork , K_NSEC (data -> delay_in_ns ));
153
+ }
154
+ } else {
155
+ data -> ramp_common .ramp_data .current_ramp_state = STEPPER_RAMP_STATE_NOT_MOVING ;
156
+ }
157
+ #endif
112
158
if (data -> step_count > 0 ) {
113
159
data -> step_count -- ;
114
160
(void )k_work_reschedule (& data -> stepper_dwork , K_NSEC (data -> delay_in_ns ));
@@ -124,9 +170,10 @@ static void update_remaining_steps(struct gpio_stepper_data *data)
124
170
}
125
171
}
126
172
127
- static void update_direction_from_step_count (const struct device * dev )
173
+ static bool update_direction_from_step_count (const struct device * dev )
128
174
{
129
175
struct gpio_stepper_data * data = dev -> data ;
176
+ enum stepper_direction direction = data -> direction ;
130
177
131
178
if (data -> step_count > 0 ) {
132
179
data -> direction = STEPPER_DIRECTION_POSITIVE ;
@@ -135,6 +182,10 @@ static void update_direction_from_step_count(const struct device *dev)
135
182
} else {
136
183
LOG_ERR ("Step count is zero" );
137
184
}
185
+ if (data -> direction != direction ) {
186
+ return true;
187
+ }
188
+ return false;
138
189
}
139
190
140
191
static void position_mode_task (const struct device * dev )
@@ -178,6 +229,23 @@ static void stepper_work_step_handler(struct k_work *work)
178
229
}
179
230
}
180
231
232
+ static bool is_step_timing_valid (const struct device * dev )
233
+ {
234
+ struct gpio_stepper_data * data = dev -> data ;
235
+ #ifdef CONFIG_STEPPER_RAMP
236
+
237
+ if (data -> ramp_common .ramp_profile .max_velocity > 0 ) {
238
+ return true;
239
+ }
240
+ return false;
241
+ #else
242
+ if (data -> delay_in_ns > 0 ) {
243
+ return true;
244
+ }
245
+ return false;
246
+ #endif
247
+ }
248
+
181
249
static int gpio_stepper_move_by (const struct device * dev , int32_t micro_steps )
182
250
{
183
251
struct gpio_stepper_data * data = dev -> data ;
@@ -187,14 +255,29 @@ static int gpio_stepper_move_by(const struct device *dev, int32_t micro_steps)
187
255
return - ECANCELED ;
188
256
}
189
257
190
- if (data -> delay_in_ns == 0 ) {
191
- LOG_ERR ("Step interval not set or invalid step interval set" );
258
+ if (!is_step_timing_valid (dev )) {
192
259
return - EINVAL ;
193
260
}
261
+
262
+ if (micro_steps == 0 ) {
263
+ LOG_WRN ("Step count is zero" );
264
+ return 0 ;
265
+ }
266
+
194
267
K_SPINLOCK (& data -> lock ) {
195
268
data -> run_mode = STEPPER_RUN_MODE_POSITION ;
196
269
data -> step_count = micro_steps ;
197
- update_direction_from_step_count (dev );
270
+ bool is_dir_changed = update_direction_from_step_count (dev );
271
+ #ifdef CONFIG_STEPPER_RAMP
272
+ const struct gpio_stepper_config * config = dev -> config ;
273
+ uint32_t steps_to_move = abs (micro_steps );
274
+
275
+ trapezoidal_ramp_api .reset_ramp_data (& config -> ramp_config , & data -> ramp_common ,
276
+ & data -> delay_in_ns , is_dir_changed ,
277
+ steps_to_move );
278
+ #else
279
+ ARG_UNUSED (is_dir_changed );
280
+ #endif
198
281
(void )k_work_reschedule (& data -> stepper_dwork , K_NO_WAIT );
199
282
}
200
283
return 0 ;
@@ -229,14 +312,24 @@ static int gpio_stepper_move_to(const struct device *dev, int32_t micro_steps)
229
312
return - ECANCELED ;
230
313
}
231
314
232
- if (data -> delay_in_ns == 0 ) {
233
- LOG_ERR ("Step interval not set or invalid step interval set" );
315
+ if (!is_step_timing_valid (dev )) {
234
316
return - EINVAL ;
235
317
}
318
+
236
319
K_SPINLOCK (& data -> lock ) {
237
320
data -> run_mode = STEPPER_RUN_MODE_POSITION ;
238
321
data -> step_count = micro_steps - data -> actual_position ;
239
- update_direction_from_step_count (dev );
322
+ bool is_dir_changed = update_direction_from_step_count (dev );
323
+ #ifdef CONFIG_STEPPER_RAMP
324
+ const struct gpio_stepper_config * config = dev -> config ;
325
+ uint32_t steps_to_move = abs (micro_steps - data -> actual_position );
326
+
327
+ trapezoidal_ramp_api .reset_ramp_data (& config -> ramp_config , & data -> ramp_common ,
328
+ & data -> delay_in_ns , is_dir_changed ,
329
+ steps_to_move );
330
+ #else
331
+ ARG_UNUSED (is_dir_changed );
332
+ #endif
240
333
(void )k_work_reschedule (& data -> stepper_dwork , K_NO_WAIT );
241
334
}
242
335
return 0 ;
@@ -268,6 +361,23 @@ static int gpio_stepper_set_microstep_interval(const struct device *dev,
268
361
return 0 ;
269
362
}
270
363
364
+ #ifdef CONFIG_STEPPER_RAMP
365
+
366
+ static int gpio_stepper_set_ramp_profile (const struct device * dev ,
367
+ const struct stepper_ramp_profile * const ramp_profile )
368
+ {
369
+ struct gpio_stepper_data * data = dev -> data ;
370
+
371
+ K_SPINLOCK (& data -> lock ) {
372
+ data -> ramp_common .ramp_profile .acceleration = ramp_profile -> acceleration ;
373
+ data -> ramp_common .ramp_profile .max_velocity = ramp_profile -> max_velocity ;
374
+ data -> ramp_common .ramp_profile .deceleration = ramp_profile -> deceleration ;
375
+ }
376
+ return 0 ;
377
+ }
378
+
379
+ #endif
380
+
271
381
static int gpio_stepper_run (const struct device * dev , const enum stepper_direction direction )
272
382
{
273
383
struct gpio_stepper_data * data = dev -> data ;
@@ -350,6 +460,9 @@ static int gpio_stepper_disable(const struct device *dev)
350
460
int err ;
351
461
352
462
K_SPINLOCK (& data -> lock ) {
463
+ #ifdef CONFIG_STEPPER_RAMP
464
+ data -> ramp_common .ramp_data .current_ramp_state = STEPPER_RAMP_STATE_NOT_MOVING ;
465
+ #endif
353
466
(void )k_work_cancel_delayable (& data -> stepper_dwork );
354
467
err = energize_coils (dev , false);
355
468
if (err == 0 ) {
@@ -385,6 +498,7 @@ static int gpio_stepper_init(const struct device *dev)
385
498
for (uint8_t n_pin = 0 ; n_pin < NUM_CONTROL_PINS ; n_pin ++ ) {
386
499
(void )gpio_pin_configure_dt (& config -> control_pins [n_pin ], GPIO_OUTPUT_INACTIVE );
387
500
}
501
+
388
502
k_work_init_delayable (& data -> stepper_dwork , stepper_work_step_handler );
389
503
return 0 ;
390
504
}
@@ -403,20 +517,29 @@ static DEVICE_API(stepper, gpio_stepper_api) = {
403
517
.run = gpio_stepper_run ,
404
518
.stop = gpio_stepper_stop ,
405
519
.is_moving = gpio_stepper_is_moving ,
520
+ IF_ENABLED (CONFIG_STEPPER_RAMP , (.set_ramp_profile = gpio_stepper_set_ramp_profile ,))
521
+
406
522
};
407
523
408
524
#define GPIO_STEPPER_DEFINE (inst ) \
409
525
static const struct gpio_dt_spec gpio_stepper_motor_control_pins_##inst[] = { \
410
526
DT_INST_FOREACH_PROP_ELEM_SEP(inst, gpios, GPIO_DT_SPEC_GET_BY_IDX, (,)), \
411
527
}; \
412
528
BUILD_ASSERT(ARRAY_SIZE(gpio_stepper_motor_control_pins_##inst) == 4, \
413
- "gpio_stepper_controller driver currently supports only 4 wire configuration"); \
529
+ "gpio_stepper_controller driver currently supports only 4 wire configuration"); \
414
530
static const struct gpio_stepper_config gpio_stepper_config_##inst = { \
415
531
.invert_direction = DT_INST_PROP(inst, invert_direction), \
416
- .control_pins = gpio_stepper_motor_control_pins_##inst}; \
532
+ .control_pins = gpio_stepper_motor_control_pins_##inst, \
533
+ IF_ENABLED(CONFIG_STEPPER_RAMP, \
534
+ (.ramp_config.forced_deceleration_steps = DT_INST_PROP(inst, forced_decel_steps))) }; \
417
535
static struct gpio_stepper_data gpio_stepper_data_##inst = { \
418
536
.step_gap = MAX_MICRO_STEP_RES >> (DT_INST_PROP(inst, micro_step_res) - 1), \
419
- }; \
537
+ IF_ENABLED(CONFIG_STEPPER_RAMP, \
538
+ (.ramp_common.ramp_data.ramp_stop_step_interval_threshold_in_ns = \
539
+ DT_INST_PROP(inst, ramp_stop_step_interval), \
540
+ .ramp_common.ramp_profile.acceleration = DT_INST_PROP(inst, acceleration), \
541
+ .ramp_common.ramp_profile.deceleration = DT_INST_PROP(inst, deceleration), \
542
+ .ramp_common.ramp_profile.max_velocity = DT_INST_PROP(inst, max_speed),)) }; \
420
543
BUILD_ASSERT(DT_INST_PROP(inst, micro_step_res) <= STEPPER_MICRO_STEP_2, \
421
544
"gpio_stepper_controller driver supports up to 2 micro steps"); \
422
545
DEVICE_DT_INST_DEFINE(inst, gpio_stepper_init, NULL, &gpio_stepper_data_##inst, \
0 commit comments