-
Notifications
You must be signed in to change notification settings - Fork 6.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: Change Stepper API to use step interval #83726
Conversation
Did not include it yet, but the |
5090c7c
to
d09f9cb
Compare
The API Change and then relevant changes in shell, drivers, tests should be squashed in one commit. |
d09f9cb
to
38f96d2
Compare
About the squashing - don't know whats the proper ettiquette for it. Did not do that many treewide changes as of now. |
when we recently shifted to I would have had one commit for |
You should really squash the API change with the code update to use the new API, basically no commit should break the build. Doc update can be on its own. In this case it does make it harder to review but that's how it should be done. |
38f96d2
to
7b61f11
Compare
8cadbdf
to
facdd26
Compare
{ | ||
__ASSERT_NO_MSG(clock_frequency); | ||
__ASSERT_NO_MSG(step_interval_us); | ||
|
||
uint32_t velocity_hz = 1e6 / step_interval_us; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Max possible speed here is then limited 1MHz, which is not much since 256 usteps * 200 steps/rev = 51200 usteps/rev
, so over here we will be limiting the speed to somewhere around 2rps
. At this point i can only see that we need to allow both the interfaces.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe use nanoseconds instead of microseconds?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also 1e6/51200 is about 20rps, or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No that's correct, although 20 rps is still i would say on the slow speed spectrum.
Let's do it this way since step_interval
serves majority of the drivers, let's keep it, i think microseconds timebase is good enough.
I think going in nanoseconds timebase would just be to accomodate drivers like tmc5041, or?
For drivers like tmc5041, this function shall return -ENOTSUP, as there is also a way to set speed via ramp as can be seen over here
int tmc5041_stepper_set_ramp(const struct device *dev, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are also 0.9° steppers which are also very common especially for projects requiring precise positions. This would half the RPM additionally. But on the other hand, the use case where you step at 1/256 uSteps and want to achieve very fast speeds at the same time are very rare. In this case dynamic microstepping can be used, where you change the uStep resolution for slow and fast velocities can be used (this would be responsibility of the application code, since it would introduce to much complexity into the stepper driver in zephyr). This is what we are doing in OpenAstroTech. We switch to something like 1/32 for fast slew movements and then back to e.g. 1/128 for slow and precise tracking rotations.
In general tmc2209 needs a STEP pin input timing of at least 100ns. Disregarding other factors this would result in maximal frequency of 10MHz.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so i suppose we need to go to nanoseconds timebase.
For controllers like tmc5041 with internal ramp control we cannot ascertain step_interval
due to acceleration/deceleration, we can more or less only set_max_velocity
, also the reason why this API was designed like this.
stepper_set_step_interval(const struct device*, uint64_t step_interval_nsec)
it is :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For drivers like tmc5041, this function shall return -ENOTSUP, as there is also a way to set speed via ramp as can be seen over here
How would that condition look like? The issue is if you want to be faster then 1 step_interval_us but since its a uint64_t you can not attempt to go faster, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry it is -ENOSYS, i mean that the tmc5041 driver shall not implement stepper_set_step_interval, ofcourse with uint64_t tmc5041 could go faster, what i was trying to say that when i set a step interval, i expect that every step shall be exactly that interval apart, which cannot be ascertained with drivers like tmc5041 which have internal ramp motion controller which is reponsible for stepping intervals.
Hence the stepper_set_step_interval
shall not be supported by the tmc5041 driver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm test does fail now because the counter_us_to_ticks
returns a uint32_t
which is not enough to hold 50 microsteps per second in microsecond interval (stepper_set_step_interval(dev, 20000000)
which will call counter_us_to_ticks
with 20000000000
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jilaypandya @andre-stefanov I fixed this inside the counter timing source calculation, can you also verify that this is correct?
facdd26
to
f194f0b
Compare
f194f0b
to
d5c2833
Compare
@@ -348,15 +348,21 @@ static int tmc5041_stepper_move_by(const struct device *dev, const int32_t micro | |||
return 0; | |||
} | |||
|
|||
static int tmc5041_stepper_set_max_velocity(const struct device *dev, uint32_t velocity) | |||
static int tmc5041_stepper_set_step_interval(const struct device *dev, uint64_t step_interval_ns) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tmc5041 can contextually only set velocities and because of its internal ramp controller, the step intervals vary depending on which part of ramp you are on.
The term max_velocity
kind of also pointed towards that the api was not really ensuring that the stepper would move with that velocity, was more like a best effort scenario.
I like the step_interval
approach since it allows more granular control, however, does not really apply to these kind of drivers with internal ramp control. Hence this function cannot be supported by the tmc5041 driver.
Would like to hear from @dipakgmx about this as well.
d5c2833
to
5a9daa2
Compare
doc/releases/migration-guide-4.1.rst
Outdated
* Renamed the ``stepper_move`` function to :c:func:`stepper_move_by`. | ||
* Renamed the ``stepper_set_target_position`` function to :c:func:`stepper_move_to`. | ||
* Renamed the ``stepper_set_max_velocity`` function to :c:func:`stepper_set_step_interval`. | ||
The function now takes the step interval in nanoseconds. This allows for a more precise control. | ||
* Changed the :c:func:`stepper_run` to take the step interval in microseconds instead of velocity. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Changed the :c:func:`stepper_run` to take the step interval in microseconds instead of velocity. | |
* Deprecating setting max velocity via :c:func:`stepper_run` . |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
5e9305c
to
7400931
Compare
data->counter_top_cfg.ticks = | ||
DIV_ROUND_UP(counter_us_to_ticks(config->counter, USEC_PER_SEC), velocity); | ||
data->counter_top_cfg.ticks = DIV_ROUND_UP( | ||
counter_get_frequency(config->counter) * step_interval_ns, NSEC_PER_SEC); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This conversion looks good to me. @Irockasingranite @jbehrensnx can you give this a look as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fine to me, its essentially what counter_us_to_ticks actually does behind the scenes, just with ns instead of us
@@ -17,18 +17,18 @@ static void step_counter_top_interrupt(const struct device *dev, void *user_data | |||
stepper_handle_timing_signal(data->dev); | |||
} | |||
|
|||
int step_counter_timing_source_update(const struct device *dev, const uint32_t velocity) | |||
int step_counter_timing_source_update(const struct device *dev, const uint64_t step_interval_ns) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's use microstep in order to avoid ambiguity.
int step_counter_timing_source_update(const struct device *dev, const uint64_t step_interval_ns) | |
int step_counter_timing_source_update(const struct device *dev, const uint64_t microstep_interval_ns) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -70,7 +70,7 @@ struct step_dir_stepper_common_data { | |||
enum stepper_direction direction; | |||
enum stepper_run_mode run_mode; | |||
int32_t actual_position; | |||
uint32_t max_velocity; | |||
uint64_t step_interval_ns; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uint64_t step_interval_ns; | |
uint64_t microstep_interval_ns; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
include/zephyr/drivers/stepper.h
Outdated
*/ | ||
typedef int (*stepper_set_max_velocity_t)(const struct device *dev, | ||
const uint32_t micro_steps_per_second); | ||
typedef int (*stepper_set_step_interval_t)(const struct device *dev, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry that this was not discovered in one of the earlier reviews.
typedef int (*stepper_set_step_interval_t)(const struct device *dev, | |
typedef int (*stepper_set_microstep_interval_t)(const struct device *dev, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
e3bba2b
to
8b413bf
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just this one open point about tmc5041 :)
} | ||
|
||
velocity_fclk = tmc5xxx_calculate_velocity_fclk_from_step_interval(microstep_interval_ns, | ||
clock_frequency); | ||
|
||
err = tmc5041_write(config->controller, TMC5041_VMAX(config->index), velocity_fclk); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we undo the changes to the tmc5041 driver for now. It has an internal ramp controller which takes care of setting step intervals. As can be seen over here converting a step_interval to vmax is kinda not really correct. VMAX is a ramp parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Undid the changes - the header common method is now unused, but I did not remove it just yet.
c79b6e3
to
f6c2c94
Compare
@@ -348,24 +348,6 @@ static int tmc5041_stepper_move_by(const struct device *dev, const int32_t micro | |||
return 0; | |||
} | |||
|
|||
static int tmc5041_stepper_set_max_velocity(const struct device *dev, uint32_t velocity) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's not remove this function for now, I'll create a PR right after this PR is merged exposing this function from the trinamic api. This function is quite relevant for the use-cases where you do not want to set the entire ramp and just want to cut the speed by a certain fraction.
Change the stepper API to instead of changing the stepper speed based on the velocity in microsteps per second to use the delay in usec between successive steps. Also remove the velocity from the `stepper_run` function as typical API usage is enable -> set step interval -> run. Signed-off-by: Fabian Blatz <fabianblatz@gmail.com>
Migrates the peripherals documentation to the new step interval based APi instead of the velocity one. Signed-off-by: Fabian Blatz <fabianblatz@gmail.com>
f6c2c94
to
408ccd2
Compare
Adds a two bullet points explaining the change of the velocity based API towards an step interval one. Signed-off-by: Fabian Blatz <fabianblatz@gmail.com>
408ccd2
to
c42e944
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good :)
As discussed in the original RFC issue: Change the stepper API to accept the interval to wait at a minimum in between executing consequtive steps. This allows for a more granular control then the previous interface.
Resolves #83591