1use embedded_hal::delay::DelayNs;
2
3use crate::registers::{
4 ACC_CONF, ACC_DATA_X, ALT_ACC_CONF, ALT_CONF, ALT_GYR_CONF, ALT_STATUS, BMI323_CHIP_ID,
5 CHIP_ID, CMD, ERR_REG, EXT_ALT_CONFIG_CHG, EXT_ANYMO_1, EXT_ANYMO_2, EXT_ANYMO_3, EXT_FLAT_1,
6 EXT_FLAT_2, EXT_GEN_SET_1, EXT_NOMO_1, EXT_NOMO_2, EXT_NOMO_3, EXT_ORIENT_1, EXT_ORIENT_2,
7 EXT_SC_1, EXT_SIGMO_1, EXT_SIGMO_2, EXT_SIGMO_3, EXT_ST_RESULT, EXT_ST_SELECT, EXT_TAP_1,
8 EXT_TAP_2, EXT_TAP_3, EXT_TILT_1, EXT_TILT_2, FEATURE_CTRL, FEATURE_DATA_ADDR, FEATURE_DATA_TX,
9 FEATURE_IO_STATUS, FEATURE_IO0, FEATURE_IO1, FEATURE_IO2, FEATURE_IO3, FIFO_CONF, FIFO_CTRL,
10 FIFO_DATA, FIFO_FILL_LEVEL, FIFO_WATERMARK, GYR_CONF, GYR_DATA_X, INT_CONF, IO_INT_CTRL,
11 SELF_TEST, SENSOR_TIME_0, SOFT_RESET, STATUS, TEMP_DATA, TransportKind, interrupt_map_location,
12 words_to_axis,
13};
14use crate::{
15 AccelConfig, ActiveLevel, AltAccelConfig, AltConfigControl, AltGyroConfig, AltStatus,
16 AnyMotionConfig, AxisData, Bmi323, DeviceState, Error, ErrorWord, EventReportMode, FifoConfig,
17 FlatConfig, GyroConfig, ImuData, InterruptChannel, InterruptPinConfig, InterruptRoute,
18 InterruptSource, InterruptStatus, NoMotionConfig, OrientationConfig, OutputDataRate,
19 OutputMode, ReferenceUpdate, SelfTestDetail, SelfTestResult, SelfTestSelection,
20 SignificantMotionConfig, StatusWord, StepCounterConfig, SyncAccess, TapConfig, TiltConfig,
21};
22
23impl<T> Bmi323<T>
24where
25 Self: SyncAccess,
26{
27 pub fn init<D: DelayNs>(
35 &mut self,
36 delay: &mut D,
37 ) -> Result<DeviceState, Error<<Self as SyncAccess>::BusError>> {
38 self.soft_reset(delay)?;
41
42 if matches!(self.kind, TransportKind::Spi) {
43 self.read_word(CHIP_ID).map_err(Error::Bus)?;
44 delay.delay_us(250);
45 }
46
47 let chip_id = self.read_word(CHIP_ID).map_err(Error::Bus)? as u8;
48 if chip_id != BMI323_CHIP_ID {
49 return Err(Error::InvalidChipId(chip_id));
50 }
51
52 let error = self.error_word()?;
53 if error.fatal() {
54 return Err(Error::FatalError);
55 }
56
57 Ok(DeviceState {
58 chip_id,
59 status: self.status_word()?,
60 error,
61 })
62 }
63
64 pub fn soft_reset<D: DelayNs>(
66 &mut self,
67 delay: &mut D,
68 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
69 self.write_word(CMD, SOFT_RESET).map_err(Error::Bus)?;
70 delay.delay_ms(2);
71 Ok(())
72 }
73
74 pub fn run_self_test<D: DelayNs>(
86 &mut self,
87 delay: &mut D,
88 selection: SelfTestSelection,
89 ) -> Result<SelfTestResult, Error<<Self as SyncAccess>::BusError>> {
90 let saved_acc_conf = self.read_word(ACC_CONF).map_err(Error::Bus)?;
91 let saved_gyr_conf = self.read_word(GYR_CONF).map_err(Error::Bus)?;
92 let saved_alt_acc_conf = self.read_word(ALT_ACC_CONF).map_err(Error::Bus)?;
93 let saved_alt_gyr_conf = self.read_word(ALT_GYR_CONF).map_err(Error::Bus)?;
94 let saved_st_select = self.read_feature_word(EXT_ST_SELECT)?;
95 let saved_accel_range = self.accel_range;
96 let saved_gyro_range = self.gyro_range;
97
98 let result = self.run_self_test_inner(delay, selection);
99 let restore = self.restore_self_test_configuration(
100 saved_acc_conf,
101 saved_gyr_conf,
102 saved_alt_acc_conf,
103 saved_alt_gyr_conf,
104 saved_st_select,
105 );
106
107 self.accel_range = saved_accel_range;
108 self.gyro_range = saved_gyro_range;
109
110 match (result, restore) {
111 (Err(err), _) => Err(err),
112 (Ok(_), Err(err)) => Err(err),
113 (Ok(report), Ok(())) => Ok(report),
114 }
115 }
116
117 pub fn status_word(&mut self) -> Result<StatusWord, Error<<Self as SyncAccess>::BusError>> {
119 self.read_word(STATUS).map(StatusWord).map_err(Error::Bus)
120 }
121
122 pub fn error_word(&mut self) -> Result<ErrorWord, Error<<Self as SyncAccess>::BusError>> {
124 self.read_word(ERR_REG).map(ErrorWord).map_err(Error::Bus)
125 }
126
127 pub fn set_accel_config(
132 &mut self,
133 config: AccelConfig,
134 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
135 self.write_word(ACC_CONF, config.to_word())
136 .map_err(Error::Bus)?;
137 self.accel_range = config.range;
138 Ok(())
139 }
140
141 pub fn set_gyro_config(
146 &mut self,
147 config: GyroConfig,
148 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
149 self.write_word(GYR_CONF, config.to_word())
150 .map_err(Error::Bus)?;
151 self.gyro_range = config.range;
152 Ok(())
153 }
154
155 pub fn accel_range(&self) -> crate::AccelRange {
160 self.accel_range
161 }
162
163 pub fn gyro_range(&self) -> crate::GyroRange {
168 self.gyro_range
169 }
170
171 pub fn read_accel(&mut self) -> Result<AxisData, Error<<Self as SyncAccess>::BusError>> {
176 let mut words = [0u16; 3];
177 self.read_words(ACC_DATA_X, &mut words)
178 .map_err(Error::Bus)?;
179 Ok(words_to_axis(words))
180 }
181
182 pub fn read_gyro(&mut self) -> Result<AxisData, Error<<Self as SyncAccess>::BusError>> {
187 let mut words = [0u16; 3];
188 self.read_words(GYR_DATA_X, &mut words)
189 .map_err(Error::Bus)?;
190 Ok(words_to_axis(words))
191 }
192
193 pub fn read_imu_data(&mut self) -> Result<ImuData, Error<<Self as SyncAccess>::BusError>> {
199 let mut words = [0u16; 6];
200 self.read_words(ACC_DATA_X, &mut words)
201 .map_err(Error::Bus)?;
202 Ok(ImuData {
203 accel: words_to_axis([words[0], words[1], words[2]]),
204 gyro: words_to_axis([words[3], words[4], words[5]]),
205 })
206 }
207
208 pub fn read_temperature_celsius(
210 &mut self,
211 ) -> Result<f32, Error<<Self as SyncAccess>::BusError>> {
212 let raw = self.read_word(TEMP_DATA).map_err(Error::Bus)? as i16;
213 Ok(raw as f32 / 512.0 + 23.0)
214 }
215
216 pub fn read_sensor_time(&mut self) -> Result<u32, Error<<Self as SyncAccess>::BusError>> {
218 let mut words = [0u16; 2];
219 self.read_words(SENSOR_TIME_0, &mut words)
220 .map_err(Error::Bus)?;
221 Ok(words[0] as u32 | ((words[1] as u32) << 16))
222 }
223
224 pub fn configure_interrupt_pin(
229 &mut self,
230 channel: InterruptChannel,
231 config: InterruptPinConfig,
232 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
233 let mut word = self.read_word(IO_INT_CTRL).map_err(Error::Bus)?;
234 let shift = match channel {
235 InterruptChannel::Int1 => 0,
236 InterruptChannel::Int2 => 8,
237 InterruptChannel::Ibi => return Ok(()),
238 };
239 word &= !(0b111 << shift);
240 word |= ((matches!(config.active_level, ActiveLevel::High) as u16) << shift)
241 | ((matches!(config.output_mode, OutputMode::OpenDrain) as u16) << (shift + 1))
242 | ((config.enabled as u16) << (shift + 2));
243 self.write_word(IO_INT_CTRL, word).map_err(Error::Bus)
244 }
245
246 pub fn set_interrupt_latching(
248 &mut self,
249 latched: bool,
250 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
251 self.write_word(INT_CONF, latched as u16)
252 .map_err(Error::Bus)
253 }
254
255 pub fn map_interrupt(
257 &mut self,
258 source: InterruptSource,
259 route: InterruptRoute,
260 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
261 let (register, shift) = interrupt_map_location(source);
262 let mut word = self.read_word(register).map_err(Error::Bus)?;
263 word &= !(0b11 << shift);
264 word |= u16::from(route) << shift;
265 self.write_word(register, word).map_err(Error::Bus)
266 }
267
268 pub fn read_interrupt_status(
270 &mut self,
271 channel: InterruptChannel,
272 ) -> Result<InterruptStatus, Error<<Self as SyncAccess>::BusError>> {
273 let reg = match channel {
274 InterruptChannel::Int1 => 0x0D,
275 InterruptChannel::Int2 => 0x0E,
276 InterruptChannel::Ibi => 0x0F,
277 };
278 self.read_word(reg).map(InterruptStatus).map_err(Error::Bus)
279 }
280
281 pub fn set_fifo_config(
283 &mut self,
284 config: FifoConfig,
285 watermark_words: u16,
286 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
287 self.write_word(FIFO_WATERMARK, watermark_words & 0x03FF)
288 .map_err(Error::Bus)?;
289 self.write_word(FIFO_CONF, config.to_word())
290 .map_err(Error::Bus)
291 }
292
293 pub fn fifo_fill_level(&mut self) -> Result<u16, Error<<Self as SyncAccess>::BusError>> {
295 Ok(self.read_word(FIFO_FILL_LEVEL).map_err(Error::Bus)? & 0x07FF)
296 }
297
298 pub fn flush_fifo(&mut self) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
300 self.write_word(FIFO_CTRL, 0x0001).map_err(Error::Bus)
301 }
302
303 pub fn read_fifo_words(
313 &mut self,
314 words: &mut [u16],
315 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
316 assert!(
317 words.len() <= 64,
318 "read_fifo_words: words.len() must not exceed 64"
319 );
320 self.read_words(FIFO_DATA, words).map_err(Error::Bus)
321 }
322
323 pub fn enable_feature_engine(&mut self) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
331 self.write_word(ACC_CONF, 0).map_err(Error::Bus)?;
332 self.write_word(GYR_CONF, 0).map_err(Error::Bus)?;
333 self.write_word(FEATURE_IO2, 0x012C).map_err(Error::Bus)?;
334 self.write_word(FEATURE_IO_STATUS, 0x0001)
335 .map_err(Error::Bus)?;
336 self.write_word(FEATURE_CTRL, 0x0001).map_err(Error::Bus)?;
337
338 for _ in 0..32 {
339 let io1 = self.read_word(FEATURE_IO1).map_err(Error::Bus)?;
340 let status = (io1 & 0x000F) as u8;
341 if status == 0x1 || status == 0x5 {
342 return Ok(());
343 }
344 }
345 let io1 = self.read_word(FEATURE_IO1).map_err(Error::Bus)?;
346 Err(Error::FeatureEngineNotReady((io1 & 0x000F) as u8))
347 }
348
349 pub fn configure_any_motion(
351 &mut self,
352 config: AnyMotionConfig,
353 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
354 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)?;
355 self.write_feature_word(
356 EXT_ANYMO_1,
357 (config.threshold & 0x0FFF)
358 | (match config.reference_update {
359 ReferenceUpdate::OnDetection => 0,
360 ReferenceUpdate::EverySample => 1,
361 } << 12),
362 )?;
363 self.write_feature_word(EXT_ANYMO_2, config.hysteresis & 0x03FF)?;
364 self.write_feature_word(
365 EXT_ANYMO_3,
366 (config.duration & 0x1FFF) | (((config.wait_time as u16) & 0x07) << 13),
367 )?;
368 self.modify_word(FEATURE_IO0, |mut word| {
369 word &= !(0b111 << 3);
370 word |= (config.axes.x as u16) << 3;
371 word |= (config.axes.y as u16) << 4;
372 word |= (config.axes.z as u16) << 5;
373 word
374 })
375 }
376
377 pub fn configure_no_motion(
379 &mut self,
380 config: NoMotionConfig,
381 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
382 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)?;
383 self.write_feature_word(
384 EXT_NOMO_1,
385 (config.threshold & 0x0FFF)
386 | (match config.reference_update {
387 ReferenceUpdate::OnDetection => 0,
388 ReferenceUpdate::EverySample => 1,
389 } << 12),
390 )?;
391 self.write_feature_word(EXT_NOMO_2, config.hysteresis & 0x03FF)?;
392 self.write_feature_word(
393 EXT_NOMO_3,
394 (config.duration & 0x1FFF) | (((config.wait_time as u16) & 0x07) << 13),
395 )?;
396 self.modify_word(FEATURE_IO0, |mut word| {
397 word &= !0b111;
398 word |= config.axes.x as u16;
399 word |= (config.axes.y as u16) << 1;
400 word |= (config.axes.z as u16) << 2;
401 word
402 })
403 }
404
405 pub fn configure_flat(
408 &mut self,
409 config: FlatConfig,
410 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
411 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)?;
412 self.write_feature_word(
413 EXT_FLAT_1,
414 u16::from(config.theta & 0x3F)
415 | ((config.blocking as u16) << 6)
416 | (u16::from(config.hold_time) << 8),
417 )?;
418 self.write_feature_word(
419 EXT_FLAT_2,
420 u16::from(config.slope_threshold) | (u16::from(config.hysteresis) << 8),
421 )?;
422 self.set_flat_enabled(true)
423 }
424
425 pub fn set_flat_enabled(
427 &mut self,
428 enabled: bool,
429 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
430 self.modify_word(FEATURE_IO0, |mut word| {
431 if enabled {
432 word |= 1 << 6;
433 } else {
434 word &= !(1 << 6);
435 }
436 word
437 })
438 }
439
440 pub fn configure_orientation(
443 &mut self,
444 config: OrientationConfig,
445 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
446 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)?;
447 self.write_feature_word(
448 EXT_ORIENT_1,
449 (config.upside_down_enabled as u16)
450 | ((config.mode as u16) << 1)
451 | ((config.blocking as u16) << 3)
452 | ((u16::from(config.theta & 0x3F)) << 5)
453 | ((u16::from(config.hold_time & 0x1F)) << 11),
454 )?;
455 self.write_feature_word(
456 EXT_ORIENT_2,
457 u16::from(config.slope_threshold) | (u16::from(config.hysteresis) << 8),
458 )?;
459 self.set_orientation_enabled(true)
460 }
461
462 pub fn set_orientation_enabled(
464 &mut self,
465 enabled: bool,
466 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
467 self.modify_word(FEATURE_IO0, |mut word| {
468 if enabled {
469 word |= 1 << 7;
470 } else {
471 word &= !(1 << 7);
472 }
473 word
474 })
475 }
476
477 pub fn configure_tap(
482 &mut self,
483 config: TapConfig,
484 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
485 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)?;
486 self.write_feature_word(
487 EXT_TAP_1,
488 (config.axis as u16)
489 | ((config.reporting_mode as u16) << 2)
490 | ((u16::from(config.max_peaks_for_tap & 0x07)) << 3)
491 | ((config.mode as u16) << 6),
492 )?;
493 self.write_feature_word(
494 EXT_TAP_2,
495 (config.tap_peak_threshold & 0x03FF)
496 | ((u16::from(config.max_gesture_duration & 0x3F)) << 10),
497 )?;
498 self.write_feature_word(
499 EXT_TAP_3,
500 u16::from(config.max_duration_between_peaks & 0x0F)
501 | (u16::from(config.tap_shock_settling_duration & 0x0F) << 4)
502 | (u16::from(config.min_quiet_duration_between_taps & 0x0F) << 8)
503 | (u16::from(config.quiet_time_after_gesture & 0x0F) << 12),
504 )?;
505 self.modify_word(FEATURE_IO0, |mut word| {
506 word &= !((1 << 12) | (1 << 13) | (1 << 14));
507 word |= (config.single_tap_enabled as u16) << 12;
508 word |= (config.double_tap_enabled as u16) << 13;
509 word |= (config.triple_tap_enabled as u16) << 14;
510 word
511 })
512 }
513
514 pub fn configure_significant_motion(
517 &mut self,
518 config: SignificantMotionConfig,
519 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
520 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)?;
521 self.write_feature_word(EXT_SIGMO_1, config.block_size)?;
522 self.write_feature_word(
523 EXT_SIGMO_2,
524 (config.peak_to_peak_min & 0x03FF)
525 | ((u16::from(config.mean_crossing_rate_min & 0x3F)) << 10),
526 )?;
527 self.write_feature_word(
528 EXT_SIGMO_3,
529 (config.peak_to_peak_max & 0x03FF)
530 | ((u16::from(config.mean_crossing_rate_max & 0x3F)) << 10),
531 )?;
532 self.set_significant_motion_enabled(true)
533 }
534
535 pub fn set_significant_motion_enabled(
537 &mut self,
538 enabled: bool,
539 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
540 self.modify_word(FEATURE_IO0, |mut word| {
541 if enabled {
542 word |= 1 << 10;
543 } else {
544 word &= !(1 << 10);
545 }
546 word
547 })
548 }
549
550 pub fn configure_tilt(
553 &mut self,
554 config: TiltConfig,
555 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
556 self.apply_common_feature_settings(config.report_mode, config.interrupt_hold)?;
557 self.write_feature_word(
558 EXT_TILT_1,
559 u16::from(config.segment_size) | (u16::from(config.min_tilt_angle) << 8),
560 )?;
561 self.write_feature_word(EXT_TILT_2, config.beta_acc_mean)?;
562 self.set_tilt_enabled(true)
563 }
564
565 pub fn set_tilt_enabled(
567 &mut self,
568 enabled: bool,
569 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
570 self.modify_word(FEATURE_IO0, |mut word| {
571 if enabled {
572 word |= 1 << 11;
573 } else {
574 word &= !(1 << 11);
575 }
576 word
577 })
578 }
579
580 pub fn set_step_detector_enabled(
586 &mut self,
587 enabled: bool,
588 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
589 self.modify_word(FEATURE_IO0, |mut word| {
590 if enabled {
591 word |= 1 << 8;
592 } else {
593 word &= !(1 << 8);
594 }
595 word
596 })
597 }
598
599 pub fn set_step_counter_enabled(
605 &mut self,
606 enabled: bool,
607 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
608 self.modify_word(FEATURE_IO0, |mut word| {
609 if enabled {
610 word |= 1 << 9;
611 } else {
612 word &= !(1 << 9);
613 }
614 word
615 })
616 }
617
618 pub fn configure_step_counter(
623 &mut self,
624 config: StepCounterConfig,
625 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
626 self.write_feature_word(EXT_SC_1, config.to_word())
627 }
628
629 pub fn reset_step_counter(&mut self) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
631 self.configure_step_counter(StepCounterConfig {
632 reset_counter: true,
633 ..StepCounterConfig::disabled()
634 })
635 }
636
637 pub fn read_step_count(&mut self) -> Result<u32, Error<<Self as SyncAccess>::BusError>> {
639 let low = self.read_word(FEATURE_IO2).map_err(Error::Bus)? as u32;
640 let high = self.read_word(FEATURE_IO3).map_err(Error::Bus)? as u32;
641 Ok(low | (high << 16))
642 }
643
644 pub fn set_alt_accel_config(
646 &mut self,
647 config: AltAccelConfig,
648 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
649 self.write_word(ALT_ACC_CONF, config.to_word())
650 .map_err(Error::Bus)
651 }
652
653 pub fn set_alt_gyro_config(
655 &mut self,
656 config: AltGyroConfig,
657 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
658 self.write_word(ALT_GYR_CONF, config.to_word())
659 .map_err(Error::Bus)
660 }
661
662 pub fn configure_alt_config_control(
665 &mut self,
666 config: AltConfigControl,
667 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
668 self.write_word(
669 ALT_CONF,
670 (config.accel_enabled as u16)
671 | ((config.gyro_enabled as u16) << 4)
672 | ((config.reset_on_user_config_write as u16) << 8),
673 )
674 .map_err(Error::Bus)?;
675 self.write_feature_word(
676 EXT_ALT_CONFIG_CHG,
677 (config.switch_to_alternate as u16) | ((config.switch_to_user as u16) << 4),
678 )
679 }
680
681 pub fn alt_status(&mut self) -> Result<AltStatus, Error<<Self as SyncAccess>::BusError>> {
683 self.read_word(ALT_STATUS)
684 .map(AltStatus)
685 .map_err(Error::Bus)
686 }
687
688 fn modify_word<F>(&mut self, reg: u8, f: F) -> Result<(), Error<<Self as SyncAccess>::BusError>>
689 where
690 F: FnOnce(u16) -> u16,
691 {
692 let value = self.read_word(reg).map_err(Error::Bus)?;
693 self.write_word(reg, f(value)).map_err(Error::Bus)?;
694 if reg == FEATURE_IO0 {
695 self.write_word(FEATURE_IO_STATUS, 1).map_err(Error::Bus)?;
696 }
697 Ok(())
698 }
699
700 fn run_self_test_inner<D: DelayNs>(
701 &mut self,
702 delay: &mut D,
703 selection: SelfTestSelection,
704 ) -> Result<SelfTestResult, Error<<Self as SyncAccess>::BusError>> {
705 self.enable_feature_engine()?;
706
707 if selection.tests_gyroscope() {
708 self.write_word(
709 ACC_CONF,
710 AccelConfig {
711 mode: crate::AccelMode::HighPerformance,
712 odr: OutputDataRate::Hz200,
713 ..Default::default()
714 }
715 .to_word(),
716 )
717 .map_err(Error::Bus)?;
718 }
719
720 self.write_word(ALT_ACC_CONF, 0).map_err(Error::Bus)?;
721 self.write_word(ALT_GYR_CONF, 0).map_err(Error::Bus)?;
722 self.write_feature_word(EXT_ST_SELECT, selection.to_word())?;
723 self.write_word(CMD, SELF_TEST).map_err(Error::Bus)?;
724
725 for _ in 0..50 {
726 delay.delay_ms(10);
727 let feature_io1 = self.read_word(FEATURE_IO1).map_err(Error::Bus)?;
728 if feature_io1 & (1 << 4) != 0 {
729 let detail = SelfTestDetail(self.read_feature_word(EXT_ST_RESULT)?);
730 return Ok(SelfTestResult {
731 selection,
732 passed: feature_io1 & (1 << 6) != 0,
733 sample_rate_error: feature_io1 & (1 << 7) != 0,
734 error_status: (feature_io1 & 0x000F) as u8,
735 detail,
736 });
737 }
738 }
739
740 Err(Error::SelfTestTimeout)
741 }
742
743 fn restore_self_test_configuration(
744 &mut self,
745 acc_conf: u16,
746 gyr_conf: u16,
747 alt_acc_conf: u16,
748 alt_gyr_conf: u16,
749 st_select: u16,
750 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
751 self.write_word(ACC_CONF, acc_conf).map_err(Error::Bus)?;
752 self.write_word(GYR_CONF, gyr_conf).map_err(Error::Bus)?;
753 self.write_word(ALT_ACC_CONF, alt_acc_conf)
754 .map_err(Error::Bus)?;
755 self.write_word(ALT_GYR_CONF, alt_gyr_conf)
756 .map_err(Error::Bus)?;
757 self.write_feature_word(EXT_ST_SELECT, st_select)
758 }
759
760 fn write_feature_word(
761 &mut self,
762 ext_addr: u16,
763 value: u16,
764 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
765 self.write_word(FEATURE_DATA_ADDR, ext_addr)
766 .map_err(Error::Bus)?;
767 self.write_word(FEATURE_DATA_TX, value).map_err(Error::Bus)
768 }
769
770 fn read_feature_word(
771 &mut self,
772 ext_addr: u16,
773 ) -> Result<u16, Error<<Self as SyncAccess>::BusError>> {
774 self.write_word(FEATURE_DATA_ADDR, ext_addr)
775 .map_err(Error::Bus)?;
776 self.read_word(FEATURE_DATA_TX).map_err(Error::Bus)
777 }
778
779 fn modify_feature_word<F>(
780 &mut self,
781 ext_addr: u16,
782 f: F,
783 ) -> Result<(), Error<<Self as SyncAccess>::BusError>>
784 where
785 F: FnOnce(u16) -> u16,
786 {
787 let word = self.read_feature_word(ext_addr)?;
788 self.write_feature_word(ext_addr, f(word))
789 }
790
791 fn apply_common_feature_settings(
800 &mut self,
801 report_mode: EventReportMode,
802 interrupt_hold: u8,
803 ) -> Result<(), Error<<Self as SyncAccess>::BusError>> {
804 self.modify_feature_word(EXT_GEN_SET_1, |word| {
805 let mut updated = word & !0x003F;
806 updated |= match report_mode {
807 EventReportMode::AllEvents => 0,
808 EventReportMode::FirstEventOnly => 1,
809 };
810 updated |= ((interrupt_hold.min(13) as u16) & 0x0F) << 1;
811 updated
812 })
813 }
814}