1pub mod dmp;
4mod dmp_constants;
5
6extern crate ak8963;
7use ak8963::Ak8963Reg;
8extern crate byteorder;
9use byteorder::{BigEndian, ByteOrder};
10extern crate i2cdev;
11use i2cdev::core::*;
12use i2cdev::linux::{LinuxI2CDevice, LinuxI2CError};
13#[macro_use]
14extern crate ndarray;
15use ndarray::prelude::*;
16use std::convert::From;
17use std::thread;
18use std::time;
19
20pub const G: f32 = 9.80665;
21
22pub const MPU9250_SLAVE_ADDR: u16 = 0x68;
23
24pub(crate) fn get_i2c_bus_path(i2c_bus: i32) -> String {
25 format!("/dev/i2c-{}", i2c_bus)
26}
27
28#[allow(dead_code)]
29#[derive(Clone, Copy)]
30enum Mpu9250Reg {
31 SmplrtDiv = 0x019,
32 Config = 0x1a,
33 GyroConfig = 0x1b,
34 AccelConfig = 0x1c,
35 AccelConfig2 = 0x1d,
36 FifoEn = 0x23,
37 I2cMstCtrl = 0x24,
38 I2cSlv0Addr = 0x25,
39 I2cSlv0Reg = 0x26,
40 I2cSlv0Ctrl = 0x27,
41 #[allow(dead_code)]
42 I2cSlv4Ctrl = 0x34,
43 IntPinCfg = 0x37,
44 IntEnable = 0x38,
45 #[allow(dead_code)]
46 AccelXoutH = 0x3b,
47 #[allow(dead_code)]
48 GyroConfigXoutH = 0x43,
49 I2cMstDelayCtrl = 0x67,
50 UserCtrl = 0x6a,
51 PwrMgmt1 = 0x6b,
52 FifoCountH = 0x72,
53 FifoRw = 0x74,
54 WhoAmI = 0x75,
55}
56
57impl Mpu9250Reg {
58 pub fn addr(&self) -> u8 {
59 *self as u8
60 }
61}
62
63pub trait Register {
64 fn mask(&self) -> u8;
65}
66
67enum RegI2cMstCtrl {
68 Speed400kHz,
70 I2cMstPNsr,
71 MultMstEn,
72}
73
74impl Register for RegI2cMstCtrl {
75 fn mask(&self) -> u8 {
76 match *self {
77 RegI2cMstCtrl::Speed400kHz => 0x0d,
78 RegI2cMstCtrl::I2cMstPNsr => 1 << 4,
79 RegI2cMstCtrl::MultMstEn => 1 << 7,
80 }
81 }
82}
83
84enum RegI2cSlv0Addr {
85 I2cSlv0Rnw,
86}
87
88impl Register for RegI2cSlv0Addr {
89 fn mask(&self) -> u8 {
90 match *self {
91 RegI2cSlv0Addr::I2cSlv0Rnw => 1 << 7,
92 }
93 }
94}
95
96enum RegI2cSlv0Ctrl {
97 I2cSlv0En,
98}
99
100impl Register for RegI2cSlv0Ctrl {
101 fn mask(&self) -> u8 {
102 match *self {
103 RegI2cSlv0Ctrl::I2cSlv0En => 1 << 7,
104 }
105 }
106}
107
108enum RegPwrMgmt1 {
109 Hreset,
110 Sleep,
111}
112
113impl Register for RegPwrMgmt1 {
114 fn mask(&self) -> u8 {
115 match *self {
116 RegPwrMgmt1::Sleep => 1 << 6,
117 RegPwrMgmt1::Hreset => 1 << 7,
118 }
119 }
120}
121
122enum RegIntPinCfg {
123 BypassEn,
124 Actl, }
126
127impl Register for RegIntPinCfg {
128 fn mask(&self) -> u8 {
129 match *self {
130 RegIntPinCfg::BypassEn => 1 << 1,
131 RegIntPinCfg::Actl => 1 << 7,
132 }
133 }
134}
135
136#[allow(dead_code)]
137enum RegFifoEn {
138 Slv0,
139 Accel,
140 GyroZ,
141 GyroY,
142 GyroX,
143 Temp,
144}
145
146impl Register for RegFifoEn {
147 fn mask(&self) -> u8 {
148 match *self {
149 RegFifoEn::Slv0 => 1,
150 RegFifoEn::Accel => 1 << 3,
151 RegFifoEn::GyroZ => 1 << 4,
152 RegFifoEn::GyroY => 1 << 5,
153 RegFifoEn::GyroX => 1 << 6,
154 RegFifoEn::Temp => 1 << 7,
155 }
156 }
157}
158
159enum RegUserCtrl {
160 FifoRst,
161 DmpRst,
162 I2cMstEn,
163 FifoEn,
164 DmpEn,
165}
166
167impl Register for RegUserCtrl {
168 fn mask(&self) -> u8 {
169 match *self {
170 RegUserCtrl::FifoRst => 1 << 2,
171 RegUserCtrl::DmpRst => 1 << 3,
172 RegUserCtrl::I2cMstEn => 1 << 5,
173 RegUserCtrl::FifoEn => 1 << 6,
174 RegUserCtrl::DmpEn => 1 << 7,
175 }
176 }
177}
178
179enum RegIntEnable {
180 DmpIntEn,
181}
182
183impl Register for RegIntEnable {
184 fn mask(&self) -> u8 {
185 match *self {
186 RegIntEnable::DmpIntEn => 1 << 1,
187 }
188 }
189}
190
191#[allow(dead_code)]
192enum RegI2cMstDelayCtrl {
193 I2cSlv0DlyEn,
194 I2cSlv1DlyEn,
195 I2cSlv2DlyEn,
196 I2cSlv3DlyEn,
197 I2cSlv4DlyEn,
198 DelayEsShadow,
199}
200
201impl Register for RegI2cMstDelayCtrl {
202 fn mask(&self) -> u8 {
203 match *self {
204 RegI2cMstDelayCtrl::I2cSlv0DlyEn => 1,
205 RegI2cMstDelayCtrl::I2cSlv1DlyEn => 1 << 1,
206 RegI2cMstDelayCtrl::I2cSlv2DlyEn => 1 << 2,
207 RegI2cMstDelayCtrl::I2cSlv3DlyEn => 1 << 3,
208 RegI2cMstDelayCtrl::I2cSlv4DlyEn => 1 << 4,
209 RegI2cMstDelayCtrl::DelayEsShadow => 1 << 7,
210 }
211 }
212}
213
214#[allow(dead_code)]
215#[derive(Copy, Clone, Debug)]
216pub enum AccelFsr {
217 Opt2G,
218 Opt4G,
219 Opt8G,
220 Opt16G,
221}
222
223impl AccelFsr {
227 pub fn get_sensitivity_g(&self) -> f32 {
229 return match *self {
230 AccelFsr::Opt2G => 2.0,
231 AccelFsr::Opt4G => 4.0,
232 AccelFsr::Opt8G => 8.0,
233 AccelFsr::Opt16G => 16.0,
234 } / 32768.0;
235 }
236
237 pub fn get_sensitivity_mss(&self) -> f32 {
239 return match *self {
242 AccelFsr::Opt2G => 2.0,
243 AccelFsr::Opt4G => 4.0,
244 AccelFsr::Opt8G => 8.0,
245 AccelFsr::Opt16G => 16.0,
246 } * G / 32768.0;
247 }
248}
249
250#[allow(dead_code)]
251#[derive(Copy, Clone, Debug)]
252pub enum AccelDlpf {
253 OptOff,
254 Opt184,
255 Opt92,
256 Opt41,
257 Opt20,
258 Opt10,
259 Opt5,
260}
261
262#[allow(dead_code)]
266#[derive(Copy, Clone, Debug)]
267pub enum GyroFsr {
268 Opt250,
269 Opt500,
270 Opt1000,
271 Opt2000,
272}
273
274impl GyroFsr {
275 pub fn get_scalar(&self) -> f32 {
276 return match *self {
277 GyroFsr::Opt250 => 250.0,
278 GyroFsr::Opt500 => 500.0,
279 GyroFsr::Opt1000 => 1000.0,
280 GyroFsr::Opt2000 => 2000.0,
281 } / 32768.0;
282 }
283}
284
285#[allow(dead_code)]
286#[derive(Copy, Clone, Debug)]
287pub enum GyroDlpf {
288 OptOff,
289 Opt184,
290 Opt92,
291 Opt41,
292 Opt20,
293 Opt10,
294 Opt5,
295}
296
297pub struct Mpu9250 {
298 i2c_dev: LinuxI2CDevice,
299 pub accel_fsr: AccelFsr,
300 pub gyro_fsr: GyroFsr,
301 pub debug: bool,
302 pub ak8963_i2c_addr: u16,
303}
304
305impl Mpu9250 {
306 pub fn new(
320 i2c_bus: i32,
321 i2c_addr: Option<u16>,
322 whoami: Option<u8>,
323 ak8963_i2c_addr: Option<u16>,
324 ) -> Result<Self, LinuxI2CError> {
325 let mut i2c_dev = LinuxI2CDevice::new(get_i2c_bus_path(i2c_bus), i2c_addr.unwrap_or(0x68))?;
326
327 let mut buf1 = [0u8; 1];
328 i2c_dev.write(&[Mpu9250Reg::WhoAmI.addr()])?;
329 i2c_dev.read(&mut buf1)?;
330 if buf1[0] != whoami.unwrap_or(0x71) {
331 panic!("Unexpected WHOAMI value: {:?}", buf1[0]);
332 }
333
334 let mut mpu = Self {
335 i2c_dev,
336 accel_fsr: AccelFsr::Opt2G,
337 gyro_fsr: GyroFsr::Opt2000,
338 debug: false,
339 ak8963_i2c_addr: ak8963_i2c_addr.unwrap_or(0x0c),
340 };
341 mpu.write_config()?;
342 Ok(mpu)
343 }
344
345 pub fn set_debug(&mut self, debug: bool) {
347 self.debug = debug;
348 }
349
350 pub fn write_config(&mut self) -> Result<(), LinuxI2CError> {
352 let accel_fsr = self.accel_fsr.clone();
353 self.write_accel_fsr(accel_fsr)?;
354 let gyro_fsr = self.gyro_fsr.clone();
355 self.write_gyro_fsr(gyro_fsr)?;
356 Ok(())
357 }
358
359 pub fn write_accel_fsr(&mut self, accel_fsr: AccelFsr) -> Result<(), LinuxI2CError> {
360 let accel_config_byte: u8 = match accel_fsr {
361 AccelFsr::Opt2G => 0,
362 AccelFsr::Opt4G => 1,
363 AccelFsr::Opt8G => 2,
364 AccelFsr::Opt16G => 3,
365 } << 3;
366 self.i2c_dev
367 .write(&[Mpu9250Reg::AccelConfig.addr(), accel_config_byte])?;
368 self.accel_fsr = accel_fsr;
369 Ok(())
370 }
371
372 pub fn write_accel_dlpf(&mut self, accel_dlpf: AccelDlpf) -> Result<(), LinuxI2CError> {
373 let accel_config_2_byte: u8 = match accel_dlpf {
374 AccelDlpf::OptOff => 7,
375 AccelDlpf::Opt184 => 1,
376 AccelDlpf::Opt92 => 2,
377 AccelDlpf::Opt41 => 3,
378 AccelDlpf::Opt20 => 4,
379 AccelDlpf::Opt10 => 5,
380 AccelDlpf::Opt5 => 6,
381 };
382 self.i2c_dev
383 .write(&[Mpu9250Reg::AccelConfig2.addr(), accel_config_2_byte])?;
384 Ok(())
385 }
386
387 pub fn write_gyro_fsr(&mut self, gyro_fsr: GyroFsr) -> Result<(), LinuxI2CError> {
388 let gyro_config_byte: u8 = match gyro_fsr {
389 GyroFsr::Opt250 => 0,
390 GyroFsr::Opt500 => 1,
391 GyroFsr::Opt1000 => 2,
392 GyroFsr::Opt2000 => 3,
393 } << 3;
394 self.i2c_dev
395 .write(&[Mpu9250Reg::GyroConfig.addr(), gyro_config_byte])?;
396 self.gyro_fsr = gyro_fsr;
397 Ok(())
398 }
399
400 pub fn write_gyro_dlpf(&mut self, gyro_dlpf: GyroDlpf) -> Result<(), LinuxI2CError> {
401 let config_byte: u8 = match gyro_dlpf {
402 GyroDlpf::OptOff => 7,
403 GyroDlpf::Opt184 => 1,
404 GyroDlpf::Opt92 => 2,
405 GyroDlpf::Opt41 => 3,
406 GyroDlpf::Opt20 => 4,
407 GyroDlpf::Opt10 => 5,
408 GyroDlpf::Opt5 => 6,
409 };
410 self.i2c_dev
411 .write(&[Mpu9250Reg::Config.addr(), config_byte])?;
412 self.wait_for_nonzero_gyro()?;
415 Ok(())
416 }
417
418 pub fn wait_for_nonzero_gyro(&mut self) -> Result<(), LinuxI2CError> {
422 loop {
423 let sample = self.read_sample()?;
424 if sample.gyro == array![0.0, 0.0, 0.0] {
425 thread::sleep(time::Duration::from_millis(10));
426 } else {
427 return Ok(());
428 }
429 }
430 }
431
432 pub fn read_sample(&mut self) -> Result<Mpu9250Sample, LinuxI2CError> {
434 let mut buf: [u8; 14] = [0u8; 14];
435 self.i2c_dev.write(&[Mpu9250Reg::AccelXoutH.addr()])?;
436 self.i2c_dev.read(&mut buf)?;
437
438 Ok(Self::parse_accel_and_gyro_and_temp(
439 &buf,
440 self.accel_fsr.get_sensitivity_mss(),
441 self.gyro_fsr.get_scalar(),
442 ))
443 }
444
445 pub(crate) fn parse_accel_and_gyro(
449 data: &[u8],
450 accel_fsr_scalar: f32,
451 gyro_fsr_scalar: f32,
452 ) -> Mpu9250Sample {
453 let accel_v_raw = Self::buffer_to_array1x3_i16(&data[0..6]);
454 let gyro_v_raw = Self::buffer_to_array1x3_i16(&data[6..12]);
455
456 let accel_v = accel_fsr_scalar * accel_v_raw.map(|e| *e as f32);
457 let gyro_v = gyro_fsr_scalar * gyro_v_raw.map(|e| *e as f32);
458
459 Mpu9250Sample {
460 accel: accel_v,
461 accel_raw: accel_v_raw,
462 gyro: gyro_v,
463 gyro_raw: gyro_v_raw,
464 }
465 }
466
467 pub(crate) fn parse_accel_and_gyro_and_temp(
472 data: &[u8],
473 accel_fsr_scalar: f32,
474 gyro_fsr_scalar: f32,
475 ) -> Mpu9250Sample {
476 let accel_v_raw = Self::buffer_to_array1x3_i16(&data[0..6]);
478 let gyro_v_raw = Self::buffer_to_array1x3_i16(&data[8..14]);
479
480 let accel_v = accel_fsr_scalar * accel_v_raw.map(|e| *e as f32);
481 let gyro_v = gyro_fsr_scalar * gyro_v_raw.map(|e| *e as f32);
482
483 Mpu9250Sample {
484 accel: accel_v,
485 accel_raw: accel_v_raw,
486 gyro: gyro_v,
487 gyro_raw: gyro_v_raw,
488 }
489 }
490
491 pub fn enable_bypass(&mut self) -> Result<(), LinuxI2CError> {
494 self.i2c_dev.write(&[Mpu9250Reg::UserCtrl.addr(), 0])?;
495 self.i2c_dev.write(&[
496 Mpu9250Reg::IntPinCfg.addr(),
497 RegIntPinCfg::Actl.mask() | RegIntPinCfg::BypassEn.mask(),
498 ])?;
499 return Ok(());
500 }
501
502 pub fn disable_bypass(&mut self) -> Result<(), LinuxI2CError> {
503 self.i2c_dev
504 .write(&[Mpu9250Reg::UserCtrl.addr(), RegUserCtrl::I2cMstEn.mask()])?;
505 self.i2c_dev
506 .write(&[Mpu9250Reg::IntPinCfg.addr(), RegIntPinCfg::Actl.mask()])?;
507 Ok(())
508 }
509
510 fn buffer_to_array1x3_i16(buf: &[u8]) -> Array1<i16> {
511 array![
512 BigEndian::read_i16(&buf[0..2]),
513 BigEndian::read_i16(&buf[2..4]),
514 BigEndian::read_i16(&buf[4..6])
515 ]
516 }
517
518 pub fn reset(&mut self) -> Result<(), LinuxI2CError> {
521 self.i2c_dev
523 .write(&[Mpu9250Reg::PwrMgmt1.addr(), RegPwrMgmt1::Hreset.mask()])?;
524
525 self.i2c_dev.write(&[Mpu9250Reg::PwrMgmt1.addr(), 0u8])?;
527
528 thread::sleep(time::Duration::from_millis(100));
529 Ok(())
530 }
531
532 pub fn power_off(&mut self) -> Result<(), LinuxI2CError> {
533 self.i2c_dev
535 .write(&[Mpu9250Reg::PwrMgmt1.addr(), RegPwrMgmt1::Hreset.mask()])?;
536 self.i2c_dev
538 .write(&[Mpu9250Reg::PwrMgmt1.addr(), RegPwrMgmt1::Sleep.mask()])?;
539 Ok(())
540 }
541
542 pub fn dmp_enable(&mut self) -> Result<(), LinuxI2CError> {
543 self.dmp_interrupt_disable()?;
544
545 self.disable_bypass()?;
546
547 self.i2c_dev.write(&[Mpu9250Reg::FifoEn.addr(), 0])?;
549
550 self.dmp_interrupt_enable()?;
551
552 self.reset_fifo()?;
553 Ok(())
554 }
555
556 pub fn dmp_disable(&mut self) -> Result<(), LinuxI2CError> {
557 self.dmp_interrupt_disable()?;
558 self.i2c_dev.write(&[Mpu9250Reg::FifoEn.addr(), 0])?;
559 self.reset_fifo()?;
560 Ok(())
561 }
562
563 pub fn dmp_interrupt_enable(&mut self) -> Result<(), LinuxI2CError> {
564 self.i2c_dev
565 .write(&[Mpu9250Reg::IntEnable.addr(), RegIntEnable::DmpIntEn.mask()])?;
566 self.i2c_dev.write(&[Mpu9250Reg::FifoEn.addr(), 0])?;
568 Ok(())
569 }
570
571 pub fn dmp_interrupt_disable(&mut self) -> Result<(), LinuxI2CError> {
572 self.i2c_dev.write(&[Mpu9250Reg::IntEnable.addr(), 0])?;
573 self.i2c_dev.write(&[Mpu9250Reg::FifoEn.addr(), 0])?;
575 Ok(())
576 }
577
578 pub fn setup_mag_in_fifo(&mut self) -> Result<(), LinuxI2CError> {
585 self.i2c_dev.write(&[
587 Mpu9250Reg::I2cMstCtrl.addr(),
588 RegI2cMstCtrl::Speed400kHz.mask()
589 | RegI2cMstCtrl::MultMstEn.mask()
590 | RegI2cMstCtrl::I2cMstPNsr.mask(),
591 ])?;
592
593 self.i2c_dev.write(&[
595 Mpu9250Reg::I2cSlv0Addr.addr(),
596 RegI2cSlv0Addr::I2cSlv0Rnw.mask() | self.ak8963_i2c_addr as u8,
597 ])?;
598
599 self.i2c_dev
601 .write(&[Mpu9250Reg::I2cSlv0Reg.addr(), Ak8963Reg::Hxl.addr()])?;
602
603 self.i2c_dev.write(&[
605 Mpu9250Reg::I2cSlv0Ctrl.addr(),
606 RegI2cSlv0Ctrl::I2cSlv0En.mask() | 0x07,
607 ])?;
608
609 Ok(())
615 }
616
617 pub fn set_sample_rate(&mut self, rate: u16) -> Result<(), LinuxI2CError> {
623 if rate > 1000 || rate < 4 {
624 panic!("Error: Invalid sample rate.");
625 }
626
627 let smplrt_div = (1000 / rate) as u8 - 1;
629 self.i2c_dev
630 .write(&[Mpu9250Reg::SmplrtDiv.addr(), smplrt_div])?;
631 Ok(())
632 }
633
634 pub fn reset_fifo(&mut self) -> Result<(), LinuxI2CError> {
637 self.disable_fifo()?;
638 self.enable_fifo()?;
639 Ok(())
640 }
641
642 pub fn enable_fifo(&mut self) -> Result<(), LinuxI2CError> {
644 self.i2c_dev
645 .write(&[Mpu9250Reg::IntEnable.addr(), RegIntEnable::DmpIntEn.mask()])?;
646 self.i2c_dev
647 .write(&[Mpu9250Reg::FifoEn.addr(), RegFifoEn::Slv0.mask()])?;
648 self.i2c_dev.write(&[
649 Mpu9250Reg::UserCtrl.addr(),
650 RegUserCtrl::I2cMstEn.mask() | RegUserCtrl::FifoEn.mask() | RegUserCtrl::DmpEn.mask(),
651 ])?;
652
653 Ok(())
654 }
655
656 pub fn disable_fifo(&mut self) -> Result<(), LinuxI2CError> {
659 self.i2c_dev.write(&[Mpu9250Reg::IntEnable.addr(), 0])?;
660 self.i2c_dev.write(&[Mpu9250Reg::FifoEn.addr(), 0])?;
661 self.i2c_dev.write(&[
662 Mpu9250Reg::UserCtrl.addr(),
663 RegUserCtrl::FifoRst.mask() | RegUserCtrl::DmpRst.mask(),
664 ])?;
665 Ok(())
666 }
667
668 fn read_fifo_byte_count(&mut self) -> Result<u16, LinuxI2CError> {
670 let mut data = [0u8; 2];
671 self.i2c_dev.write(&[Mpu9250Reg::FifoCountH.addr()])?;
672 self.i2c_dev.read(&mut data)?;
673
674 data[0] = data[0] & 0x1f;
677 let length: u16 = BigEndian::read_u16(&data);
678 if self.debug {
679 println!("FIFO byte count: {:?}", length);
680 }
681 Ok(length)
682 }
683
684 pub fn read_fifo_strict(&mut self, count: u16) -> Result<Vec<u8>, FifoReadError> {
686 let available_bytes = self.read_fifo_byte_count()?;
687 if available_bytes < count {
688 return Err(FifoReadError::InsufficientData(available_bytes));
689 }
690
691 let mut data = vec![0; count as usize];
692 self.i2c_dev.write(&[Mpu9250Reg::FifoRw.addr()])?;
693 self.i2c_dev.read(&mut data)?;
694 Ok(data)
695 }
696}
697
698#[derive(Clone, Debug)]
699pub struct Mpu9250Sample {
700 pub accel: Array1<f32>,
701 pub accel_raw: Array1<i16>,
702 pub gyro: Array1<f32>,
703 pub gyro_raw: Array1<i16>,
704}
705
706#[derive(Debug)]
707pub enum FifoReadError {
708 InsufficientData(u16),
709 I2c(LinuxI2CError),
710}
711
712impl From<LinuxI2CError> for FifoReadError {
713 fn from(e: LinuxI2CError) -> Self {
714 FifoReadError::I2c(e)
715 }
716}
717
718#[cfg(test)]
719mod tests {
720 use super::Mpu9250;
721 use std::env;
722
723 fn get_i2c_bus() -> i32 {
724 match env::var("MPU9250_I2C_BUS") {
725 Ok(bus_string) => bus_string
726 .parse()
727 .expect("Could not convert MPU9250_I2C_BUS env var to i32."),
728 Err(_) => 1,
729 }
730 }
731
732 fn get_i2c_addr() -> Option<u16> {
733 match env::var("MPU9250_I2C_ADDR") {
734 Ok(addr_string) => Some(
735 addr_string
736 .parse()
737 .expect("Could not convert MPU9250_I2C_ADDR env var to u16."),
738 ),
739 Err(_) => None,
740 }
741 }
742
743 fn get_whoami() -> Option<u8> {
744 match env::var("MPU9250_WHOAMI") {
745 Ok(whoami_string) => Some(
746 whoami_string
747 .parse()
748 .expect("Could not convert MPU9250_WHOAMI env var to u8."),
749 ),
750 Err(_) => None,
751 }
752 }
753
754 fn get_ak8963_i2c_addr() -> Option<u16> {
755 match env::var("AK8963_I2C_ADDR") {
756 Ok(addr_string) => Some(
757 addr_string
758 .parse()
759 .expect("Could not convert AK8963_I2C_ADDR env var to u16."),
760 ),
761 Err(_) => None,
762 }
763 }
764
765 #[test]
766 fn basic() {
767 let mut mpu9250 = Mpu9250::new(
768 get_i2c_bus(),
769 get_i2c_addr(),
770 get_whoami(),
771 get_ak8963_i2c_addr(),
772 ).expect("Could not connect to MPU9250");
773 mpu9250.read_sample().unwrap();
774 }
775}