Skip to content

Commit 5c2b7bc

Browse files
Verena Schweinstetterkartben
authored andcommitted
drivers: stepper: Add stepper driver for allegro a4979
Adding a stepper driver implementation for allegro a4979 microstepping programmable stepper motor driver. The implemenation was tested using the drv8424/api testsuite. Signed-off-by: Verena Schweinstetter <[email protected]>
1 parent b7f99ff commit 5c2b7bc

File tree

7 files changed

+365
-0
lines changed

7 files changed

+365
-0
lines changed

drivers/stepper/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/stepper.h)
55

66
# zephyr-keep-sorted-start
77
add_subdirectory_ifdef(CONFIG_STEPPER_ADI_TMC adi_tmc)
8+
add_subdirectory_ifdef(CONFIG_STEPPER_ALLEGRO allegro)
89
add_subdirectory_ifdef(CONFIG_STEPPER_TI ti)
910
add_subdirectory_ifdef(CONFIG_STEP_DIR_STEPPER step_dir)
1011
# zephyr-keep-sorted-stop

drivers/stepper/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ comment "Stepper Drivers"
3434
rsource "Kconfig.fake"
3535
rsource "Kconfig.gpio"
3636
rsource "adi_tmc/Kconfig"
37+
rsource "allegro/Kconfig"
3738
rsource "ti/Kconfig"
3839
# zephyr-keep-sorted-stop
3940

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 Carl Zeiss Meditec AG
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
zephyr_library()
5+
zephyr_library_property(ALLOW_EMPTY TRUE)
6+
7+
zephyr_library_sources_ifdef(CONFIG_A4979_STEPPER a4979.c)

drivers/stepper/allegro/Kconfig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 Carl Zeiss Meditec AG
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
menuconfig STEPPER_ALLEGRO
5+
bool "Allegro Stepper Controller"
6+
depends on STEPPER
7+
default y
8+
help
9+
Enable allegro stepper controller
10+
11+
if STEPPER_ALLEGRO
12+
13+
comment "Allegro Stepper Drivers"
14+
15+
# zephyr-keep-sorted-start
16+
rsource "Kconfig.a4979"
17+
# zephyr-keep-sorted-stop
18+
19+
endif # STEPPER_ALLEGRO

drivers/stepper/allegro/Kconfig.a4979

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 Carl Zeiss Meditec AG
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config A4979_STEPPER
5+
bool "Activate allegro A4979 stepper driver"
6+
default y
7+
depends on DT_HAS_ALLEGRO_A4979_ENABLED
8+
select STEP_DIR_STEPPER
9+
help
10+
Microstepping motor driver for stepper motors.

