drivers: stepper: drv8424: Use step_dir common code

Adapt the drv8424 driver to use the common step dir interface.

Signed-off-by: Fabian Blatz <fabianblatz@gmail.com>
This commit is contained in:
Fabian Blatz 2024-12-28 10:48:00 +01:00 committed by Benjamin Cabé
parent 39dbd49874
commit 0ac9a6c512
3 changed files with 52 additions and 378 deletions

View file

@ -5,17 +5,7 @@ config DRV8424
bool "TI DRV8424 stepper motor driver"
default y
depends on DT_HAS_TI_DRV8424_ENABLED
select COUNTER
select STEP_DIR_STEPPER
select STEPPER_STEP_DIR_GENERATE_ISR_SAFE_EVENTS
help
Enable driver for TI DRV8424 stepper motor driver.
if DRV8424
config DRV8424_EVENT_QUEUE_LEN
int "Maximum number of pending stepper events"
default 4
help
The maximum number of stepper events that can be pending before new events
are dropped.
endif # DRV8424

View file

@ -5,14 +5,11 @@
#define DT_DRV_COMPAT ti_drv8424
#include <zephyr/sys/util.h>
#include <zephyr/sys_clock.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/stepper.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/counter.h>
#include <zephyr/irq.h>
#include <zephyr/drivers/stepper/stepper_drv8424.h>
#include "../step_dir/step_dir_stepper_common.h"
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(drv8424, CONFIG_STEPPER_LOG_LEVEL);
@ -24,13 +21,11 @@ LOG_MODULE_REGISTER(drv8424, CONFIG_STEPPER_LOG_LEVEL);
* needed by a given DRV8424 stepper driver.
*/
struct drv8424_config {
struct gpio_dt_spec dir_pin;
struct gpio_dt_spec step_pin;
struct step_dir_stepper_common_config common;
struct gpio_dt_spec sleep_pin;
struct gpio_dt_spec en_pin;
struct gpio_dt_spec m0_pin;
struct gpio_dt_spec m1_pin;
const struct device *counter;
};
/* Struct for storing the states of output pins. */
@ -47,119 +42,13 @@ struct drv8424_pin_states {
* This structure contains mutable data used by a DRV8424 stepper driver.
*/
struct drv8424_data {
const struct device *dev;
const struct step_dir_stepper_common_data common;
bool enabled;
struct drv8424_pin_states pin_states;
enum stepper_micro_step_resolution ustep_res;
uint32_t max_velocity;
int32_t reference_position;
int32_t target_position;
bool is_moving;
bool constant_velocity;
enum stepper_direction constant_velocity_direction;
stepper_event_callback_t event_callback;
struct k_work event_callback_work;
void *event_callback_user_data;
struct k_msgq event_msgq;
char event_msgq_buffer[CONFIG_DRV8424_EVENT_QUEUE_LEN * sizeof(enum stepper_event)];
bool step_signal_high;
struct counter_top_cfg counter_top_cfg;
};
static void drv8424_user_callback_work_fn(struct k_work *work)
{
int ret;
/* Get containing data struct */
struct drv8424_data *driver_data =
CONTAINER_OF(work, struct drv8424_data, event_callback_work);
/* Get next pending event (if any) from message queue */
enum stepper_event event;
ret = k_msgq_get(&driver_data->event_msgq, &event, K_NO_WAIT);
if (ret != 0) {
/* No pending events */
return;
}
/* Run the callback */
if (driver_data->event_callback != NULL) {
driver_data->event_callback(driver_data->dev, event,
driver_data->event_callback_user_data);
}
/* If there are more pending events, resubmit this work item to handle them */
if (k_msgq_num_used_get(&driver_data->event_msgq) > 0) {
k_work_submit(work);
}
}
static int drv8424_schedule_user_callback(struct drv8424_data *data, enum stepper_event event)
{
int ret;
/* Place event in message queue to be picked up by work item */
ret = k_msgq_put(&data->event_msgq, &event, K_NO_WAIT);
if (ret != 0) {
LOG_WRN("%s: Too many concurrent events, dropping event of type %d",
data->dev->name, event);
return -ENOBUFS;
}
/* Submit work item */
ret = k_work_submit(&data->event_callback_work);
if (ret < 0) {
LOG_ERR("%s: Failed to submit work item (error %d)", data->dev->name, ret);
return ret;
}
return 0;
}
static void drv8424_positioning_top_interrupt(const struct device *dev, void *user_data)
{
struct drv8424_data *data = user_data;
const struct drv8424_config *config = data->dev->config;
if (!data->constant_velocity && data->reference_position == data->target_position) {
/* Check if target position is reached */
counter_stop(config->counter);
if (data->event_callback != NULL) {
/* Ignore return value since we can't do anything about it anyway */
drv8424_schedule_user_callback(data, STEPPER_EVENT_STEPS_COMPLETED);
}
data->is_moving = false;
return;
}
/* Determine direction we're going in for counting purposes */
enum stepper_direction direction;
if (data->constant_velocity) {
direction = data->constant_velocity_direction;
} else {
direction = (data->target_position >= data->reference_position)
? STEPPER_DIRECTION_POSITIVE
: STEPPER_DIRECTION_NEGATIVE;
}
/* Switch step pin on or off depending position in step period */
if (data->step_signal_high) {
/* Generate a falling edge and count a completed step */
gpio_pin_set_dt(&config->step_pin, 0);
if (direction == STEPPER_DIRECTION_POSITIVE) {
data->reference_position++;
} else {
data->reference_position--;
}
} else {
/* Generate a rising edge */
gpio_pin_set_dt(&config->step_pin, 1);
}
data->step_signal_high = !data->step_signal_high;
}
STEP_DIR_STEPPER_STRUCT_CHECK(struct drv8424_config, struct drv8424_data);
static int drv8424_set_microstep_pin(const struct device *dev, const struct gpio_dt_spec *pin,
int value)
@ -263,216 +152,13 @@ static int drv8424_enable(const struct device *dev, bool enable)
data->enabled = enable;
if (!enable) {
counter_stop(config->counter);
data->is_moving = false;
gpio_pin_set_dt(&config->step_pin, 0);
data->step_signal_high = false;
config->common.timing_source->stop(dev);
gpio_pin_set_dt(&config->common.step_pin, 0);
}
return 0;
}
static int drv8424_set_counter_frequency(const struct device *dev, uint32_t freq_hz)
{
const struct drv8424_config *config = dev->config;
struct drv8424_data *data = dev->data;
int ret;
if (freq_hz == 0) {
return -EINVAL;
}
data->counter_top_cfg.ticks =
DIV_ROUND_UP(counter_us_to_ticks(config->counter, USEC_PER_SEC), freq_hz);
ret = counter_set_top_value(config->counter, &data->counter_top_cfg);
if (ret != 0) {
LOG_ERR("%s: Failed to set counter top value (error: %d)", dev->name, ret);
return ret;
}
return 0;
}
static int drv8424_start_positioning(const struct device *dev)
{
const struct drv8424_config *config = dev->config;
struct drv8424_data *data = dev->data;
int ret;
/* Unset constant velocity flag if present */
data->constant_velocity = false;
int dir_value = (data->target_position >= data->reference_position) ? 1 : 0;
ret = gpio_pin_set_dt(&config->dir_pin, dir_value);
if (ret != 0) {
LOG_ERR("%s: Failed to set direction pin (error %d)", dev->name, ret);
return ret;
}
/* Lock interrupts while modifying counter settings */
int key = irq_lock();
/* Set counter to step signal frequency */
ret = drv8424_set_counter_frequency(dev, data->max_velocity * 2);
if (ret != 0) {
LOG_ERR("%s: Failed to set counter frequency (error %d)", dev->name, ret);
goto end;
}
data->is_moving = true;
ret = counter_start(config->counter);
if (ret != 0) {
LOG_ERR("%s: Failed to start counter (error: %d)", dev->name, ret);
data->is_moving = false;
goto end;
}
end:
irq_unlock(key);
return ret;
}
static int drv8424_move_by(const struct device *dev, int32_t micro_steps)
{
struct drv8424_data *data = dev->data;
int ret;
if (data->max_velocity == 0) {
LOG_ERR("%s: Invalid max. velocity %d configured", dev->name, data->max_velocity);
return -EINVAL;
}
if (!data->enabled) {
return -ECANCELED;
}
/* Compute target position */
data->target_position = data->reference_position + micro_steps;
ret = drv8424_start_positioning(dev);
if (ret != 0) {
LOG_ERR("%s: Failed to begin positioning (error %d)", dev->name, ret);
return ret;
};
return 0;
}
static int drv8424_is_moving(const struct device *dev, bool *is_moving)
{
struct drv8424_data *data = dev->data;
*is_moving = data->is_moving;
return 0;
}
static int drv8424_set_reference_position(const struct device *dev, int32_t position)
{
struct drv8424_data *data = dev->data;
data->reference_position = position;
return 0;
}
static int drv8424_get_actual_position(const struct device *dev, int32_t *position)
{
struct drv8424_data *data = dev->data;
*position = data->reference_position;
return 0;
}
static int drv8424_move_to(const struct device *dev, int32_t position)
{
struct drv8424_data *data = dev->data;
int ret;
if (!data->enabled) {
return -ECANCELED;
}
data->target_position = position;
ret = drv8424_start_positioning(dev);
if (ret != 0) {
LOG_ERR("%s: Failed to begin positioning (error %d)", dev->name, ret);
return ret;
};
return 0;
}
static int drv8424_set_max_velocity(const struct device *dev, uint32_t velocity)
{
struct drv8424_data *data = dev->data;
data->max_velocity = velocity;
return 0;
}
static int drv8424_run(const struct device *dev, const enum stepper_direction direction,
const uint32_t velocity)
{
const struct drv8424_config *config = dev->config;
struct drv8424_data *data = dev->data;
int ret;
if (!data->enabled) {
return -ECANCELED;
}
int dir_value = (direction == STEPPER_DIRECTION_POSITIVE) ? 1 : 0;
ret = gpio_pin_set_dt(&config->dir_pin, dir_value);
if (ret != 0) {
LOG_ERR("%s: Failed to set direction pin (error %d)", dev->name, ret);
return ret;
}
/* Lock interrupts while modifying settings used by ISR */
int key = irq_lock();
/* Set data used in counter interrupt */
data->constant_velocity = true;
data->constant_velocity_direction = direction;
data->is_moving = false;
/* Treat velocity 0 by not stepping at all */
if (velocity == 0) {
ret = counter_stop(config->counter);
if (ret != 0) {
LOG_ERR("%s: Failed to stop counter (error %d)", dev->name, ret);
goto end;
}
gpio_pin_set_dt(&config->step_pin, 0);
data->step_signal_high = false;
} else {
ret = drv8424_set_counter_frequency(dev, velocity * 2);
if (ret != 0) {
LOG_ERR("%s: Failed to set counter frequency (error %d)", dev->name, ret);
goto end;
}
ret = counter_start(config->counter);
if (ret != 0) {
LOG_ERR("%s: Failed to start counter (error %d)", dev->name, ret);
goto end;
}
data->is_moving = true;
}
end:
irq_unlock(key);
return ret;
}
static int drv8424_set_micro_step_res(const struct device *dev,
enum stepper_micro_step_resolution micro_step_res)
{
@ -554,15 +240,41 @@ static int drv8424_get_micro_step_res(const struct device *dev,
return 0;
}
static int drv8424_set_event_callback(const struct device *dev, stepper_event_callback_t callback,
void *user_data)
static int drv8424_move_to(const struct device *dev, int32_t target)
{
struct drv8424_data *data = dev->data;
data->event_callback = callback;
data->event_callback_user_data = user_data;
if (!data->enabled) {
LOG_ERR("Failed to move to target position, device is not enabled");
return -ECANCELED;
}
return 0;
return step_dir_stepper_common_move_to(dev, target);
}
static int drv8424_move_by(const struct device *dev, int32_t steps)
{
struct drv8424_data *data = dev->data;
if (!data->enabled) {
LOG_ERR("Failed to move by delta, device is not enabled");
return -ECANCELED;
}
return step_dir_stepper_common_move_by(dev, steps);
}
static int drv8424_run(const struct device *dev, enum stepper_direction direction,
uint32_t velocity)
{
struct drv8424_data *data = dev->data;
if (!data->enabled) {
LOG_ERR("Failed to run stepper, device is not enabled");
return -ECANCELED;
}
return step_dir_stepper_common_run(dev, direction, velocity);
}
static int drv8424_init(const struct device *dev)
@ -571,22 +283,6 @@ static int drv8424_init(const struct device *dev)
struct drv8424_data *const data = dev->data;
int ret;
data->dev = dev;
/* Configure direction pin */
ret = gpio_pin_configure_dt(&config->dir_pin, GPIO_OUTPUT_ACTIVE);
if (ret != 0) {
LOG_ERR("%s: Failed to configure dir_pin (error: %d)", dev->name, ret);
return ret;
}
/* Configure step pin */
ret = gpio_pin_configure_dt(&config->step_pin, GPIO_OUTPUT_INACTIVE);
if (ret != 0) {
LOG_ERR("%s: Failed to configure step_pin (error: %d)", dev->name, ret);
return ret;
}
/* Configure sleep pin if it is available */
if (config->sleep_pin.port != NULL) {
ret = gpio_pin_configure_dt(&config->sleep_pin, GPIO_OUTPUT_ACTIVE);
@ -628,17 +324,11 @@ static int drv8424_init(const struct device *dev)
return ret;
}
/* Set initial counter configuration */
data->step_signal_high = false;
data->counter_top_cfg.callback = drv8424_positioning_top_interrupt;
data->counter_top_cfg.user_data = data;
data->counter_top_cfg.flags = 0;
data->counter_top_cfg.ticks = counter_us_to_ticks(config->counter, 1000000);
/* Initialize work item and message queue for handling event callbacks */
k_msgq_init(&data->event_msgq, data->event_msgq_buffer, sizeof(enum stepper_event),
CONFIG_DRV8424_EVENT_QUEUE_LEN);
k_work_init(&data->event_callback_work, drv8424_user_callback_work_fn);
ret = step_dir_stepper_common_init(dev);
if (ret != 0) {
LOG_ERR("Failed to initialize common step direction stepper (error: %d)", ret);
return ret;
}
return 0;
}
@ -647,31 +337,29 @@ static DEVICE_API(stepper, drv8424_stepper_api) = {
.enable = drv8424_enable,
.move_by = drv8424_move_by,
.move_to = drv8424_move_to,
.is_moving = drv8424_is_moving,
.set_reference_position = drv8424_set_reference_position,
.get_actual_position = drv8424_get_actual_position,
.set_max_velocity = drv8424_set_max_velocity,
.is_moving = step_dir_stepper_common_is_moving,
.set_reference_position = step_dir_stepper_common_set_reference_position,
.get_actual_position = step_dir_stepper_common_get_actual_position,
.set_max_velocity = step_dir_stepper_common_set_max_velocity,
.run = drv8424_run,
.set_micro_step_res = drv8424_set_micro_step_res,
.get_micro_step_res = drv8424_get_micro_step_res,
.set_event_callback = drv8424_set_event_callback,
.set_event_callback = step_dir_stepper_common_set_event_callback,
};
#define DRV8424_DEVICE(inst) \
\
static const struct drv8424_config drv8424_config_##inst = { \
.dir_pin = GPIO_DT_SPEC_INST_GET(inst, dir_gpios), \
.step_pin = GPIO_DT_SPEC_INST_GET(inst, step_gpios), \
.common = STEP_DIR_STEPPER_DT_INST_COMMON_CONFIG_INIT(inst), \
.sleep_pin = GPIO_DT_SPEC_INST_GET_OR(inst, sleep_gpios, {0}), \
.en_pin = GPIO_DT_SPEC_INST_GET_OR(inst, en_gpios, {0}), \
.m0_pin = GPIO_DT_SPEC_INST_GET(inst, m0_gpios), \
.m1_pin = GPIO_DT_SPEC_INST_GET(inst, m1_gpios), \
.counter = DEVICE_DT_GET(DT_INST_PHANDLE(inst, counter)), \
}; \
\
static struct drv8424_data drv8424_data_##inst = { \
.common = STEP_DIR_STEPPER_DT_INST_COMMON_DATA_INIT(inst), \
.ustep_res = DT_INST_PROP(inst, micro_step_res), \
.reference_position = 0, \
}; \
\
DEVICE_DT_INST_DEFINE(inst, &drv8424_init, NULL, &drv8424_data_##inst, \

View file

@ -34,6 +34,7 @@ include:
- step-gpios
- dir-gpios
- en-gpios
- counter
properties:
fault-gpios:
@ -53,8 +54,3 @@ properties:
required: true
type: phandle-array
description: Microstep configuration pin 1.
counter:
required: true
type: phandle
description: Counter used for generating step-accurate pulse signals.