You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
121 lines
3.1 KiB
121 lines
3.1 KiB
/* |
|
* SPDX-FileCopyrightText: Copyright (c) 2024 Fabian Blatz <fabianblatz@gmail.com> |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <zephyr/drivers/counter.h> |
|
#include "step_dir_stepper_common.h" |
|
|
|
#include <zephyr/logging/log.h> |
|
LOG_MODULE_DECLARE(step_dir_stepper); |
|
|
|
static void step_counter_top_interrupt(const struct device *dev, void *user_data) |
|
{ |
|
ARG_UNUSED(dev); |
|
struct step_dir_stepper_common_data *data = user_data; |
|
|
|
stepper_handle_timing_signal(data->dev); |
|
} |
|
|
|
int step_counter_timing_source_update(const struct device *dev, |
|
const uint64_t microstep_interval_ns) |
|
{ |
|
const struct step_dir_stepper_common_config *config = dev->config; |
|
struct step_dir_stepper_common_data *data = dev->data; |
|
int ret; |
|
|
|
if (microstep_interval_ns == 0) { |
|
return -EINVAL; |
|
} |
|
|
|
data->counter_top_cfg.ticks = DIV_ROUND_UP( |
|
counter_get_frequency(config->counter) * microstep_interval_ns, NSEC_PER_SEC); |
|
|
|
/* Lock interrupts while modifying counter settings */ |
|
int key = irq_lock(); |
|
|
|
ret = counter_set_top_value(config->counter, &data->counter_top_cfg); |
|
|
|
irq_unlock(key); |
|
|
|
if (ret != 0) { |
|
LOG_ERR("%s: Failed to set counter top value (error: %d)", dev->name, ret); |
|
return ret; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
int step_counter_timing_source_start(const struct device *dev) |
|
{ |
|
const struct step_dir_stepper_common_config *config = dev->config; |
|
struct step_dir_stepper_common_data *data = dev->data; |
|
int ret; |
|
|
|
ret = counter_start(config->counter); |
|
if (ret < 0 && ret != -EALREADY) { |
|
LOG_ERR("Failed to start counter: %d", ret); |
|
return ret; |
|
} |
|
|
|
data->counter_running = true; |
|
|
|
return 0; |
|
} |
|
|
|
int step_counter_timing_source_stop(const struct device *dev) |
|
{ |
|
const struct step_dir_stepper_common_config *config = dev->config; |
|
struct step_dir_stepper_common_data *data = dev->data; |
|
int ret; |
|
|
|
ret = counter_stop(config->counter); |
|
if (ret < 0 && ret != -EALREADY) { |
|
LOG_ERR("Failed to stop counter: %d", ret); |
|
return ret; |
|
} |
|
|
|
data->counter_running = false; |
|
|
|
return 0; |
|
} |
|
|
|
bool step_counter_timing_source_needs_reschedule(const struct device *dev) |
|
{ |
|
ARG_UNUSED(dev); |
|
return false; |
|
} |
|
|
|
bool step_counter_timing_source_is_running(const struct device *dev) |
|
{ |
|
struct step_dir_stepper_common_data *data = dev->data; |
|
|
|
return data->counter_running; |
|
} |
|
|
|
int step_counter_timing_source_init(const struct device *dev) |
|
{ |
|
const struct step_dir_stepper_common_config *config = dev->config; |
|
struct step_dir_stepper_common_data *data = dev->data; |
|
|
|
if (!device_is_ready(config->counter)) { |
|
LOG_ERR("Counter device is not ready"); |
|
return -ENODEV; |
|
} |
|
|
|
data->counter_top_cfg.callback = step_counter_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); |
|
|
|
return 0; |
|
} |
|
|
|
const struct stepper_timing_source_api step_counter_timing_source_api = { |
|
.init = step_counter_timing_source_init, |
|
.update = step_counter_timing_source_update, |
|
.start = step_counter_timing_source_start, |
|
.needs_reschedule = step_counter_timing_source_needs_reschedule, |
|
.stop = step_counter_timing_source_stop, |
|
.is_running = step_counter_timing_source_is_running, |
|
};
|
|
|