drivers/stepper/allegro/a4979.c

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
/*
2+
* SPDX-FileCopyrightText: Copyright (c) 2025 Carl Zeiss Meditec AG
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#define DT_DRV_COMPAT allegro_a4979
7+
8+
#include <zephyr/kernel.h>
9+
#include <zephyr/drivers/stepper.h>
10+
#include <zephyr/drivers/gpio.h>
11+
#include "../step_dir/step_dir_stepper_common.h"
12+
13+
#include <zephyr/logging/log.h>
14+
LOG_MODULE_REGISTER(a4979, CONFIG_STEPPER_LOG_LEVEL);
15+
16+
struct a4979_config {
17+
const struct step_dir_stepper_common_config common;
18+
const struct gpio_dt_spec en_pin;
19+
const struct gpio_dt_spec reset_pin;
20+
const struct gpio_dt_spec m0_pin;
21+
const struct gpio_dt_spec m1_pin;
22+
};
23+
24+
struct a4979_data {
25+
const struct step_dir_stepper_common_data common;
26+
enum stepper_micro_step_resolution micro_step_res;
27+
bool enabled;
28+
};
29+
30+
STEP_DIR_STEPPER_STRUCT_CHECK(struct a4979_config, struct a4979_data);
31+
32+
static int a4979_set_microstep_pin(const struct device *dev, const struct gpio_dt_spec *pin,
33+
int value)
34+
{
35+
int ret;
36+
37+
/* Reset microstep pin as it may have been disconnected. */
38+
ret = gpio_pin_configure_dt(pin, GPIO_OUTPUT_INACTIVE);
39+
if (ret != 0) {
40+
LOG_ERR("Failed to configure microstep pin (error: %d)", ret);
41+
return ret;
42+
}
43+
44+
ret = gpio_pin_set_dt(pin, value);
45+
if (ret != 0) {
46+
LOG_ERR("Failed to set microstep pin (error: %d)", ret);
47+
return ret;
48+
}
49+
50+
return 0;
51+
}
52+
53+
static int a4979_stepper_enable(const struct device *dev, bool enable)
54+
{
55+
int ret;
56+
const struct a4979_config *config = dev->config;
57+
struct a4979_data *data = dev->data;
58+
bool has_enable_pin = config->en_pin.port != NULL;
59+
60+
/* Check availability of enable pin, as it might be hardwired. */
61+
if (!has_enable_pin) {
62+
LOG_ERR("%s: Enable pin undefined.", dev->name);
63+
return -ENOTSUP;
64+
}
65+
66+
ret = gpio_pin_set_dt(&config->en_pin, enable);
67+
if (ret != 0) {
68+
LOG_ERR("%s: Failed to set en_pin (error: %d)", dev->name, ret);
69+
return ret;
70+
}
71+
72+
data->enabled = enable;
73+
if (!enable) {
74+
config->common.timing_source->stop(dev);
75+
}
76+
77+
return 0;
78+
}
79+
80+
static int a4979_stepper_set_micro_step_res(const struct device *dev,
81+
const enum stepper_micro_step_resolution micro_step_res)
82+
{
83+
const struct a4979_config *config = dev->config;
84+
struct a4979_data *data = dev->data;
85+
int ret;
86+
87+
uint8_t m0_value = 0;
88+
uint8_t m1_value = 0;
89+
90+
switch (micro_step_res) {
91+
case STEPPER_MICRO_STEP_1:
92+
m0_value = 0;
93+
m1_value = 0;
94+
break;
95+
case STEPPER_MICRO_STEP_2:
96+
m0_value = 1;
97+
m1_value = 0;
98+
break;
99+
case STEPPER_MICRO_STEP_4:
100+
m0_value = 0;
101+
m1_value = 1;
102+
case STEPPER_MICRO_STEP_16:
103+
m0_value = 1;
104+
m1_value = 1;
105+
break;
106+
default:
107+
LOG_ERR("Unsupported micro step resolution %d", micro_step_res);
108+
return -ENOTSUP;
109+
}
110+
111+
ret = a4979_set_microstep_pin(dev, &config->m0_pin, m0_value);
112+
if (ret != 0) {
113+
return ret;
114+
}
115+
ret = a4979_set_microstep_pin(dev, &config->m1_pin, m1_value);
116+
if (ret != 0) {
117+
return ret;
118+
}
119+
120+
data->micro_step_res = micro_step_res;
121+
return 0;
122+
}
123+
124+
static int a4979_stepper_get_micro_step_res(const struct device *dev,
125+
enum stepper_micro_step_resolution *micro_step_res)
126+
{
127+
struct a4979_data *data = dev->data;
128+
129+
*micro_step_res = data->micro_step_res;
130+
return 0;
131+
}
132+
133+
static int a4979_move_to(const struct device *dev, int32_t target)
134+
{
135+
struct a4979_data *data = dev->data;
136+
137+
if (!data->enabled) {
138+
LOG_ERR("Failed to move to target position, device is not enabled");
139+
return -ECANCELED;
140+
}
141+
142+
return step_dir_stepper_common_move_to(dev, target);
143+
}
144+
145+
static int a4979_stepper_move_by(const struct device *dev, const int32_t micro_steps)
146+
{
147+
struct a4979_data *data = dev->data;
148+
149+
if (!data->enabled) {
150+
LOG_ERR("Failed to move by delta, device is not enabled");
151+
return -ECANCELED;
152+
}
153+
154+
return step_dir_stepper_common_move_by(dev, micro_steps);
155+
}
156+
157+
static int a4979_run(const struct device *dev, enum stepper_direction direction)
158+
{
159+
struct a4979_data *data = dev->data;
160+
161+
if (!data->enabled) {
162+
LOG_ERR("Failed to run stepper, device is not enabled");
163+
return -ECANCELED;
164+
}
165+
166+
return step_dir_stepper_common_run(dev, direction);
167+
}
168+
169+
static int a4979_init(const struct device *dev)
170+
{
171+
const struct a4979_config *config = dev->config;
172+
struct a4979_data *data = dev->data;
173+
int ret;
174+
175+
bool has_enable_pin = config->en_pin.port != NULL;
176+
bool has_reset_pin = config->reset_pin.port != NULL;
177+
178+
LOG_DBG("Initializing %s gpios", dev->name);
179+
180+
/* Configure reset pin if it is available */
181+
if (has_reset_pin) {
182+
if (!gpio_is_ready_dt(&config->reset_pin)) {
183+
LOG_ERR("Enable Pin is not ready");
184+
return -ENODEV;
185+
}
186+
187+
ret = gpio_pin_configure_dt(&config->reset_pin, GPIO_OUTPUT_ACTIVE);
188+
if (ret != 0) {
189+
LOG_ERR("%s: Failed to configure reset_pin (error: %d)", dev->name, ret);
190+
return ret;
191+
}
192+
}
193+
194+
/* Configure enable pin if it is available */
195+
if (has_enable_pin) {
196+
if (!gpio_is_ready_dt(&config->en_pin)) {
197+
LOG_ERR("Enable Pin is not ready");
198+
return -ENODEV;
199+
}
200+
201+
ret = gpio_pin_configure_dt(&config->en_pin, GPIO_OUTPUT_INACTIVE);
202+
if (ret != 0) {
203+
LOG_ERR("%s: Failed to configure en_pin (error: %d)", dev->name, ret);
204+
return ret;
205+
}
206+
}
207+
208+
/* Configure microstep pin 0 */
209+
if (!gpio_is_ready_dt(&config->m0_pin)) {
210+
LOG_ERR("m0 Pin is not ready");
211+
return -ENODEV;
212+
}
213+
ret = gpio_pin_configure_dt(&config->m0_pin, GPIO_OUTPUT_INACTIVE);
214+
if (ret != 0) {
215+
LOG_ERR("%s: Failed to configure m0_pin (error: %d)", dev->name, ret);
216+
return ret;
217+
}
218+
219+
/* Configure microstep pin 1 */
220+
if (!gpio_is_ready_dt(&config->m1_pin)) {
221+
LOG_ERR("m1 Pin is not ready");
222+
return -ENODEV;
223+
}
224+
ret = gpio_pin_configure_dt(&config->m1_pin, GPIO_OUTPUT_INACTIVE);
225+
if (ret != 0) {
226+
LOG_ERR("%s: Failed to configure m1_pin (error: %d)", dev->name, ret);
227+
return ret;
228+
}
229+
230+
ret = a4979_stepper_set_micro_step_res(dev, data->micro_step_res);
231+
if (ret != 0) {
232+
LOG_ERR("Failed to set micro step resolution: %d", ret);
233+
return ret;
234+
}
235+
236+
ret = step_dir_stepper_common_init(dev);
237+
if (ret != 0) {
238+
LOG_ERR("Failed to initialize common stepper data: %d", ret);
239+
return ret;
240+
}
241+
gpio_pin_set_dt(&config->common.step_pin, 0);
242+
243+
return 0;
244+
}
245+
246+
static DEVICE_API(stepper, a4979_stepper_api) = {
247+
.enable = a4979_stepper_enable,
248+
.move_by = a4979_stepper_move_by,
249+
.move_to = a4979_move_to,
250+
.is_moving = step_dir_stepper_common_is_moving,
251+
.set_reference_position = step_dir_stepper_common_set_reference_position,
252+
.get_actual_position = step_dir_stepper_common_get_actual_position,
253+
.set_microstep_interval = step_dir_stepper_common_set_microstep_interval,
254+
.run = a4979_run,
255+
.set_micro_step_res = a4979_stepper_set_micro_step_res,
256+
.get_micro_step_res = a4979_stepper_get_micro_step_res,
257+
.set_event_callback = step_dir_stepper_common_set_event_callback,
258+
};
259+
260+
#define A4979_DEVICE(inst) \
261+
\
262+
static const struct a4979_config a4979_config_##inst = { \
263+
.common = STEP_DIR_STEPPER_DT_INST_COMMON_CONFIG_INIT(inst), \
264+
.en_pin = GPIO_DT_SPEC_INST_GET_OR(inst, en_gpios, {0}), \
265+
.reset_pin = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {0}), \
266+
.m0_pin = GPIO_DT_SPEC_INST_GET(inst, m0_gpios), \
267+
.m1_pin = GPIO_DT_SPEC_INST_GET(inst, m1_gpios), \
268+
}; \
269+
\
270+
static struct a4979_data a4979_data_##inst = { \
271+
.common = STEP_DIR_STEPPER_DT_INST_COMMON_DATA_INIT(inst), \
272+
.micro_step_res = DT_INST_PROP(inst, micro_step_res), \
273+
}; \
274+
\
275+
DEVICE_DT_INST_DEFINE(inst, a4979_init, NULL, &a4979_data_##inst, &a4979_config_##inst, \
276+
POST_KERNEL, CONFIG_STEPPER_INIT_PRIORITY, &a4979_stepper_api);
277+
278+
DT_INST_FOREACH_STATUS_OKAY(A4979_DEVICE)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 Carl Zeiss Meditec AG
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: |
5+
Allegro A4979 microstepping stepper motor driver.
6+
A4979 is a flexible microstepping motor driver with built-in translator for easy operation.
7+
It is designed to operate bipolar stepper motors in full-, half-, quarter-, and sixteenth-step
8+
modes.
9+
10+
Example:
11+
a4979: a4979 {
12+
status = "okay";
13+
compatible = "allegro,a4979";
14+
micro-step-res = <2>;
15+
reset-gpios = <&gpiod 10 GPIO_ACTIVE_HIGH>;
16+
dir-gpios = <&gpiod 14 GPIO_ACTIVE_HIGH>;
17+
step-gpios = <&gpiod 15 GPIO_ACTIVE_HIGH>;
18+
en-gpios = <&gpiod 11 GPIO_ACTIVE_HIGH>;
19+
m0-gpios = <&gpiod 13 0>;
20+
m1-gpios = <&gpiod 12 0>;
21+
counter = <&counter5>;
22+
};
23+
24+
compatible: "allegro,a4979"
25+
26+
include:
27+
- name: stepper-controller.yaml
28+
property-allowlist:
29+
- micro-step-res
30+
- step-gpios
31+
- dir-gpios
32+
- en-gpios
33+
- counter
34+
35+
properties:
36+
m0-gpios:
37+
required: true
38+
type: phandle-array
39+
description: Microstep configuration pin 0.
40+
41+
m1-gpios:
42+
required: true
43+
type: phandle-array
44+
description: Microstep configuration pin 1.
45+
46+
reset-gpios:
47+
type: phandle-array
48+
required: true
49+
description: Reset pin

0 commit comments

Comments
 (0)