drv2605_async/
lib.rs

1#![cfg_attr(not(test), no_std)]
2
3use bitfield::bitfield;
4use embedded_hal_async::i2c::I2c;
5
6bitfield! {
7    pub struct StatusReg(u8);
8    impl Debug;
9    /// Latching overcurrent detection flag.  If the load impedance is below
10    /// the load-impedance threshold, the device shuts down and periodically
11    /// attempts to restart until the impedance is above the threshold
12    pub oc_detected, _: 0;
13    /// Latching overtemperature detection flag. If the device becomes too hot,
14    /// it shuts down. This bit clears upon read.
15    pub over_temp, _: 1;
16    /// Contains status for the feedback controller. This indicates when the ERM
17    /// back-EMF has been zero for more than ~10 ms in ERM mode, and
18    /// indicates when the LRA frequency tracking has lost frequency lock in LRA
19    /// mode. This bit is for debug purposes only, and may sometimes be set
20    /// under normal operation when extensive braking periods are used. This bit
21    /// will clear upon read.
22    pub feedback_controller_timed_out, _: 2;
23    /// This flag stores the result of the auto-calibration routine and the diagnostic
24    /// routine. The flag contains the result for whichever routine was executed
25    /// last. The flag clears upon read. Test result is not valid until the GO bit self-
26    /// clears at the end of the routine.
27    /// Auto-calibration mode:
28    /// 0: Auto-calibration passed (optimum result converged)
29    /// 1: Auto-calibration failed (result did not converge)
30    /// Diagnostic mode:
31    /// 0: Actuator is functioning normally
32    /// 1: Actuator is not present or is shorted, timing out, or giving
33    /// out–of-range back-EMF.
34    pub diagnostic_result, _: 3;
35    /// Device identifier. The DEVICE_ID bit indicates the part number to the user.
36    /// The user software can ascertain the device capabilities by reading this
37    /// register.
38    /// 4: DRV2604 (contains RAM, does not contain licensed ROM library)
39    /// 3: DRV2605 (contains licensed ROM library, does not contain RAM)
40    /// 6: DRV2604L (low-voltage version of the DRV2604 device)
41    /// 7: DRV2605L (low-voltage version of the DRV2605 device)
42    pub device_id, _: 7, 5;
43}
44
45#[derive(Debug, Clone, Copy)]
46pub enum Mode {
47    /// Waveforms are fired by setting the GO bit in register 0x0C.
48    InternalTrigger = 0,
49    /// A rising edge on the IN/TRIG pin sets the GO Bit. A second rising
50    /// edge on the IN/TRIG pin cancels the waveform if the second rising
51    /// edge occurs before the GO bit has cleared.
52    ExternalTriggerRisingEdge = 1,
53    /// The GO bit follows the state of the external trigger. A rising edge on
54    /// the IN/TRIG pin sets the GO bit, and a falling edge sends a cancel. If
55    /// the GO bit is already in the appropriate state, no change occurs.
56    ExternalTriggerLevelMode = 2,
57    /// A PWM or analog signal is accepted at the IN/TRIG pin and used as
58    /// the driving source. The device actively drives the actuator while in
59    /// this mode. The PWM or analog input selection occurs by using the
60    /// N_PWM_ANALOG bit.
61    PwmInputAndAnalogInput = 3,
62    /// An AC-coupled audio signal is accepted at the IN/TRIG pin. The
63    /// device converts the audio signal into meaningful haptic vibration. The
64    /// AC_COUPLE and N_PWM_ANALOG bits should also be set.
65    AudioToVibe = 4,
66    /// The device actively drives the actuator with the contents of the
67    /// RTP_INPUT\[7:0\] bit in register 0x02.
68    RealTimePlayback = 5,
69    /// Set the device in this mode to perform a diagnostic test on the
70    /// actuator. The user must set the GO bit to start the test. The test is
71    /// complete when the GO bit self-clears. Results are stored in the
72    /// DIAG_RESULT bit in register 0x00.
73    Diagnostics = 6,
74    /// Set the device in this mode to auto calibrate the device for the
75    /// actuator. Before starting the calibration, the user must set the all
76    /// required input parameters. The user must set the GO bit to start the
77    /// calibration. Calibration is complete when the GO bit self-clears.
78    AutoCalibration = 7,
79}
80
81impl From<u8> for Mode {
82    fn from(val: u8) -> Mode {
83        match val {
84            0 => Mode::InternalTrigger,
85            1 => Mode::ExternalTriggerRisingEdge,
86            2 => Mode::ExternalTriggerLevelMode,
87            3 => Mode::PwmInputAndAnalogInput,
88            4 => Mode::AudioToVibe,
89            5 => Mode::RealTimePlayback,
90            6 => Mode::Diagnostics,
91            7 => Mode::AutoCalibration,
92            _ => unreachable!("impossible value read back from Mode register"),
93        }
94    }
95}
96
97bitfield! {
98    pub struct ModeReg(u8);
99    impl Debug;
100    /// Device reset. Setting this bit performs the equivalent operation of power
101    /// cycling the device. Any playback operations are immediately interrupted,
102    /// and all registers are reset to the default values. The DEV_RESET bit self-
103    /// clears after the reset operation is complete.
104    pub dev_reset, set_dev_reset: 7;
105
106    /// Software standby mode
107    /// 0: Device ready
108    /// 1: Device in software standby
109    pub standby, set_standby: 6;
110
111    /// The `Mode`
112    pub into Mode, mode, set_mode: 2, 0;
113}
114
115#[derive(Debug, Clone, Copy)]
116pub enum LibrarySelection {
117    Empty = 0,
118    A = 1,
119    B = 2,
120    C = 3,
121    D = 4,
122    E = 5,
123    LRA = 6,
124    Reserved = 7,
125}
126
127impl From<u8> for LibrarySelection {
128    fn from(val: u8) -> LibrarySelection {
129        match val {
130            0 => LibrarySelection::Empty,
131            1 => LibrarySelection::A,
132            2 => LibrarySelection::B,
133            3 => LibrarySelection::C,
134            4 => LibrarySelection::D,
135            5 => LibrarySelection::E,
136            6 => LibrarySelection::LRA,
137            7 => LibrarySelection::Reserved,
138            _ => unreachable!("impossible LibrarySelection value"),
139        }
140    }
141}
142
143bitfield! {
144    pub struct RegisterThree(u8);
145    impl Debug;
146    /// This bit sets the output driver into a true high-impedance state. The device
147    /// must be enabled to go into the high-impedance state. When in hardware
148    /// shutdown or standby mode, the output drivers have 15 kΩ to ground. When
149    /// the HI_Z bit is asserted, the hi-Z functionality takes effect immediately, even
150    /// if a transaction is taking place.
151    pub hi_z, set_hi_z: 4;
152
153    /// Waveform library selection value. This bit determines which library the
154    /// playback engine selects when the GO bit is set.
155    pub into LibrarySelection, library_selection, set_library_selection: 2, 0;
156}
157
158/// Identifies which of the waveforms from the ROM library that should
159/// be played in a given waveform slot.
160#[derive(Debug, Clone, Copy)]
161pub enum Effect {
162    /// Strong Click - 100%
163    StrongClick100 = 1,
164    /// Strong Click - 60%
165    StrongClick60 = 2,
166    /// Strong Click - 30%
167    StrongClick30 = 3,
168    /// Sharp Click - 100%
169    SharpClick100 = 4,
170    /// Sharp Click - 60%
171    SharpClick60 = 5,
172    /// Sharp Click - 30%
173    SharpClick30 = 6,
174    /// Soft Bump - 100%
175    SoftBump100 = 7,
176    /// Soft Bump - 60%
177    SoftBump60 = 8,
178    /// Soft Bump - 30%
179    SoftBump30 = 9,
180    /// Double Click - 100%
181    DoubleClick100 = 10,
182    /// Double Click - 60%
183    DoubleClick60 = 11,
184    /// Triple Click - 100%
185    TripleClick100 = 12,
186    /// Soft Fuzz - 60%
187    SoftFuzz60 = 13,
188    /// Strong Buzz - 100%
189    StrongBuzz100 = 14,
190    /// 750 ms Alert 100%
191    Alert750ms = 15,
192    /// 1000 ms Alert 100%
193    Alert1000ms = 16,
194    /// Strong Click 1 - 100%
195    StrongClickOne100 = 17,
196    /// Strong Click 2 - 80%
197    StrongClickTwo80 = 18,
198    /// Strong Click 3 - 60%
199    StrongClickThree60 = 19,
200    /// Strong Click 4 - 30%
201    StrongClickFour30 = 20,
202    /// Medium Click 1 - 100%
203    MediumClickOne100 = 21,
204    /// Medium Click 2 - 80%
205    MediumClickTwo80 = 22,
206    /// Medium Click 3 - 60%
207    MediumClickThree60 = 23,
208    /// Sharp Tick 1 - 100%
209    SharpTickOne100 = 24,
210    /// Sharp Tick 2 - 80%
211    SharpTickTwo80 = 25,
212    /// Sharp Tick 3 - 60%
213    SharpTickThree60 = 26,
214    /// Short Double Click Strong 1 - 100%
215    ShortDoubleClickStrongOne100 = 27,
216    /// Short Double Click Strong 2 - 80%
217    ShortDoubleClickStrongTwo80 = 28,
218    /// Short Double Click Strong 3 - 60%
219    ShortDoubleClickStrongThree60 = 29,
220    /// Short Double Click Strong 4 - 30%
221    ShortDoubleClickStrongFour30 = 30,
222    /// Short Double Click Medium 1 - 100%
223    ShortDoubleClickMediumOne100 = 31,
224    /// Short Double Click Medium 2 - 80%
225    ShortDoubleClickMediumTwo80 = 32,
226    /// Short Double Click Medium 3 - 60%
227    ShortDoubleClickMediumThree60 = 33,
228    /// Short Double Sharp Tick 1 - 100%
229    ShortDoubleSharpTickOne100 = 34,
230    /// Short Double Sharp Tick 2 - 80%
231    ShortDoubleSharpTickTwo80 = 35,
232    /// Short Double Sharp Tick 3 - 60%
233    ShortDoubleSharpTickThree60 = 36,
234    /// Long Double Sharp Click Strong 1 - 100%
235    LongDoubleSharpClickStrongOne100 = 37,
236    /// Long Double Sharp Click Strong 2 - 80%
237    LongDoubleSharpClickStrongTwo80 = 38,
238    /// Long Double Sharp Click Strong 3 - 60%
239    LongDoubleSharpClickStrongThree60 = 39,
240    /// Long Double Sharp Click Strong 4 - 30%
241    LongDoubleSharpClickStrongFour30 = 40,
242    /// Long Double Sharp Click Medium 1 - 100%
243    LongDoubleSharpClickMediumOne100 = 41,
244    /// Long Double Sharp Click Medium 2 - 80%
245    LongDoubleSharpClickMediumTwo80 = 42,
246    /// Long Double Sharp Click Medium 3 - 60%
247    LongDoubleSharpClickMediumThree60 = 43,
248    /// Long Double Sharp Tick 1 - 100%
249    LongDoubleSharpTickOne100 = 44,
250    /// Long Double Sharp Tick 2 - 80%
251    LongDoubleSharpTickTwo80 = 45,
252    /// Long Double Sharp Tick 3 - 60%
253    LongDoubleSharpTickThree60 = 46,
254    /// Buzz 1 - 100%
255    BuzzOne100 = 47,
256    /// Buzz 2 - 80%
257    BuzzTwo80 = 48,
258    /// Buzz 3 - 60%
259    BuzzThree60 = 49,
260    /// Buzz 4 - 40%
261    BuzzFour40 = 50,
262    /// Buzz 5 - 20%
263    BuzzFive20 = 51,
264    /// Pulsing Strong 1 - 100%
265    PulsingStrongOne100 = 52,
266    /// Pulsing Strong 2 - 60%
267    PulsingStrongTwo60 = 53,
268    /// Pulsing Medium 1 - 100%
269    PulsingMediumOne100 = 54,
270    /// Pulsing Medium 2 - 60%
271    PulsingMediumTwo60 = 55,
272    /// Pulsing Sharp 1 - 100%
273    PulsingSharpOne100 = 56,
274    /// Pulsing Sharp 2 - 60%
275    PulsingSharpTwo60 = 57,
276    /// Transition Click 1 - 100%
277    TransitionClickOne100 = 58,
278    /// Transition Click 2 - 80%
279    TransitionClickTwo80 = 59,
280    /// Transition Click 3 - 60%
281    TransitionClickThree60 = 60,
282    /// Transition Click 4 - 40%
283    TransitionClickFour40 = 61,
284    /// Transition Click 5 - 20%
285    TransitionClickFive20 = 62,
286    /// Transition Click 6 - 10%
287    TransitionClickSix10 = 63,
288    /// Transition Hum 1 - 100%
289    TransitionHumOne100 = 64,
290    /// Transition Hum 2 - 80%
291    TransitionHumTwo80 = 65,
292    /// Transition Hum 3 - 60%
293    TransitionHumThree60 = 66,
294    /// Transition Hum 4 - 40%
295    TransitionHumFour40 = 67,
296    /// Transition Hum 5 - 20%
297    TransitionHumFive20 = 68,
298    /// Transition Hum 6 - 10%
299    TransitionHumSix10 = 69,
300    /// Transition Ramp Down Long Smooth 1 - 100 to 0%
301    TransitionRampDownLongSmoothOne100to0 = 70,
302    /// Transition Ramp Down Long Smooth 2 - 100 to 0%
303    TransitionRampDownLongSmoothTwo100to0 = 71,
304    /// Transition Ramp Down Medium Smooth 1 - 100 to 0%
305    TransitionRampDownMediumSmoothOne100to0 = 72,
306    /// Transition Ramp Down Medium Smooth 2 - 100 to 0%
307    TransitionRampDownMediumSmoothTwo100to0 = 73,
308    /// Transition Ramp Down Short Smooth 1 - 100 to 0%
309    TransitionRampDownShortSmoothOne100to0 = 74,
310    /// Transition Ramp Down Short Smooth 2 - 100 to 0%
311    TransitionRampDownShortSmoothTwo100to0 = 75,
312    /// Transition Ramp Down Long Sharp 1 - 100 to 0%
313    TransitionRampDownLongSharpOne100to0 = 76,
314    /// Transition Ramp Down Long Sharp 2 - 100 to 0%
315    TransitionRampDownLongSharpTwo100to0 = 77,
316    /// Transition Ramp Down Medium Sharp 1 - 100 to 0%
317    TransitionRampDownMediumSharpOne100to0 = 78,
318    /// Transition Ramp Down Medium Sharp 2 - 100 to 0%
319    TransitionRampDownMediumSharpTwo100to0 = 79,
320    /// Transition Ramp Down Short Sharp 1 - 100 to 0%
321    TransitionRampDownShortSharpOne100to0 = 80,
322    /// Transition Ramp Down Short Sharp 2 - 100 to 0%
323    TransitionRampDownShortSharpTwo100to0 = 81,
324    /// Transition Ramp Up Long Smooth 1 - 0 to 100%
325    TransitionRampUpLongSmoothOne0to100 = 82,
326    /// Transition Ramp Up Long Smooth 2 - 0 to 100%
327    TransitionRampUpLongSmoothTwo0to100 = 83,
328    /// Transition Ramp Up Medium Smooth 1 - 0 to 100%
329    TransitionRampUpMediumSmoothOne0to100 = 84,
330    /// Transition Ramp Up Medium Smooth 2 - 0 to 100%
331    TransitionRampUpMediumSmoothTwo0to100 = 85,
332    /// Transition Ramp Up Short Smooth 1 - 0 to 100%
333    TransitionRampUpShortSmoothOne0to100 = 86,
334    /// Transition Ramp Up Short Smooth 2 - 0 to 100%
335    TransitionRampUpShortSmoothTwo0to100 = 87,
336    /// Transition Ramp Up Long Sharp 1 - 0 to 100%
337    TransitionRampUpLongSharpOne0to100 = 88,
338    /// Transition Ramp Up Long Sharp 2 - 0 to 100%
339    TransitionRampUpLongSharpTwo0to100 = 89,
340    /// Transition Ramp Up Medium Sharp 1 - 0 to 100%
341    TransitionRampUpMediumSharpOne0to100 = 90,
342    /// Transition Ramp Up Medium Sharp 2 - 0 to 100%
343    TransitionRampUpMediumSharpTwo0to100 = 91,
344    /// Transition Ramp Up Short Sharp 1 - 0 to 100%
345    TransitionRampUpShortSharpOne0to100 = 92,
346    /// Transition Ramp Up Short Sharp 2 - 0 to 100%
347    TransitionRampUpShortSharpTwo0to100 = 93,
348    /// Transition Ramp Down Long Smooth 1 - 50 to 0%
349    TransitionRampDownLongSmoothOne50to0 = 94,
350    /// Transition Ramp Down Long Smooth 2 - 50 to 0%
351    TransitionRampDownLongSmoothTwo50to0 = 95,
352    /// Transition Ramp Down Medium Smooth 1 - 50 to 0%
353    TransitionRampDownMediumSmoothOne50to0 = 96,
354    /// Transition Ramp Down Medium Smooth 2 - 50 to 0%
355    TransitionRampDownMediumSmoothTwo50to0 = 97,
356    /// Transition Ramp Down Short Smooth 1 - 50 to 0%
357    TransitionRampDownShortSmoothOne50to0 = 98,
358    /// Transition Ramp Down Short Smooth 2 - 50 to 0%
359    TransitionRampDownShortSmoothTwo50to0 = 99,
360    /// Transition Ramp Down Long Sharp 1 - 50 to 0%
361    TransitionRampDownLongSharpOne50to0 = 100,
362    /// Transition Ramp Down Long Sharp 2 - 50 to 0%
363    TransitionRampDownLongSharpTwo50to0 = 101,
364    /// Transition Ramp Down Medium Sharp 1 - 50 to 0%
365    TransitionRampDownMediumSharpOne50to0 = 102,
366    /// Transition Ramp Down Medium Sharp 2 - 50 to 0%
367    TransitionRampDownMediumSharpTwo50to0 = 103,
368    /// Transition Ramp Down Short Sharp 1 - 50 to 0%
369    TransitionRampDownShortSharpOne50to0 = 104,
370    /// Transition Ramp Down Short Sharp 2 - 50 to 0%
371    TransitionRampDownShortSharpTwo50to0 = 105,
372    /// Transition Ramp Up Long Smooth 1 - 0 to 50%
373    TransitionRampUpLongSmoothOne0to50 = 106,
374    /// Transition Ramp Up Long Smooth 2 - 0 to 50%
375    TransitionRampUpLongSmoothTwo0to50 = 107,
376    /// Transition Ramp Up Medium Smooth 1 - 0 to 50%
377    TransitionRampUpMediumSmoothOne0to50 = 108,
378    /// Transition Ramp Up Medium Smooth 2 - 0 to 50%
379    TransitionRampUpMediumSmoothTwo0to50 = 109,
380    /// Transition Ramp Up Short Smooth 1 - 0 to 50%
381    TransitionRampUpShortSmoothOne0to50 = 110,
382    /// Transition Ramp Up Short Smooth 2 - 0 to 50%
383    TransitionRampUpShortSmoothTwo0to50 = 111,
384    /// Transition Ramp Up Long Sharp 1 - 0 to 50%
385    TransitionRampUpLongSharpOne0to50 = 112,
386    /// Transition Ramp Up Long Sharp 2 - 0 to 50%
387    TransitionRampUpLongSharpTwo0to50 = 113,
388    /// Transition Ramp Up Medium Sharp 1 - 0 to 50%
389    TransitionRampUpMediumSharpOne0to50 = 114,
390    /// Transition Ramp Up Medium Sharp 2 - 0 to 50%
391    TransitionRampUpMediumSharpTwo0to50 = 115,
392    /// Transition Ramp Up Short Sharp 1 - 0 to 50%
393    TransitionRampUpShortSharpOne0to50 = 116,
394    /// Transition Ramp Up Short Sharp 2 - 0 to 50%
395    TransitionRampUpShortSharpTwo0to50 = 117,
396    /// Long Buzz For Programmatic Stopping - 100%
397    LongBuzzForProgrammaticStopping100 = 118,
398    /// Smooth Hum 1 (No kick or brake pulse) - 50%
399    SmoothHumOne50 = 119,
400    /// Smooth Hum 2 (No kick or brake pulse) - 40%
401    SmoothHumTwo40 = 120,
402    /// Smooth Hum 3 (No kick or brake pulse) - 30%
403    SmoothHumThree30 = 121,
404    /// Smooth Hum 4 (No kick or brake pulse) - 20%
405    SmoothHumFour20 = 122,
406    /// Smooth Hum 5 (No kick or brake pulse) - 10%
407    SmoothHumFive10 = 123,
408}
409
410bitfield! {
411    pub struct WaveformReg(u8);
412    impl Debug;
413    /// When this bit is set, the WAV_FRM_SEQ[6:0] bit is interpreted as a wait
414    /// time in which the playback engine idles. This bit is used to insert timed
415    /// delays between sequentially played waveforms.
416    /// Delay time = 10 ms × WAV_FRM_SEQ[6:0]
417    /// If WAIT = 0, then WAV_FRM_SEQ[6:0] is interpreted as a waveform
418    /// identifier for sequence playback.
419    wait, set_wait: 7;
420
421    /// Waveform sequence value. This bit holds the waveform identifier of the
422    /// waveform to be played. A waveform identifier is an integer value referring
423    /// to the index position of a waveform in a ROM library. Playback begins at
424    /// register address 0x04 when the user asserts the GO bit (register 0x0C).
425    /// When playback of that waveform ends, the waveform sequencer plays the
426    /// next waveform identifier held in register 0x05, if the next waveform
427    /// identifier is non-zero. The waveform sequencer continues in this way until
428    /// the sequencer reaches an identifier value of zero, or all eight identifiers are
429    /// played (register addresses 0x04 through 0x0B), whichever comes first.
430    waveform_seq, set_waveform_seq: 6, 0;
431}
432
433impl WaveformReg {
434    /// Stops playing the sequence of effects
435    pub fn new_stop() -> Self {
436        let mut w = WaveformReg(0);
437        w.set_wait(false);
438        w.set_waveform_seq(0);
439        w
440    }
441
442    /// Set the effect
443    pub fn new_effect(effect: Effect) -> Self {
444        let mut w = WaveformReg(0);
445        w.set_wait(false);
446        w.set_waveform_seq(effect as u8);
447        w
448    }
449
450    /// Wait the specified amount of time (in 10ms intervals), before
451    /// moving to the next effect and playing it.
452    pub fn new_wait_time(tens_of_ms: u8) -> Self {
453        let mut w = WaveformReg(0);
454        w.set_wait(true);
455        w.set_waveform_seq(tens_of_ms);
456        w
457    }
458}
459
460bitfield! {
461    pub struct GoReg(u8);
462    impl Debug;
463    /// This bit is used to fire processes in the DRV2605 device. The process
464    /// fired by the GO bit is selected by the MODE[2:0] bit (register 0x01). The
465    /// primary function of this bit is to fire playback of the waveform identifiers in
466    /// the waveform sequencer (registers 0x04 to 0x0B), in which case, this bit
467    /// can be thought of a software trigger for haptic waveforms. The GO bit
468    /// remains high until the playback of the haptic waveform sequence is
469    /// complete. Clearing the GO bit during waveform playback cancels the
470    /// waveform sequence. Using one of the external trigger modes can cause
471    /// the GO bit to be set or cleared by the external trigger pin. This bit can also
472    /// be used to fire the auto-calibration process or the diagnostic process.
473    pub go, set_go: 0;
474}
475
476bitfield! {
477    pub struct FeedbackControlReg(u8);
478    impl Debug;
479
480    /// This bit sets the DRV2605 device in ERM or LRA mode. This bit should be set
481    /// prior to running auto calibration.
482    /// 0: ERM Mode
483    /// 1: LRA Mode
484    pub n_erm_lra, set_n_erm_lra: 7;
485
486    /// This bit selects the feedback gain ratio between braking gain and driving gain.
487    /// In general, adding additional feedback gain while braking is desirable so that the
488    /// actuator brakes as quickly as possible. Large ratios provide less-stable
489    /// operation than lower ones. The advanced user can select to optimize this
490    /// register. Otherwise, the default value should provide good performance for most
491    /// actuators. This value should be set prior to running auto calibration.
492    /// 0: 1x
493    /// 1: 2x
494    /// 2: 3x
495    /// 3: 4x
496    /// 4: 6x
497    /// 5: 8x
498    /// 6: 16x
499    /// 7: Braking disabled
500    pub fb_brake_factor, set_fb_brake_factor: 6, 4;
501
502    /// This bit selects a loop gain for the feedback control. The LOOP_GAIN[1:0] bit
503    /// sets how fast the loop attempts to make the back-EMF (and thus motor velocity)
504    /// match the input signal level. Higher loop-gain (faster settling) options provide
505    /// less-stable operation than lower loop gain (slower settling). The advanced user
506    /// can select to optimize this register. Otherwise, the default value should provide
507    /// good performance for most actuators. This value should be set prior to running
508    /// auto calibration.
509    /// 0: Low
510    /// 1: Medium (default)
511    /// 2: High
512    /// 3: Very High
513    pub loop_gain, set_loop_gain: 3, 2;
514
515    /// This bit sets the analog gain of the back-EMF amplifier. This value is interpreted
516    /// differently between ERM mode and LRA mode. Auto calibration automatically
517    /// populates the BEMF_GAIN bit with the most appropriate value for the actuator.
518    /// ERM Mode
519    /// 0: 0.33x
520    /// 1: 1.0x
521    /// 2: 1.8x (default)
522    /// 3: 4.0x
523    /// LRA Mode
524    /// 0: 5x
525    /// 1: 10x
526    /// 2: 20x (default)
527    /// 3: 30x
528    pub bemf_gain, set_bemf_gain: 1, 0;
529}
530
531bitfield! {
532    pub struct Control1Reg(u8);
533    impl Debug;
534    /// This bit applies higher loop gain during overdrive to enhance actuator transient response.
535    pub startup_boost, set_startup_boost: 7;
536    /// This bit applies a 0.9-V common mode voltage to the IN/TRIG pin when an AC-
537    /// coupling capacitor is used. This bit is only useful for analog input mode. This bit
538    /// should not be asserted for PWM mode or external trigger mode.
539    /// 0: Common-mode drive disabled for DC-coupling or digital inputs modes
540    /// 1: Common-mode drive enabled for AC coupling
541    pub ac_couple, set_ac_couple: 5;
542    /// LRA Mode: Sets initial guess for LRA drive-time in LRA mode. Drive time is
543    /// automatically adjusted for optimum drive in real time; however, this register
544    /// should be optimized for the approximate LRA frequency. If the bit is set too low,
545    /// it can affect the actuator startup time. If it is set too high, it can cause instability.
546    /// Optimum drive time (ms) ≈ 0.5 × LRA Period
547    /// Drive time (ms) = DRIVE_TIME[4:0] × 0.1 ms + 0.5 ms
548    /// ERM Mode: Sets the sample rate for the back-EMF detection. Lower drive times
549    /// cause higher peak-to-average ratios in the output signal, requiring more supply
550    /// headroom. Higher drive times cause the feedback to react at a slower rate.
551    /// Drive Time (ms) = DRIVE_TIME[4:0] × 0.2 ms + 1 ms
552    pub drive_time, set_drive_time: 4, 0;
553}
554
555bitfield! {
556    pub struct Control2Reg(u8);
557    impl Debug;
558    /// The BIDIR_INPUT bit selects how the engine interprets data.
559    /// 0: Unidirectional input mode
560    /// Braking is automatically determined by the feedback conditions and is
561    /// applied when needed. Use of this mode also recovers an additional bit
562    /// of vertical resolution. This mode should only be used for closed-loop
563    /// operation.
564    /// Examples::
565    /// 0% Input -> No output signal
566    /// 50% Input -> Half-scale output signal
567    /// 100% Input -> Full-scale output signal
568    /// 1: Bidirectional input mode (default)
569    /// This mode is compatible with traditional open-loop signaling and also
570    /// works well with closed-loop mode. When operating closed-loop, braking
571    /// is automatically determined by the feedback conditions and applied
572    /// when needed. When operating open-loop modes, braking is only
573    /// applied when the input signal is less than 50%.
574    /// Open-loop mode (ERM and LRA) examples:
575    /// 0% Input -> Negative full-scale output signal (braking)
576    /// 25% Input -> Negative half-scale output signal (braking)
577    /// 50% Input -> No output signal
578    /// 75% Input -> Positive half-scale output signal
579    /// 100% Input -> Positive full-scale output signal
580    /// Closed-loop mode (ERM and LRA) examples:
581    /// 0% to 50% Input -> No output signal
582    /// 50% Input -> No output signal
583    /// 75% Input -> Half-scale output signal
584    /// 100% Input -> Full-scale output signal
585    pub bidir_input, set_bidir_input: 7;
586    /// When this bit is set, loop gain is reduced when braking is almost complete to
587    /// improve loop stability
588    pub brake_stabilizer, set_brake_stabilizer: 6;
589    /// LRA auto-resonance sampling time (Advanced use only)
590    /// 0: 150 us
591    /// 1: 200 us
592    /// 2: 250 us
593    /// 3: 300 us
594    pub sample_time, set_sample_time: 5, 4;
595    /// Blanking time before the back-EMF AD makes a conversion. (Advanced use only)
596    pub blanking_time, set_blanking_time: 3, 2;
597    /// Current dissipation time. This bit is the time allowed for the current to dissipate
598    /// from the actuator between PWM cycles for flyback mitigation. (Advanced use
599    /// only)
600    pub idiss_time, set_idiss_time: 1, 0;
601}
602
603bitfield! {
604    pub struct Control3Reg(u8);
605    impl Debug;
606
607    /// This bit is the noise-gate threshold for PWM and analog inputs.
608    /// 0: Disabled
609    /// 1: 2%
610    /// 2: 4% (Default)
611    /// 3: 8%
612    pub ng_thresh, set_ng_thresh: 7, 6;
613    /// This bit selects mode of operation while in ERM mode. Closed-loop operation is
614    /// usually desired for because of automatic overdrive and braking properties.
615    /// However, many existing waveform libraries were designed for open-loop
616    /// operation, so open-loop operation may be required for compatibility.
617    /// 0: Closed Loop
618    /// 1: Open Loop
619    pub erm_open_loop, set_erm_open_loop: 5;
620    /// This bit disables supply compensation. The DRV2605 device generally provides
621    /// constant drive output over variation in the power supply input (V DD ). In some
622    /// systems, supply compensation may have already been implemented upstream,
623    /// so disabling the DRV2605 supply compensation can be useful.
624    /// 0: Supply compensation enabled
625    /// 1: Supply compensation disabled
626    pub supply_comp_dis, set_supply_comp_dis: 4;
627    /// This bit selects the input data interpretation for RTP (Real-Time Playback)
628    /// mode.
629    /// 0: Signed
630    /// 1: Unsigned
631    pub data_format_rtp, set_data_format_rtp: 3;
632    /// This bit selects the drive mode for the LRA algorithm. This bit determines how
633    /// often the drive amplitude is updated. Updating once per cycle provides a
634    /// symmetrical output signal, while updating twice per cycle provides more precise
635    /// control.
636    /// 0: Once per cycle
637    /// 1: Twice per cycle
638    pub lra_drive_mode, set_lra_drive_mode: 2;
639    /// This bit selects the input mode for the IN/TRIG pin when MODE[2:0] = 3. In
640    /// PWM input mode, the duty cycle of the input signal determines the amplitude of
641    /// the waveform. In analog input mode, the amplitude of the input determines the
642    /// amplitude of the waveform.
643    /// 0: PWM Input
644    /// 1: Analog Input
645    pub n_pwm_analog, set_n_pwm_analog: 1;
646    /// This bit selects an open-loop drive option for LRA Mode. When asserted, the
647    /// playback engine drives the LRA at the selected frequency independently of the
648    /// resonance frequency. In PWM input mode, the playback engine recovers the
649    /// LRA commutation frequency from the PWM input, dividing the frequency by
650    /// 128. Therefore the PWM input frequency must be equal to 128 times the
651    /// resonant frequency of the LRA.
652    /// 0: Auto-resonance mode
653    /// 1: LRA open-loop mode
654    pub lra_open_loop, set_lra_open_loop: 0;
655}
656
657bitfield! {
658    pub struct Control4Reg(u8);
659    impl Debug;
660
661    /// This bit sets the length of the auto calibration time. The AUTO_CAL_TIME[1:0]
662    /// bit should be enough time for the motor acceleration to settle when driven at the
663    /// RATED_VOLTAGE[7:0] value.
664    /// 0: 150 ms (minimum), 350 ms (maximum)
665    /// 1: 250 ms (minimum), 450 ms (maximum)
666    /// 2: 500 ms (minimum), 700 ms (maximum)
667    /// 3: 1000 ms (minimum), 1200 ms (maximum)
668    pub auto_cal_time, set_auto_cal_time: 5, 4;
669
670    /// OTP Memory status
671    /// 0: OTP Memory has not been programmed
672    /// 1: OTP Memory has been programmed
673    pub otp_status, set_otp_status: 2;
674
675    /// This bit launches the programming process for one-time programmable (OTP)
676    /// memory which programs the contents of register 0x16 through 0x1A into
677    /// nonvolatile memory. This process can only be executed one time per device.
678    /// See the Programming On-Chip OTP Memory section for details.
679    pub otp_program, set_otp_program: 1;
680}
681
682#[derive(Copy, Clone)]
683#[repr(u8)]
684pub enum Register {
685    Status = 0,
686    Mode = 1,
687    /// This field is the entry point for real-time playback (RTP) data. The DRV2605
688    /// playback engine drives the RTP_INPUT[7:0] value to the load when
689    /// MODE[2:0] = 5 (RTP mode). The RTP_INPUT[7:0] value can be updated in
690    /// real-time by the host controller to create haptic waveforms. The
691    /// RTP_INPUT[7:0] value is interpreted as signed by default, but can be set to
692    /// unsigned by the DATA_FORMAT_RTP bit in register 0x1D. When the
693    /// haptic waveform is complete, the user can idle the device by setting
694    /// MODE[2:0] = 0, or alternatively by setting STANDBY = 1.
695    RealTimePlaybackInput = 2,
696    Register3 = 3,
697    WaveformSequence0 = 4,
698    WaveformSequence1 = 5,
699    WaveformSequence2 = 6,
700    WaveformSequence3 = 7,
701    WaveformSequence4 = 8,
702    WaveformSequence5 = 9,
703    WaveformSequence6 = 0xa,
704    WaveformSequence7 = 0xb,
705    Go = 0xc,
706    OverdriveTimeOffset = 0xd,
707    SustainTimeOffsetPositive = 0xe,
708    SustainTimeOffsetNegative = 0xf,
709    BrakeTimeOffset = 0x10,
710
711    /// This bit sets the reference voltage for full-scale output during closed-loop
712    /// operation. The auto-calibration routine uses this register as an input, so this
713    /// register must be written with the rated voltage value of the motor before
714    /// calibration is performed. This register is ignored for open-loop operation
715    /// because the overdrive voltage sets the reference for that case. Any
716    /// modification of this register value should be followed by calibration to set
717    /// A_CAL_BEMF appropriately.
718    /// See the Rated Voltage Programming section for calculating the correct register
719    /// value.
720    RatedVoltage = 0x16,
721
722    /// During closed-loop operation the actuator feedback allows the output voltage
723    /// to go above the rated voltage during the automatic overdrive and automatic
724    /// braking periods. This register sets a clamp so that the automatic overdrive is
725    /// bounded. This bit also serves as the full-scale reference voltage for open-loop
726    /// operation.
727    /// See the Overdrive Voltage-Clamp Programming section for calculating the
728    /// correct register value.
729    OverdriveClampVoltage = 0x17,
730
731    /// This register contains the voltage-compensation result after execution of auto
732    /// calibration. The value stored in the A_CAL_COMP bit compensates for any
733    /// resistive losses in the driver. The calibration routine checks the impedance of
734    /// the actuator to automatically determine an appropriate value. The auto-
735    /// calibration compensation-result value is multiplied by the drive gain during
736    /// playback.
737    /// Auto-calibration compensation coefficient = 1 + A_CAL_COMP[7:0] / 255
738    AutoCalibrationCompensationResult = 0x18,
739
740    /// This register contains the rated back-EMF result after execution of auto
741    /// calibration. The A_CAL_BEMF[7:0] bit is the level of back-EMF voltage that the
742    /// actuator gives when the actuator is driven at the rated voltage. The DRV2605
743    /// playback engine uses this the value stored in this bit to automatically determine
744    /// the appropriate feedback gain for closed-loop operation.
745    /// Auto-calibration back-EMF (V) = (A_CAL_BEMF[7:0] / 255) × 1.22 V /
746    /// BEMF_GAIN[1:0]
747    AutoCalibrationBackEMFResult = 0x19,
748
749    FeedbackControl = 0x1a,
750
751    Control1 = 0x1b,
752    Control2 = 0x1c,
753    Control3 = 0x1d,
754    Control4 = 0x1e,
755}
756
757/// The hard-coded address of the driver.  All drivers share the same
758/// address so that it is possible to broadcast on the bus and have
759/// multiple units emit the same waveform
760pub const ADDRESS: u8 = 0x5a;
761
762pub struct Drv2605<I2C>
763where
764    I2C: I2c,
765{
766    i2c: I2C,
767}
768
769impl<I2C, E> Drv2605<I2C>
770where
771    I2C: I2c<Error = E>,
772{
773    /// Construct a driver instance, but don't do any initialization
774    pub fn new(i2c: I2C) -> Self {
775        Self { i2c }
776    }
777
778    pub async fn init_open_loop_erm(&mut self) -> Result<(), E> {
779        self.set_standby(false).await?;
780        self.set_realtime_playback_input(0).await?;
781        self.set_waveform(&[
782            WaveformReg::new_effect(Effect::StrongClick100),
783            WaveformReg::new_stop(),
784            WaveformReg::new_stop(),
785            WaveformReg::new_stop(),
786            WaveformReg::new_stop(),
787            WaveformReg::new_stop(),
788            WaveformReg::new_stop(),
789            WaveformReg::new_stop(),
790        ]).await?;
791
792        let mut feedback = FeedbackControlReg(self.read(Register::FeedbackControl).await?);
793        feedback.set_n_erm_lra(false);
794        self.write(Register::FeedbackControl, feedback.0).await?;
795
796        let mut control3 = Control3Reg(self.read(Register::Control3).await?);
797        control3.set_erm_open_loop(true);
798        self.write(Register::Control3, control3.0).await?;
799        Ok(())
800    }
801
802    /// Write `value` to `register`
803    async fn write(&mut self, register: Register, value: u8) -> Result<(), E> {
804        self.i2c.write(ADDRESS, &[register as u8, value]).await
805    }
806
807    /// Read an 8-bit value from the register
808    async fn read(&mut self, register: Register) -> Result<u8, E> {
809        let mut buf = [0u8; 1];
810        self.i2c
811            .write_read(ADDRESS, &[register as u8], &mut buf)
812            .await?;
813        Ok(buf[0])
814    }
815
816    pub async fn get_status(&mut self) -> Result<StatusReg, E> {
817        self.read(Register::Status).await.map(StatusReg)
818    }
819
820    pub async fn get_mode(&mut self) -> Result<ModeReg, E> {
821        self.read(Register::Mode).await.map(ModeReg)
822    }
823
824    /// performs the equivalent operation of power
825    /// cycling the device. Any playback operations are immediately interrupted,
826    /// and all registers are reset to the default values.
827    pub async fn reset(&mut self) -> Result<(), E> {
828        let mut mode = ModeReg(0);
829        mode.set_dev_reset(true);
830        self.write(Register::Mode, mode.0).await
831    }
832
833    /// Put the device into standby mode, or wake it up from standby
834    pub async fn set_standby(&mut self, standby: bool) -> Result<(), E> {
835        let mut mode = ModeReg(self.read(Register::Mode).await?);
836        mode.set_standby(standby);
837        self.write(Register::Mode, mode.0).await
838    }
839
840    /// This field is the entry point for real-time playback (RTP) data. The DRV2605
841    /// playback engine drives the RTP_INPUT[7:0] value to the load when
842    /// MODE[2:0] = 5 (RTP mode). The RTP_INPUT[7:0] value can be updated in
843    /// real-time by the host controller to create haptic waveforms. The
844    /// RTP_INPUT[7:0] value is interpreted as signed by default, but can be set to
845    /// unsigned by the DATA_FORMAT_RTP bit in register 0x1D. When the
846    /// haptic waveform is complete, the user can idle the device by setting
847    /// MODE[2:0] = 0, or alternatively by setting STANDBY = 1.
848    pub async fn set_realtime_playback_input(&mut self, value: i8) -> Result<(), E> {
849        self.write(Register::RealTimePlaybackInput, value as u8)
850            .await
851    }
852
853    /// This bit sets the output driver into a true high-impedance state. The device
854    /// must be enabled to go into the high-impedance state. When in hardware
855    /// shutdown or standby mode, the output drivers have 15 kΩ to ground. When
856    /// the HI_Z bit is asserted, the hi-Z functionality takes effect immediately, even
857    /// if a transaction is taking place.
858    pub async fn set_high_impedance_state(&mut self, value: bool) -> Result<(), E> {
859        let mut register = RegisterThree(self.read(Register::Register3).await?);
860        register.set_hi_z(value);
861        self.write(Register::Register3, register.0).await
862    }
863
864    /// Selects the library the playback engine selects when the GO bit is set.
865    pub async fn set_library(&mut self, value: LibrarySelection) -> Result<(), E> {
866        let mut register = RegisterThree(self.read(Register::Register3).await?);
867        register.set_library_selection(value as u8);
868        self.write(Register::Register3, register.0).await
869    }
870
871    /// Sets the waveform generation registers to the shape provided
872    pub async fn set_waveform(&mut self, waveform: &[WaveformReg; 8]) -> Result<(), E> {
873        let buf: [u8; 9] = [
874            Register::WaveformSequence0 as u8,
875            waveform[0].0,
876            waveform[1].0,
877            waveform[2].0,
878            waveform[3].0,
879            waveform[4].0,
880            waveform[5].0,
881            waveform[6].0,
882            waveform[7].0,
883        ];
884        self.i2c.write(ADDRESS, &buf).await
885    }
886
887    pub async fn set_single_effect(&mut self, effect: Effect) -> Result<(), E> {
888        let buf: [u8; 3] = [
889            Register::WaveformSequence0 as u8,
890            WaveformReg::new_effect(effect).0,
891            WaveformReg::new_stop().0,
892        ];
893        self.i2c.write(ADDRESS, &buf).await
894    }
895
896    /// This bit is used to fire processes in the DRV2605 device. The process
897    /// fired by the GO bit is selected by the MODE[2:0] bit (register 0x01). The
898    /// primary function of this bit is to fire playback of the waveform identifiers in
899    /// the waveform sequencer (registers 0x04 to 0x0B), in which case, this bit
900    /// can be thought of a software trigger for haptic waveforms. The GO bit
901    /// remains high until the playback of the haptic waveform sequence is
902    /// complete. Clearing the GO bit during waveform playback cancels the
903    /// waveform sequence. Using one of the external trigger modes can cause
904    /// the GO bit to be set or cleared by the external trigger pin. This bit can also
905    /// be used to fire the auto-calibration process or the diagnostic process.
906    pub async fn set_go(&mut self, go: bool) -> Result<(), E> {
907        let mut register = GoReg(self.read(Register::Go).await?);
908        register.set_go(go);
909        self.write(Register::Go, register.0).await
910    }
911
912    /// This bit adds a time offset to the overdrive portion of the library
913    /// waveforms. Some motors require more overdrive time than others, so this
914    /// register allows the user to add or remove overdrive time from the library
915    /// waveforms. The maximum voltage value in the library waveform is
916    /// automatically determined to be the overdrive portion. This register is only
917    /// useful in open-loop mode. Overdrive is automatic for closed-loop mode.
918    /// The offset is interpreted as 2s complement, so the time offset may be
919    /// positive or negative.
920    /// Overdrive Time Offset (ms) = ODT[7:0] × PLAYBACK_INTERVAL
921    /// See the section for PLAYBACK_INTERVAL details.
922    pub async fn set_overdrive_time_offset(&mut self, value: i8) -> Result<(), E> {
923        self.write(Register::OverdriveTimeOffset, value as u8).await
924    }
925
926    /// This bit adds a time offset to the positive sustain portion of the library
927    /// waveforms. Some motors have a faster or slower response time than
928    /// others, so this register allows the user to add or remove positive sustain
929    /// time from the library waveforms. Any positive voltage value other than the
930    /// overdrive portion is considered as a sustain positive value. The offset is
931    /// interpreted as 2s complement, so the time offset can positive or negative.
932    /// Sustain-Time Positive Offset (ms) = SPT[7:0] × PLAYBACK_INTERVAL
933    /// See the section for PLAYBACK_INTERVAL details.
934    pub async fn set_sustain_time_offset_positive(&mut self, value: i8) -> Result<(), E> {
935        self.write(Register::SustainTimeOffsetPositive, value as u8)
936            .await
937    }
938
939    /// This bit adds a time offset to the negative sustain portion of the library
940    /// waveforms. Some motors have a faster or slower response time than
941    /// others, so this register allows the user to add or remove negative sustain
942    /// time from the library waveforms. Any negative voltage value other than the
943    /// overdrive portion is considered as a sustaining negative value. The offset is
944    /// interpreted as two’s complement, so the time offset can be positive or
945    /// negative.
946    /// Sustain-Time Negative Offset (ms) = SNT[7:0] × PLAYBACK_INTERVAL
947    /// See the section for PLAYBACK_INTERVAL details.
948    pub async fn set_sustain_time_offset_negative(&mut self, value: i8) -> Result<(), E> {
949        self.write(Register::SustainTimeOffsetNegative, value as u8)
950            .await
951    }
952
953    /// This bit adds a time offset to the braking portion of the library waveforms.
954    /// Some motors require more braking time than others, so this register allows
955    /// the user to add or take away brake time from the library waveforms. The
956    /// most negative voltage value in the library waveform is automatically
957    /// determined to be the braking portion. This register is only useful in open-loop
958    /// mode. Braking is automatic for closed-loop mode. The offset is interpreted as
959    /// 2s complement, so the time offset can be positive or negative.
960    /// Brake Time Offset (ms) = BRT[7:0] × PLAYBACK_INTERVAL
961    /// See the section for PLAYBACK_INTERVAL details.
962    pub async fn set_brake_time_offset(&mut self, value: i8) -> Result<(), E> {
963        self.write(Register::BrakeTimeOffset, value as u8).await
964    }
965}