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}