1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! Step/Dir - Universal Stepper Motor Interface
//!
//! Step/Dir aims to provide an interface that abstracts over stepper motor
//! drivers and controllers, exposing high-level hardware features directly
//! where available, or providing software fallbacks where hardware support is
//! lacking.
//!
//! Step/Dir is part of the [Flott] motion control toolkit. Please also check
//! out [RampMaker], a library for generating stepper acceleration ramps. In a
//! future version, both libraries will be integrated, but for now they can be
//! used separately to complement each other.
//!
//! Right now, Step/Dir supports the following drivers:
//!
//! - [DRV8825](crate::drivers::drv8825::DRV8825)
//! - [STSPIN220](crate::drivers::stspin220::STSPIN220)
//!
//! Please check out the documentation of [`Driver`], which is the main entry
//! point to this API.
//!
//! # Example
//!
//! ``` rust
//! # fn main()
//! #     -> Result<
//! #         (),
//! #         step_dir::Error<
//! #             core::convert::Infallible,
//! #             core::convert::Infallible,
//! #             core::convert::Infallible,
//! #         >
//! #     > {
//! #
//! use step_dir::{
//!     embedded_time::duration::Nanoseconds,
//!     Direction, Driver,
//! };
//!
//! // This constant defines how much time there is between two steps. Changing
//! // this value directly affects the speed at which the motor runs.
//! const STEP_DELAY: Nanoseconds = Nanoseconds(500_000);
//!
//! # // Use a real driver to make things easy, without making the example seem
//! # // to specific to one driver.
//! # type MyDriver = step_dir::drivers::drv8825::DRV8825<
//! #     (), (), (), (), (), (), (), (), ()
//! # >;
//! #
//! # struct Pin;
//! # impl step_dir::embedded_hal::digital::OutputPin for Pin {
//! #     type Error = core::convert::Infallible;
//! #     fn try_set_low(&mut self) -> Result<(), Self::Error> { Ok(()) }
//! #     fn try_set_high(&mut self) -> Result<(), Self::Error> { Ok(()) }
//! # }
//! #
//! # struct Timer;
//! # impl step_dir::embedded_hal::timer::CountDown for Timer {
//! #     type Error = core::convert::Infallible;
//! #     type Time = Ticks;
//! #     fn try_start<T>(&mut self, count: T) -> Result<(), Self::Error>
//! #         where T: Into<Self::Time>
//! #     {
//! #         Ok(())
//! #     }
//! #     fn try_wait(&mut self) -> nb::Result<(), Self::Error> {
//! #         Ok(())
//! #     }
//! # }
//! #
//! # struct Ticks;
//! # impl From<Nanoseconds> for Ticks {
//! #     fn from(_: Nanoseconds) -> Self {
//! #         Self
//! #     }
//! # }
//! #
//! # fn delay_ns(_: Nanoseconds) {}
//! #
//! // We need some `embedded_hal::digital::OutputPin` implementations connected
//! // to the STEP and DIR signals of our driver chip. How you acquire those
//! // depends on the platform you run on. Here, we'll use a mock implementation
//! // for the sake of demonstration.
//! let step = Pin;
//! let dir = Pin;
//!
//! // We also need a timer (that implements `embedded_hal::timer::CountDown`),
//! // since there are time-critical aspects to communicating with the driver
//! // chip. Again, how you acquire one depends on your target platform, and
//! // again, we'll use a mock here for the sake of demonstration.
//! let mut timer = Timer;
//!
//! // Now we need to initialize the driver API. We do this by creating a
//! // driver-specific API (`MyDriver`), then wrapping that into the generic API
//! // (`Driver`). `MyDriver` is a placeholder. In a real use-case, you'd
//! // typically use one of the drivers from the `step_dir::drivers` module, but
//! // any driver that implements the traits from `step_dir::traits` will work.
//! //
//! // By default, drivers can't do anything directly after being initialized.
//! // This means they also don't require any hardware resources, which makes
//! // them easier to use when you don't need all features.
//! //
//! // Here, we enable control over the STEP and DIR pins, as we want to step
//! // the motor in a defined direction.
//! let mut driver = Driver::from_inner(MyDriver::new())
//!     .enable_direction_control(dir, Direction::Forward, &mut timer)?
//!     .enable_step_control(step);
//!
//! // Rotate stepper motor by a few steps.
//! for _ in 0 .. 5 {
//!     // The `step` method returns a future. We just use it to block until the
//!     // operation completes, but you can also use the API in a non-blocking
//!     // way.
//!     driver.step(&mut timer).wait()?;
//!
//!     // After telling the driver to make a step, we need to make sure to call
//!     // the step method again after an appropriate amount of time. Let's just
//!     // wait for the right time, using this example `delay_ns` function. How
//!     // you do this in your own code is up to you.
//!     delay_ns(STEP_DELAY - driver.pulse_length());
//! }
//! #
//! # Ok(())
//! # }
//! ```
//!
//! [Flott]: https://flott-motion.org/
//! [RampMaker]: https://crates.io/crates/ramp-maker

#![cfg_attr(not(test), no_std)]
#![deny(missing_docs, broken_intra_doc_links)]

pub extern crate embedded_hal;
pub extern crate embedded_time;

pub mod drivers;
pub mod step_mode;
pub mod traits;

mod driver;

pub use self::driver::*;

/// Defines the direction in which to rotate the motor
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Direction {
    /// Rotate the motor forward
    ///
    /// This corresponds to whatever direction the motor rotates in when the
    /// driver's DIR signal is set HIGH.
    Forward = 1,

    /// Rotate the motor backward
    ///
    /// This corresponds to whatever direction the motor rotates in when the
    /// driver's DIR signal set is LOW.
    Backward = -1,
}