Skip to main content

md22/
lib.rs

1//! Platform-agnostic MD22 motor driver which uses I2C via
2//! [embedded-hal].
3//!
4//! [embedded-hal]: https://docs.rs/embedded-hal
5
6#![forbid(unsafe_code)]
7#![cfg_attr(not(test), no_std)]
8
9
10mod register;
11use embedded_hal as hal;
12use crate::register::Register;
13use core::fmt::Debug;
14use hal::blocking::i2c::{Write, WriteRead};
15
16
17
18#[derive(Clone, Copy)]
19/// Device I2C bus address switch states
20pub enum I2CAddressSwitchState {
21    /// Switch 1 - On, Switch 2 - On, Switch 3 - On, Switch 4 - On, 
22    OnOnOnOn    = 0xB0,
23    /// Switch 1 - Off, Switch 2 - On, Switch 3 - On, Switch 4 - On,
24    OffOnOnOn   = 0xB2,
25    /// Switch 1 - On, Switch 2 - Off, Switch 3 - On, Switch 4 - On,
26    OnOffOnOn   = 0xB4,
27    /// Switch 1 - Off, Switch 2 - Off, Switch 3 - On, Switch 4 - On,
28    OffOffOnOn  = 0xB6,
29    /// Switch 1 - On, Switch 2 - On, Switch 3 - Off, Switch 4 - On,
30    OnOnOffOn   = 0xB8,
31    /// Switch 1 - Off, Switch 2 - On, Switch 3 - Off, Switch 4 - On,
32    OffOnOffOn  = 0xBA,
33    /// Switch 1 - On, Switch 2 - Off, Switch 3 - Off, Switch 4 - On,
34    OnOffOffOn  = 0xBC,
35    /// Switch 1 - Off, Switch 2 - Off, Switch 3 - Off, Switch 4 - On,
36    OffOffOffOn = 0xBE,
37}
38
39impl I2CAddressSwitchState {
40    fn bits(self) -> u8 {
41        self as u8
42    }
43}
44
45#[derive(Clone, Copy)]
46/// I2C operating mode
47pub enum OperatingMode {
48    /// (Default)  The meaning of the speed registers is literal speeds in the range of:  
49    /// - 0 (full reverse)
50    /// - 128 (stop)
51    /// - 255 (full forward)
52    Mode0,
53    /// The speed registers are interpreted as signed values:  
54    /// - -128 (full reverse)
55    /// - 0 (stop)
56    /// - 127 (full forward)
57    Mode1,
58
59}
60
61impl OperatingMode {
62
63    /// Get raw representation of operating mode.
64    pub fn bits(self) -> u8 {
65        self as u8
66    }
67
68    pub fn is_turn_mode(&self) -> bool {
69        match self {
70            OperatingMode::Mode0 | OperatingMode::Mode1 => false,
71            _ => true,
72        }
73    }
74}
75
76/// MD22 Driver
77pub struct Md22<I2C> {
78    /// Comment above struct member
79    i2c: I2C,
80    mode: u8,
81    address: u8,
82}
83
84impl<I2C, E> Md22<I2C>
85where
86    I2C: WriteRead<Error = E> + Write<Error = E>,
87    E: Debug,
88{
89    /// Create a new MD22 driver from the given I2C peripheral and mode.  
90    /// Defaults the speed, acceleration, and turn registers to 0.
91    pub fn new(i2c: I2C, mode: OperatingMode, address: I2CAddressSwitchState) -> Result<Self, E> {
92        let mut md22 = Md22 {
93            i2c: i2c,
94            mode: mode.bits(),
95            address: address.bits()
96        };
97        md22.set_mode(mode)?;
98        md22.set_acceleration(0)?;
99        md22.set_speed(0)?;
100        md22.set_turn(0)?;
101
102        Ok(md22)
103    }
104
105    /// Set the operating mode.
106    pub fn set_mode(&mut self, mode: OperatingMode) -> Result<(), E> {
107        let bytes = [Register::Mode.addr(), mode as u8];
108        self.i2c.write(self.address, &bytes)?;
109        Ok(())
110    }
111
112    /// Set the motor speed register to the specified value.
113    pub fn set_speed(&mut self, speed: u8) -> Result<(), E> {
114        let bytes = [Register::Speed.addr(), speed];
115        self.i2c.write(self.address, &bytes)?;
116        Ok(())
117    }
118
119    /// Set the motor turn register to the specified value.
120    pub fn set_turn(&mut self, turn: u8) -> Result<(), E> {
121        let bytes = [Register::Turn.addr(), turn];
122        self.i2c.write(self.address, &bytes)?;
123        Ok(())
124    }
125
126    /// Set the motor acceleration register to the specified value.  
127    /// The acceleration time is given by this value * 64us * n_steps.
128    pub fn set_acceleration(&mut self, acceleration: u8) -> Result<(), E> {
129        let bytes = [Register::Acceleration.addr(), acceleration];
130        self.i2c.write(self.address, &bytes)?;
131        Ok(())
132    }
133    
134    pub fn get_software_revision(&mut self) -> Result<u8, E> {
135        let bytes = [Register::SoftwareRevision.addr()];
136        let mut buffer: [u8;1] = [0;1];
137        self.i2c.write_read(self.address, &bytes, &mut buffer)?;
138        Ok(buffer[0])
139    }
140}
141
142
143#[cfg(test)]
144mod tests {
145
146    
147    use crate::*;
148
149    use embedded_hal_mock as hal;
150
151    #[test]
152    fn get_software_revision() {
153        let address = I2CAddressSwitchState::OnOnOnOn;
154        let expectation = [
155            hal::i2c::Transaction::write(address.bits(), vec![Register::Mode.addr(), 0]),
156            hal::i2c::Transaction::write(address.bits(), vec![Register::Acceleration.addr(), 0]),
157            hal::i2c::Transaction::write(address.bits(), vec![Register::Speed.addr(), 0]),
158            hal::i2c::Transaction::write(address.bits(), vec![Register::Turn.addr(), 0]),
159            hal::i2c::Transaction::write_read(address.bits(), vec![Register::SoftwareRevision.addr()], vec![255]),
160        ];
161        let i2c = hal::i2c::Mock::new(&expectation);
162        let mut md22 = Md22::new(i2c, OperatingMode::Mode0, address).unwrap();
163        assert_eq!(255, md22.get_software_revision().unwrap());
164    }
165
166    #[test]
167    fn set_mode() {
168        let address = I2CAddressSwitchState::OnOnOnOn;
169        let expectation = [
170            hal::i2c::Transaction::write(address.bits(), vec![Register::Mode.addr(), 0]),
171            hal::i2c::Transaction::write(address.bits(), vec![Register::Acceleration.addr(), 0]),
172            hal::i2c::Transaction::write(address.bits(), vec![Register::Speed.addr(), 0]),
173            hal::i2c::Transaction::write(address.bits(), vec![Register::Turn.addr(), 0]),
174            hal::i2c::Transaction::write(address.bits(), vec![Register::Mode.addr(), OperatingMode::Mode1.bits()]),
175        ];
176        let i2c = hal::i2c::Mock::new(&expectation);
177        let mut md22 = Md22::new(i2c, OperatingMode::Mode0, address).unwrap();
178        md22.set_mode(OperatingMode::Mode1).unwrap();
179    }
180    
181    #[test]
182    fn set_acceleration() {
183        let address = I2CAddressSwitchState::OnOnOnOn;
184        let expectation = [
185            hal::i2c::Transaction::write(address.bits(), vec![Register::Mode.addr(), 0]),
186            hal::i2c::Transaction::write(address.bits(), vec![Register::Acceleration.addr(), 0]),
187            hal::i2c::Transaction::write(address.bits(), vec![Register::Speed.addr(), 0]),
188            hal::i2c::Transaction::write(address.bits(), vec![Register::Turn.addr(), 0]),
189            hal::i2c::Transaction::write(address.bits(), vec![Register::Acceleration.addr(), 255]),
190        ];
191        let i2c = hal::i2c::Mock::new(&expectation);
192        let mut md22 = Md22::new(i2c, OperatingMode::Mode0, address).unwrap();
193        md22.set_acceleration(255).unwrap();
194    }
195
196    #[test]
197    fn set_speed() {
198        let address = I2CAddressSwitchState::OnOnOnOn;
199        let expectation = [
200            hal::i2c::Transaction::write(address.bits(), vec![Register::Mode.addr(), 0]),
201            hal::i2c::Transaction::write(address.bits(), vec![Register::Acceleration.addr(), 0]),
202            hal::i2c::Transaction::write(address.bits(), vec![Register::Speed.addr(), 0]),
203            hal::i2c::Transaction::write(address.bits(), vec![Register::Turn.addr(), 0]),
204            hal::i2c::Transaction::write(address.bits(), vec![Register::Speed.addr(), 255]),
205        ];
206        let i2c = hal::i2c::Mock::new(&expectation);
207        let mut md22 = Md22::new(i2c, OperatingMode::Mode0, address).unwrap();
208        md22.set_speed(255).unwrap();
209    }
210
211    #[test]
212    fn set_turn() {
213        let address = I2CAddressSwitchState::OnOnOnOn;
214        let expectation = [
215            hal::i2c::Transaction::write(address.bits(), vec![Register::Mode.addr(), 0]),
216            hal::i2c::Transaction::write(address.bits(), vec![Register::Acceleration.addr(), 0]),
217            hal::i2c::Transaction::write(address.bits(), vec![Register::Speed.addr(), 0]),
218            hal::i2c::Transaction::write(address.bits(), vec![Register::Turn.addr(), 0]),
219            hal::i2c::Transaction::write(address.bits(), vec![Register::Turn.addr(), 255]),
220        ];
221        let i2c = hal::i2c::Mock::new(&expectation);
222        let mut md22 = Md22::new(i2c, OperatingMode::Mode0, address).unwrap();
223        md22.set_turn(255).unwrap();
224    }
225}