1 /*
2 * Copyright 2024 Navimatix GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/gpio.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/ztest_assert.h>
10 #include <stdbool.h>
11 #include <stdint.h>
12 #include <zephyr/ztest.h>
13 #include <zephyr/drivers/stepper.h>
14
15 struct drv8424_api_fixture {
16 const struct device *dev;
17 stepper_event_callback_t callback;
18 };
19
20 struct k_poll_signal stepper_signal;
21 struct k_poll_event stepper_event;
22
drv8424_api_print_event_callback(const struct device * dev,enum stepper_event event,void * dummy)23 static void drv8424_api_print_event_callback(const struct device *dev, enum stepper_event event,
24 void *dummy)
25 {
26 switch (event) {
27 case STEPPER_EVENT_STEPS_COMPLETED:
28 k_poll_signal_raise(&stepper_signal, STEPPER_EVENT_STEPS_COMPLETED);
29 break;
30 case STEPPER_EVENT_LEFT_END_STOP_DETECTED:
31 k_poll_signal_raise(&stepper_signal, STEPPER_EVENT_LEFT_END_STOP_DETECTED);
32 break;
33 case STEPPER_EVENT_RIGHT_END_STOP_DETECTED:
34 k_poll_signal_raise(&stepper_signal, STEPPER_EVENT_RIGHT_END_STOP_DETECTED);
35 break;
36 case STEPPER_EVENT_STALL_DETECTED:
37 k_poll_signal_raise(&stepper_signal, STEPPER_EVENT_STALL_DETECTED);
38 break;
39 default:
40 break;
41 }
42 }
43
drv8424_api_setup(void)44 static void *drv8424_api_setup(void)
45 {
46 static struct drv8424_api_fixture fixture = {
47 .dev = DEVICE_DT_GET(DT_NODELABEL(drv8424)),
48 .callback = drv8424_api_print_event_callback,
49 };
50
51 k_poll_signal_init(&stepper_signal);
52 k_poll_event_init(&stepper_event, K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY,
53 &stepper_signal);
54
55 zassert_not_null(fixture.dev);
56 return &fixture;
57 }
58
drv8424_api_before(void * f)59 static void drv8424_api_before(void *f)
60 {
61 struct drv8424_api_fixture *fixture = f;
62 (void)stepper_set_reference_position(fixture->dev, 0);
63 (void)stepper_set_micro_step_res(fixture->dev, 1);
64 k_poll_signal_reset(&stepper_signal);
65 }
66
drv8424_api_after(void * f)67 static void drv8424_api_after(void *f)
68 {
69 struct drv8424_api_fixture *fixture = f;
70 (void)stepper_enable(fixture->dev, false);
71 }
72
ZTEST_F(drv8424_api,test_micro_step_res_set)73 ZTEST_F(drv8424_api, test_micro_step_res_set)
74 {
75 (void)stepper_set_micro_step_res(fixture->dev, 4);
76 enum stepper_micro_step_resolution res;
77 (void)stepper_get_micro_step_res(fixture->dev, &res);
78 zassert_equal(res, 4, "Micro step resolution not set correctly, should be %d but is %d", 4,
79 res);
80 }
81
ZTEST_F(drv8424_api,test_actual_position_set)82 ZTEST_F(drv8424_api, test_actual_position_set)
83 {
84 int32_t pos = 100u;
85 (void)stepper_set_reference_position(fixture->dev, pos);
86 (void)stepper_get_actual_position(fixture->dev, &pos);
87 zassert_equal(pos, 100u, "Actual position should be %u but is %u", 100u, pos);
88 }
89
ZTEST_F(drv8424_api,test_is_not_moving_when_disabled)90 ZTEST_F(drv8424_api, test_is_not_moving_when_disabled)
91 {
92 int32_t steps = 100;
93 bool moving = true;
94
95 (void)stepper_enable(fixture->dev, true);
96 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
97 (void)stepper_move_by(fixture->dev, steps);
98 (void)stepper_enable(fixture->dev, false);
99 (void)stepper_is_moving(fixture->dev, &moving);
100 zassert_false(moving, "Driver should not be in state is_moving after being disabled");
101 }
102
ZTEST_F(drv8424_api,test_position_not_updating_when_disabled)103 ZTEST_F(drv8424_api, test_position_not_updating_when_disabled)
104 {
105 int32_t steps = 1000;
106 int32_t position_1 = 0;
107 int32_t position_2 = 0;
108
109 (void)stepper_enable(fixture->dev, true);
110 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
111 (void)stepper_move_by(fixture->dev, steps);
112 (void)stepper_enable(fixture->dev, false);
113 (void)stepper_get_actual_position(fixture->dev, &position_1);
114 k_msleep(100);
115 (void)stepper_get_actual_position(fixture->dev, &position_2);
116 zassert_equal(position_2, position_1,
117 "Actual position should not have changed from %d but is %d", position_1,
118 position_2);
119 }
120
ZTEST_F(drv8424_api,test_is_not_moving_when_reenabled_after_movement)121 ZTEST_F(drv8424_api, test_is_not_moving_when_reenabled_after_movement)
122 {
123 int32_t steps = 1000;
124 bool moving = true;
125
126 (void)stepper_enable(fixture->dev, true);
127 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
128 (void)stepper_move_by(fixture->dev, steps);
129 (void)stepper_enable(fixture->dev, false);
130 (void)k_msleep(100);
131 (void)stepper_enable(fixture->dev, true);
132 (void)k_msleep(100);
133 (void)stepper_is_moving(fixture->dev, &moving);
134 zassert_false(moving, "Driver should not be in state is_moving after being reenabled");
135 }
ZTEST_F(drv8424_api,test_position_not_updating_when_reenabled_after_movement)136 ZTEST_F(drv8424_api, test_position_not_updating_when_reenabled_after_movement)
137 {
138 int32_t steps = 1000;
139 int32_t position_1 = 0;
140 int32_t position_2 = 0;
141
142 (void)stepper_enable(fixture->dev, true);
143 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
144 (void)stepper_move_by(fixture->dev, steps);
145 (void)stepper_enable(fixture->dev, false);
146 (void)stepper_get_actual_position(fixture->dev, &position_1);
147 (void)k_msleep(100);
148 (void)stepper_enable(fixture->dev, true);
149 (void)k_msleep(100);
150 (void)stepper_get_actual_position(fixture->dev, &position_2);
151 zassert_equal(position_2, position_1,
152 "Actual position should not have changed from %d but is %d", position_1,
153 position_2);
154 }
155
ZTEST_F(drv8424_api,test_move_to_positive_direction_movement)156 ZTEST_F(drv8424_api, test_move_to_positive_direction_movement)
157 {
158 int32_t pos = 50;
159
160 (void)stepper_enable(fixture->dev, true);
161 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
162 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
163 (void)stepper_move_to(fixture->dev, pos);
164 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
165 unsigned int signaled;
166 int result;
167
168 k_poll_signal_check(&stepper_signal, &signaled, &result);
169 zassert_equal(signaled, 1, "No event detected");
170 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
171 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
172 (void)stepper_get_actual_position(fixture->dev, &pos);
173 zassert_equal(pos, 50u, "Target position should be %d but is %d", 50u, pos);
174 }
175
ZTEST_F(drv8424_api,test_move_to_negative_direction_movement)176 ZTEST_F(drv8424_api, test_move_to_negative_direction_movement)
177 {
178 int32_t pos = -50;
179
180 (void)stepper_enable(fixture->dev, true);
181 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
182 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
183 (void)stepper_move_to(fixture->dev, pos);
184 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
185 unsigned int signaled;
186 int result;
187
188 k_poll_signal_check(&stepper_signal, &signaled, &result);
189 zassert_equal(signaled, 1, "No event detected");
190 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
191 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
192 (void)stepper_get_actual_position(fixture->dev, &pos);
193 zassert_equal(pos, -50, "Target position should be %d but is %d", -50, pos);
194 }
195
ZTEST_F(drv8424_api,test_move_to_identical_current_and_target_position)196 ZTEST_F(drv8424_api, test_move_to_identical_current_and_target_position)
197 {
198 int32_t pos = 0;
199
200 (void)stepper_enable(fixture->dev, true);
201 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
202 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
203 (void)stepper_move_to(fixture->dev, pos);
204 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
205 unsigned int signaled;
206 int result;
207
208 k_poll_signal_check(&stepper_signal, &signaled, &result);
209 zassert_equal(signaled, 1, "No event detected");
210 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
211 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
212 (void)stepper_get_actual_position(fixture->dev, &pos);
213 zassert_equal(pos, 0, "Target position should not have changed from %d but is %d", 0, pos);
214 }
215
ZTEST_F(drv8424_api,test_move_to_is_moving_true_while_moving)216 ZTEST_F(drv8424_api, test_move_to_is_moving_true_while_moving)
217 {
218 int32_t pos = 50;
219 bool moving = false;
220
221 (void)stepper_enable(fixture->dev, true);
222 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
223 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
224 (void)stepper_move_to(fixture->dev, pos);
225 (void)stepper_is_moving(fixture->dev, &moving);
226 zassert_true(moving, "Driver should be in state is_moving while moving");
227 }
228
ZTEST_F(drv8424_api,test_move_to_is_moving_false_when_completed)229 ZTEST_F(drv8424_api, test_move_to_is_moving_false_when_completed)
230 {
231 int32_t pos = 50;
232 bool moving = false;
233
234 (void)stepper_enable(fixture->dev, true);
235 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
236 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
237 (void)stepper_move_to(fixture->dev, pos);
238 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
239 unsigned int signaled;
240 int result;
241
242 k_poll_signal_check(&stepper_signal, &signaled, &result);
243 zassert_equal(signaled, 1, "No event detected");
244 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
245 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
246 (void)stepper_is_moving(fixture->dev, &moving);
247 zassert_false(moving, "Driver should not be in state is_moving after finishing");
248 }
249
ZTEST_F(drv8424_api,test_move_to_no_movement_when_disabled)250 ZTEST_F(drv8424_api, test_move_to_no_movement_when_disabled)
251 {
252 int32_t pos = 50;
253 int32_t curr_pos = 50;
254 int32_t ret = 0;
255
256 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
257 (void)stepper_enable(fixture->dev, false);
258
259 ret = stepper_move_to(fixture->dev, pos);
260 zassert_equal(ret, -ECANCELED, "Move_to should fail with error code %d but returned %d",
261 -ECANCELED, ret);
262 (void)stepper_get_actual_position(fixture->dev, &curr_pos);
263 zassert_equal(curr_pos, 0, "Current position should not have changed from %d but is %d", 0,
264 curr_pos);
265 }
266
ZTEST_F(drv8424_api,test_move_by_positive_step_count)267 ZTEST_F(drv8424_api, test_move_by_positive_step_count)
268 {
269 int32_t steps = 50;
270
271 (void)stepper_enable(fixture->dev, true);
272 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
273 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
274 (void)stepper_move_by(fixture->dev, steps);
275 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
276 unsigned int signaled;
277 int result;
278
279 k_poll_signal_check(&stepper_signal, &signaled, &result);
280 zassert_equal(signaled, 1, "No event detected");
281 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
282 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
283 (void)stepper_get_actual_position(fixture->dev, &steps);
284 zassert_equal(steps, 50u, "Target position should be %d but is %d", 50u, steps);
285 }
286
ZTEST_F(drv8424_api,test_move_by_negative_step_count)287 ZTEST_F(drv8424_api, test_move_by_negative_step_count)
288 {
289 int32_t steps = -50;
290
291 (void)stepper_enable(fixture->dev, true);
292 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
293 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
294 (void)stepper_move_by(fixture->dev, steps);
295 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
296 unsigned int signaled;
297 int result;
298
299 k_poll_signal_check(&stepper_signal, &signaled, &result);
300 zassert_equal(signaled, 1, "No event detected");
301 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
302 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
303 (void)stepper_get_actual_position(fixture->dev, &steps);
304 zassert_equal(steps, -50, "Target position should be %d but is %d", -50, steps);
305 }
306
ZTEST_F(drv8424_api,test_move_by_zero_steps_no_movement)307 ZTEST_F(drv8424_api, test_move_by_zero_steps_no_movement)
308 {
309 int32_t steps = 0;
310
311 (void)stepper_enable(fixture->dev, true);
312 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
313 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
314 (void)stepper_move_by(fixture->dev, steps);
315 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
316 unsigned int signaled;
317 int result;
318
319 k_poll_signal_check(&stepper_signal, &signaled, &result);
320 zassert_equal(signaled, 1, "No event detected");
321 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
322 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
323 (void)stepper_get_actual_position(fixture->dev, &steps);
324 zassert_equal(steps, 0, "Target position should be %d but is %d", 0, steps);
325 }
326
ZTEST_F(drv8424_api,test_move_by_zero_step_interval)327 ZTEST_F(drv8424_api, test_move_by_zero_step_interval)
328 {
329 int32_t steps = 100;
330 int32_t ret = 0;
331 int32_t pos = 100;
332
333 (void)stepper_enable(fixture->dev, true);
334 (void)stepper_enable(fixture->dev, false);
335 ret = stepper_move_by(fixture->dev, steps);
336
337 zassert_not_equal(ret, 0, "Command should fail with an error code, but returned 0");
338 k_msleep(100);
339 (void)stepper_get_actual_position(fixture->dev, &pos);
340 zassert_equal(pos, 0, "Target position should not have changed from %d but is %d", 0, pos);
341 }
342
ZTEST_F(drv8424_api,test_move_by_is_moving_true_while_moving)343 ZTEST_F(drv8424_api, test_move_by_is_moving_true_while_moving)
344 {
345 int32_t steps = 50;
346 bool moving = false;
347
348 (void)stepper_enable(fixture->dev, true);
349 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
350 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
351 (void)stepper_move_by(fixture->dev, steps);
352 (void)stepper_is_moving(fixture->dev, &moving);
353 zassert_true(moving, "Driver should be in state is_moving");
354 }
355
ZTEST_F(drv8424_api,test_move_by_is_moving_false_when_completed)356 ZTEST_F(drv8424_api, test_move_by_is_moving_false_when_completed)
357 {
358 int32_t steps = 50;
359 bool moving = true;
360
361 (void)stepper_enable(fixture->dev, true);
362 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
363 (void)stepper_set_event_callback(fixture->dev, fixture->callback, NULL);
364 (void)stepper_move_by(fixture->dev, steps);
365 (void)k_poll(&stepper_event, 1, K_SECONDS(5));
366 unsigned int signaled;
367 int result;
368
369 k_poll_signal_check(&stepper_signal, &signaled, &result);
370 zassert_equal(signaled, 1, "No event detected");
371 zassert_equal(result, STEPPER_EVENT_STEPS_COMPLETED,
372 "Event was not STEPPER_EVENT_STEPS_COMPLETED event");
373 (void)stepper_is_moving(fixture->dev, &moving);
374 zassert_false(moving, "Driver should not be in state is_moving after completion");
375 }
376
ZTEST_F(drv8424_api,test_move_by_no_movement_when_disabled)377 ZTEST_F(drv8424_api, test_move_by_no_movement_when_disabled)
378 {
379 int32_t steps = 100;
380 int32_t curr_pos = 100;
381 int32_t ret = 0;
382
383 (void)stepper_set_microstep_interval(fixture->dev, 20000000);
384 (void)stepper_enable(fixture->dev, false);
385
386 ret = stepper_move_by(fixture->dev, steps);
387 zassert_equal(ret, -ECANCELED, "Move_by should fail with error code %d but returned %d",
388 -ECANCELED, ret);
389 (void)stepper_get_actual_position(fixture->dev, &curr_pos);
390 zassert_equal(curr_pos, 0, "Current position should not have changed from %d but is %d", 0,
391 curr_pos);
392 }
393
ZTEST_F(drv8424_api,test_run_positive_direction_correct_position)394 ZTEST_F(drv8424_api, test_run_positive_direction_correct_position)
395 {
396 uint64_t step_interval = 20000000;
397 int32_t steps = 0;
398
399 (void)stepper_enable(fixture->dev, true);
400 (void)stepper_set_microstep_interval(fixture->dev, step_interval);
401 (void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE);
402 k_busy_wait(110000);
403
404 (void)stepper_get_actual_position(fixture->dev, &steps);
405 zassert_true(IN_RANGE(steps, 4, 6), "Current position should be between 4 and 6 but is %d",
406 steps);
407 }
408
ZTEST_F(drv8424_api,test_run_negative_direction_correct_position)409 ZTEST_F(drv8424_api, test_run_negative_direction_correct_position)
410 {
411 uint64_t step_interval = 20000000;
412 int32_t steps = 0;
413
414 (void)stepper_enable(fixture->dev, true);
415 (void)stepper_set_microstep_interval(fixture->dev, step_interval);
416 (void)stepper_run(fixture->dev, STEPPER_DIRECTION_NEGATIVE);
417 k_busy_wait(110000);
418
419 (void)stepper_get_actual_position(fixture->dev, &steps);
420 zassert_true(IN_RANGE(steps, -6, 4),
421 "Current position should be between -6 and -4 but is %d", steps);
422 }
423
ZTEST_F(drv8424_api,test_run_zero_step_interval_correct_position)424 ZTEST_F(drv8424_api, test_run_zero_step_interval_correct_position)
425 {
426 uint64_t step_interval = 0;
427 int32_t steps = 0;
428
429 (void)stepper_enable(fixture->dev, true);
430 (void)stepper_set_microstep_interval(fixture->dev, step_interval);
431 (void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE);
432 k_msleep(100);
433
434 zassert_equal(steps, 0, "Current position should not have changed from %d but is %d", 0,
435 steps);
436 }
437
ZTEST_F(drv8424_api,test_run_is_moving_true_when_step_interval_greater_zero)438 ZTEST_F(drv8424_api, test_run_is_moving_true_when_step_interval_greater_zero)
439 {
440 uint64_t step_interval = 20000000;
441 bool moving = false;
442
443 (void)stepper_enable(fixture->dev, true);
444 (void)stepper_set_microstep_interval(fixture->dev, step_interval);
445 (void)stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE);
446 (void)stepper_is_moving(fixture->dev, &moving);
447 zassert_true(moving, "Driver should be in state is_moving");
448 (void)stepper_enable(fixture->dev, false);
449 }
450
ZTEST_F(drv8424_api,test_run_no_movement_when_disabled)451 ZTEST_F(drv8424_api, test_run_no_movement_when_disabled)
452 {
453 uint64_t step_interval = 20000000;
454 int32_t steps = 50;
455 int32_t ret = 0;
456
457 (void)stepper_enable(fixture->dev, false);
458 (void)stepper_set_microstep_interval(fixture->dev, step_interval);
459
460 ret = stepper_run(fixture->dev, STEPPER_DIRECTION_POSITIVE);
461 zassert_equal(ret, -ECANCELED, "Run should fail with error code %d but returned %d",
462 -ECANCELED, ret);
463 (void)stepper_get_actual_position(fixture->dev, &steps);
464 zassert_equal(steps, 0, "Current position should not have changed from %d but is %d", 0,
465 steps);
466 }
467
468 ZTEST_SUITE(drv8424_api, NULL, drv8424_api_setup, drv8424_api_before, drv8424_api_after, NULL);
469