blob: 0688285384b0c0063dab1a45301c4c43c2733ea1 [file]
/*
* SPDX-FileCopyrightText: Copyright (c) 2025 Jilay Sandeep Pandya.
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/stepper/stepper.h>
#include <zephyr/drivers/stepper/stepper_ctrl.h>
#include <zephyr/input/input.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(stepper_generic, CONFIG_STEPPER_LOG_LEVEL);
/*
* The stepper-driver alias is optional: some stepper controllers (e.g. h-bridge based ones)
* drive the motor directly and do not have a separate hardware driver to enable/disable.
*/
#if DT_NODE_EXISTS(DT_ALIAS(stepper_driver))
#define HAS_STEPPER_DRIVER 1
#define STEPPER_DRIVER_MICRO_STEP_RES DT_PROP_OR(DT_ALIAS(stepper_driver), micro_step_res, 1)
static const struct device *stepper_driver = DEVICE_DT_GET(DT_ALIAS(stepper_driver));
#else
#define HAS_STEPPER_DRIVER 0
#define STEPPER_DRIVER_MICRO_STEP_RES 1
#endif
static const struct device *stepper_ctrl = DEVICE_DT_GET(DT_ALIAS(stepper_ctrl));
enum stepper_mode {
STEPPER_MODE_ENABLE,
STEPPER_MODE_PING_PONG_RELATIVE,
STEPPER_MODE_PING_PONG_ABSOLUTE,
STEPPER_MODE_ROTATE_CW,
STEPPER_MODE_ROTATE_CCW,
STEPPER_MODE_STOP,
STEPPER_MODE_DISABLE,
};
static atomic_t stepper_mode = ATOMIC_INIT(STEPPER_MODE_DISABLE);
static int32_t ping_pong_target_position = CONFIG_STEPS_PER_REV * CONFIG_PING_PONG_N_REV *
STEPPER_DRIVER_MICRO_STEP_RES;
static K_SEM_DEFINE(stepper_generic_sem, 0, 1);
static void stepper_callback(const struct device *dev, const enum stepper_ctrl_event event,
void *user_data)
{
switch (event) {
case STEPPER_CTRL_EVENT_STEPS_COMPLETED:
k_sem_give(&stepper_generic_sem);
break;
default:
break;
}
}
static void button_pressed(struct input_event *event, void *user_data)
{
ARG_UNUSED(user_data);
if (event->value == 0 && event->type == INPUT_EV_KEY) {
return;
}
enum stepper_mode mode = atomic_get(&stepper_mode);
if (mode == STEPPER_MODE_DISABLE) {
atomic_set(&stepper_mode, STEPPER_MODE_ENABLE);
} else {
atomic_inc(&stepper_mode);
}
k_sem_give(&stepper_generic_sem);
}
INPUT_CALLBACK_DEFINE(NULL, button_pressed, NULL);
int main(void)
{
LOG_INF("Starting generic stepper sample");
if (!device_is_ready(stepper_ctrl)) {
LOG_ERR("Device %s is not ready", stepper_ctrl->name);
return -ENODEV;
}
#if HAS_STEPPER_DRIVER
if (!device_is_ready(stepper_driver)) {
LOG_ERR("Device %s is not ready", stepper_driver->name);
return -ENODEV;
}
#endif
LOG_DBG("stepper is %p, name is %s", stepper_ctrl, stepper_ctrl->name);
stepper_ctrl_set_event_cb(stepper_ctrl, stepper_callback, NULL);
stepper_ctrl_set_reference_position(stepper_ctrl, 0);
stepper_ctrl_set_microstep_interval(stepper_ctrl, CONFIG_STEP_INTERVAL_NS);
for (;;) {
k_sem_take(&stepper_generic_sem, K_FOREVER);
switch (atomic_get(&stepper_mode)) {
case STEPPER_MODE_ENABLE:
#if HAS_STEPPER_DRIVER
stepper_enable(stepper_driver);
#endif
LOG_INF("mode: enable");
break;
case STEPPER_MODE_PING_PONG_RELATIVE:
ping_pong_target_position *= -1;
stepper_ctrl_move_by(stepper_ctrl, ping_pong_target_position);
LOG_INF("mode: ping pong relative");
break;
case STEPPER_MODE_PING_PONG_ABSOLUTE:
ping_pong_target_position *= -1;
stepper_ctrl_move_to(stepper_ctrl, ping_pong_target_position);
LOG_INF("mode: ping pong absolute");
break;
case STEPPER_MODE_ROTATE_CW:
stepper_ctrl_run(stepper_ctrl, STEPPER_CTRL_DIRECTION_POSITIVE);
LOG_INF("mode: rotate cw");
break;
case STEPPER_MODE_ROTATE_CCW:
stepper_ctrl_run(stepper_ctrl, STEPPER_CTRL_DIRECTION_NEGATIVE);
LOG_INF("mode: rotate ccw");
break;
case STEPPER_MODE_STOP:
stepper_ctrl_stop(stepper_ctrl);
LOG_INF("mode: stop");
break;
case STEPPER_MODE_DISABLE:
#if HAS_STEPPER_DRIVER
stepper_disable(stepper_driver);
#endif
LOG_INF("mode: disable");
break;
default:
break;
}
}
return 0;
}
static void monitor_thread(void)
{
for (;;) {
int32_t actual_position;
stepper_ctrl_get_actual_position(stepper_ctrl, &actual_position);
LOG_DBG("Actual position: %d", actual_position);
k_sleep(K_MSEC(CONFIG_MONITOR_THREAD_TIMEOUT_MS));
}
}
K_THREAD_DEFINE(monitor_tid, CONFIG_MONITOR_THREAD_STACK_SIZE, monitor_thread, NULL, NULL, NULL, 5,
0, 0);