1#![no_std]
2
3use core::{future::Future, marker::PhantomData};
4use embedded_hal_async::{
5 delay::DelayNs,
6 i2c::{self, I2c},
7 spi::{self},
8};
9
10mod reg;
11use reg::*;
12
13mod cfg;
14pub use cfg::*;
15
16const MAGNET_ADDR: u8 = 0x0C;
17const IMU_WHOAMI: u8 = 0xEA;
18const MAG_WHOAMI: u8 = 0x09;
19
20#[derive(Debug, Clone, PartialEq)]
21pub enum SetupError<E> {
22 Transport(E),
24 ImuWhoAmI(u8),
26 MagWhoAmI(u8),
28}
29
30impl<E> From<E> for SetupError<E> {
31 fn from(error: E) -> Self {
32 SetupError::Transport(error)
33 }
34}
35
36#[derive(Debug, Clone, PartialEq)]
37#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
38pub struct Data6Dof<T> {
40 pub acc: [T; 3],
41 pub gyr: [T; 3],
42 pub tmp: T,
43}
44
45#[derive(Debug, Clone, PartialEq)]
46#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
47pub struct Data9Dof<T> {
49 pub acc: [T; 3],
50 pub gyr: [T; 3],
51 pub mag: [T; 3],
52 pub tmp: T,
53}
54
55pub struct MagEnabled;
57pub struct MagDisabled;
58
59pub struct I2cDevice<I2C> {
61 bus_inner: I2C,
62 address: I2cAddress,
63}
64
65pub trait Icm20948Transport {
67 type Error: Into<SetupError<Self::Error>>;
68 fn read_registers(
69 &mut self,
70 reg_addr: u8,
71 read: &mut [u8],
72 ) -> impl Future<Output = Result<(), Self::Error>>;
73 fn write_registers(
74 &mut self,
75 reg_addr: u8,
76 write: &[u8],
77 ) -> impl Future<Output = Result<(), Self::Error>>;
78}
79
80impl<I2C: I2c> Icm20948Transport for I2cDevice<I2C> {
82 type Error = I2C::Error;
83 async fn read_registers(&mut self, reg_addr: u8, read: &mut [u8]) -> Result<(), Self::Error> {
84 let addr = self.address.get();
85 self.bus_inner.write_read(addr, &[reg_addr], read).await
86 }
87
88 async fn write_registers(&mut self, reg_addr: u8, write: &[u8]) -> Result<(), Self::Error> {
89 let addr = self.address.get();
90 self.bus_inner
91 .transaction(
92 addr,
93 &mut [
94 i2c::Operation::Write(&[reg_addr]),
95 i2c::Operation::Write(write),
96 ],
97 )
98 .await
99 }
100}
101
102mod spi_helpers {
103 const SPI_READ_NWRITE: u8 = 0x80;
104 pub(super) const fn write_addr(addr: u8) -> [u8; 1] {
105 [addr]
106 }
107 pub(super) const fn read_addr(addr: u8) -> [u8; 1] {
109 [addr | SPI_READ_NWRITE]
110 }
111}
112
113pub struct SpiDevice<SPI> {
114 inner: SPI,
115}
116
117impl<SPI: spi::SpiDevice> Icm20948Transport for SpiDevice<SPI> {
119 type Error = SPI::Error;
120 async fn read_registers(&mut self, reg_addr: u8, read: &mut [u8]) -> Result<(), Self::Error> {
121 self.inner
122 .transaction(&mut [
123 spi::Operation::Write(&spi_helpers::read_addr(reg_addr)),
124 spi::Operation::Read(read),
125 ])
126 .await
127 }
128
129 async fn write_registers(&mut self, reg_addr: u8, write: &[u8]) -> Result<(), Self::Error> {
130 self.inner
131 .transaction(&mut [
132 spi::Operation::Write(&spi_helpers::write_addr(reg_addr)),
133 spi::Operation::Write(write),
134 ])
135 .await
136 }
137}
138
139pub struct IcmBuilder<TRANSPORT, DELAY> {
151 transport: TRANSPORT,
152 delay: DELAY,
153 config: Config,
154}
155
156pub struct Icm20948<TRANSPORT, MAG> {
158 transport: TRANSPORT,
159 config: Config,
160 user_bank: UserBank,
161 mag_state: PhantomData<MAG>,
162}
163
164impl<BUS, DELAY> IcmBuilder<I2cDevice<BUS>, DELAY>
165where
166 BUS: I2c,
167 DELAY: DelayNs,
168{
169 #[must_use]
171 pub fn new_i2c(bus: BUS, delay: DELAY) -> IcmBuilder<I2cDevice<BUS>, DELAY> {
172 Self {
173 transport: I2cDevice {
174 bus_inner: bus,
175 address: I2cAddress::default(),
176 },
177 delay,
178 config: Config::default(),
179 }
180 }
181
182 #[must_use]
186 pub fn set_address(self, address: impl Into<I2cAddress>) -> IcmBuilder<I2cDevice<BUS>, DELAY> {
187 IcmBuilder {
188 transport: I2cDevice {
189 address: address.into(),
190 ..self.transport
191 },
192 ..self
193 }
194 }
195}
196
197impl<SPI, DELAY> IcmBuilder<SpiDevice<SPI>, DELAY>
198where
199 SPI: spi::SpiDevice,
200 DELAY: DelayNs,
201{
202 #[must_use]
204 pub fn new_spi(spi: SPI, delay: DELAY) -> IcmBuilder<SpiDevice<SPI>, DELAY> {
205 Self {
206 transport: SpiDevice { inner: spi },
207 delay,
208 config: Config::default(),
209 }
210 }
211}
212
213impl<TRANPORT, DELAY> IcmBuilder<TRANPORT, DELAY>
214where
215 TRANPORT: Icm20948Transport,
216 DELAY: DelayNs,
217{
218 #[must_use]
220 pub fn with_config(self, config: Config) -> IcmBuilder<TRANPORT, DELAY> {
221 IcmBuilder { config, ..self }
222 }
223
224 #[must_use]
226 pub fn acc_range(self, acc_range: AccRange) -> IcmBuilder<TRANPORT, DELAY> {
227 IcmBuilder {
228 config: Config {
229 acc_range,
230 ..self.config
231 },
232 ..self
233 }
234 }
235
236 #[must_use]
238 pub fn acc_dlp(self, acc_dlp: AccDlp) -> IcmBuilder<TRANPORT, DELAY> {
239 IcmBuilder {
240 config: Config {
241 acc_dlp,
242 ..self.config
243 },
244 ..self
245 }
246 }
247
248 #[must_use]
250 pub fn acc_unit(self, acc_unit: AccUnit) -> IcmBuilder<TRANPORT, DELAY> {
251 IcmBuilder {
252 config: Config {
253 acc_unit,
254 ..self.config
255 },
256 ..self
257 }
258 }
259
260 #[must_use]
262 pub fn acc_odr(self, acc_odr: u16) -> IcmBuilder<TRANPORT, DELAY> {
263 IcmBuilder {
264 config: Config {
265 acc_odr,
266 ..self.config
267 },
268 ..self
269 }
270 }
271
272 #[must_use]
274 pub fn gyr_range(self, gyr_range: GyrRange) -> IcmBuilder<TRANPORT, DELAY> {
275 IcmBuilder {
276 config: Config {
277 gyr_range,
278 ..self.config
279 },
280 ..self
281 }
282 }
283
284 #[must_use]
286 pub fn gyr_dlp(self, gyr_dlp: GyrDlp) -> IcmBuilder<TRANPORT, DELAY> {
287 IcmBuilder {
288 config: Config {
289 gyr_dlp,
290 ..self.config
291 },
292 ..self
293 }
294 }
295
296 #[must_use]
298 pub fn gyr_unit(self, gyr_unit: GyrUnit) -> IcmBuilder<TRANPORT, DELAY> {
299 IcmBuilder {
300 config: Config {
301 gyr_unit,
302 ..self.config
303 },
304 ..self
305 }
306 }
307
308 #[must_use]
310 pub fn gyr_odr(self, gyr_odr: u8) -> IcmBuilder<TRANPORT, DELAY> {
311 IcmBuilder {
312 config: Config {
313 gyr_odr,
314 ..self.config
315 },
316 ..self
317 }
318 }
319
320 pub async fn initialize_6dof(
322 mut self,
323 ) -> Result<Icm20948<TRANPORT, MagDisabled>, SetupError<TRANPORT::Error>> {
324 let mut imu = Icm20948 {
325 transport: self.transport,
326 config: self.config,
327 user_bank: UserBank::Bank0,
328 mag_state: PhantomData,
329 };
330
331 imu.setup_acc_gyr(&mut self.delay).await?;
332
333 Ok(imu)
334 }
335
336 pub async fn initialize_9dof(
338 mut self,
339 ) -> Result<Icm20948<TRANPORT, MagEnabled>, SetupError<TRANPORT::Error>> {
340 let mut imu = Icm20948 {
341 transport: self.transport,
342 config: self.config,
343 user_bank: UserBank::Bank0,
344 mag_state: PhantomData,
345 };
346
347 imu.setup_acc_gyr(&mut self.delay).await?;
348 imu.setup_mag(&mut self.delay).await?;
349
350 Ok(imu)
351 }
352}
353
354impl<TRANSPORT, MAG> Icm20948<TRANSPORT, MAG>
355where
356 TRANSPORT: Icm20948Transport,
357{
358 async fn setup_acc_gyr(
360 &mut self,
361 delay: &mut impl DelayNs,
362 ) -> Result<(), SetupError<TRANSPORT::Error>> {
363 self.device_reset(delay).await?;
365
366 self.set_user_bank::<Bank0>(true).await?;
368 let [imu_whoami] = self.read_from(Bank0::WhoAmI).await?;
369
370 if imu_whoami != IMU_WHOAMI {
371 return Err(SetupError::ImuWhoAmI(imu_whoami));
372 }
373
374 self.write_to(Bank0::PwrMgmt1, 0x01).await?;
376
377 self.set_acc_range(self.config.acc_range).await?;
379 self.set_gyr_range(self.config.gyr_range).await?;
380
381 self.set_gyr_dlp(self.config.gyr_dlp).await?;
383 self.set_acc_dlp(self.config.acc_dlp).await?;
384
385 self.set_acc_odr(self.config.acc_odr).await?;
387 self.set_gyr_odr(self.config.gyr_odr).await?;
388
389 Ok(())
390 }
391
392 pub async fn device_reset(&mut self, delay: &mut impl DelayNs) -> Result<(), TRANSPORT::Error> {
394 delay.delay_ms(20).await;
395 self.write_to_flag(Bank0::PwrMgmt1, 1 << 7, 1 << 7).await?;
396 delay.delay_ms(50).await;
397 Ok(())
398 }
399
400 async fn enable_i2c_master(&mut self, enable: bool) -> Result<(), TRANSPORT::Error> {
402 self.write_to_flag(Bank0::UserCtrl, u8::from(enable) << 5, 1 << 5)
403 .await
404 }
405
406 async fn reset_i2c_master(&mut self) -> Result<(), TRANSPORT::Error> {
408 self.write_to_flag(Bank0::UserCtrl, 1 << 1, 1 << 1).await
409 }
410
411 async fn set_user_bank<R: Register>(&mut self, force: bool) -> Result<(), TRANSPORT::Error> {
413 if (self.user_bank != R::bank()) || force {
414 self.transport
415 .write_registers(REG_BANK_SEL, &[(R::bank() as u8) << 4])
416 .await?;
417 self.user_bank = R::bank();
418 }
419 Ok(())
420 }
421
422 async fn read_from<const N: usize, R: Register>(
424 &mut self,
425 reg: R,
426 ) -> Result<[u8; N], TRANSPORT::Error> {
427 let mut buf = [0u8; N];
428 self.set_user_bank::<R>(false).await?;
429 self.transport.read_registers(reg.addr(), &mut buf).await?;
430 Ok(buf)
431 }
432
433 async fn write_to<R: Register>(&mut self, reg: R, data: u8) -> Result<(), TRANSPORT::Error> {
435 self.set_user_bank::<R>(false).await?;
436 self.transport.write_registers(reg.addr(), &[data]).await
437 }
438
439 async fn write_to_flag<R: Register>(
441 &mut self,
442 reg: R,
443 data: u8,
444 flag: u8,
445 ) -> Result<(), TRANSPORT::Error> {
446 let [mut register] = self.read_from(reg).await?;
447 register = (register & !flag) | (data & flag);
448 self.write_to(reg, register).await
449 }
450
451 async fn set_mag_read(&mut self) -> Result<(), TRANSPORT::Error> {
453 let [mut reg] = self.read_from(Bank3::I2cSlv0Addr).await?;
454 reg &= 0b0111_1111;
455 reg |= 1 << 7;
456 self.write_to(Bank3::I2cSlv0Addr, reg).await
457 }
458
459 async fn set_mag_write(&mut self) -> Result<(), TRANSPORT::Error> {
461 let [mut reg] = self.read_from(Bank3::I2cSlv0Addr).await?;
462 reg &= 0b0111_1111;
463 self.write_to(Bank3::I2cSlv0Addr, reg).await
464 }
465
466 async fn mag_write_to(
468 &mut self,
469 reg: MagBank,
470 data: u8,
471 delay: &mut impl DelayNs,
472 ) -> Result<(), TRANSPORT::Error> {
473 self.set_mag_write().await?;
474 delay.delay_ms(10).await;
475 self.write_to(Bank3::I2cSlv0Reg, reg.reg()).await?;
476 self.write_to(Bank3::I2cSlv0Do, data).await?;
477 self.write_to(Bank3::I2cSlv0Ctrl, (1 << 7) | 1).await?;
478 delay.delay_ms(10).await;
479 self.set_mag_read().await
480 }
481
482 async fn mag_read_from<const N: usize>(
484 &mut self,
485 reg: MagBank,
486 delay: &mut impl DelayNs,
487 ) -> Result<[u8; N], TRANSPORT::Error> {
488 self.set_mag_read().await?;
489 delay.delay_ms(10).await;
490 self.write_to(Bank3::I2cSlv0Reg, reg.reg()).await?;
491 let data = (1 << 7) | (N as u8).min(16);
492 self.write_to(Bank3::I2cSlv0Ctrl, data).await?;
493 delay.delay_ms(10).await;
494 self.read_from(Bank0::ExtSlvSensData00).await
495 }
496
497 pub async fn set_acc_range(&mut self, range: AccRange) -> Result<(), TRANSPORT::Error> {
499 self.write_to_flag(Bank2::AccelConfig, (range as u8) << 1, 0b0110)
500 .await?;
501 self.config.acc_range = range;
502 Ok(())
503 }
504
505 pub async fn set_gyr_range(&mut self, range: GyrRange) -> Result<(), TRANSPORT::Error> {
507 self.write_to_flag(Bank2::GyroConfig1, (range as u8) << 1, 0b0110)
508 .await?;
509 self.config.gyr_range = range;
510 Ok(())
511 }
512
513 pub fn set_acc_unit(&mut self, unit: AccUnit) {
515 self.config.acc_unit = unit;
516 }
517
518 pub fn set_gyr_unit(&mut self, unit: GyrUnit) {
520 self.config.gyr_unit = unit;
521 }
522
523 pub async fn set_acc_dlp(&mut self, acc_dlp: AccDlp) -> Result<(), TRANSPORT::Error> {
525 let flag = 0b0011_1001;
526 let data = if AccDlp::Disabled != acc_dlp {
527 ((acc_dlp as u8) << 3) | 1
528 } else {
529 0u8
530 };
531 self.write_to_flag(Bank2::AccelConfig, data, flag).await
532 }
533
534 pub async fn set_gyr_dlp(&mut self, gyr_dlp: GyrDlp) -> Result<(), TRANSPORT::Error> {
536 let flag = 0b0011_1001;
537 if GyrDlp::Disabled == gyr_dlp {
538 self.write_to_flag(Bank2::GyroConfig1, 0u8, flag).await
539 } else {
540 let data = ((gyr_dlp as u8) << 3) | 1;
541 self.write_to_flag(Bank2::GyroConfig1, data, flag).await
542 }
543 }
544
545 pub async fn set_acc_odr(&mut self, acc_odr: u16) -> Result<(), TRANSPORT::Error> {
547 let [msb, lsb] = acc_odr.clamp(0, 0xFFF).to_be_bytes();
548 self.write_to(Bank2::AccelSmplrtDiv1, msb).await?;
549 self.write_to(Bank2::AccelSmplrtDiv2, lsb).await
550 }
551
552 pub async fn set_gyr_odr(&mut self, gyr_odr: u8) -> Result<(), TRANSPORT::Error> {
554 self.write_to(Bank2::GyroSmplrtDiv, gyr_odr).await
555 }
556}
557
558impl<TRANSPORT> Icm20948<TRANSPORT, MagEnabled>
559where
560 TRANSPORT: Icm20948Transport,
561{
562 async fn setup_mag(
564 &mut self,
565 delay: &mut impl DelayNs,
566 ) -> Result<(), SetupError<TRANSPORT::Error>> {
567 self.mag_reset(delay).await?;
569
570 self.write_to(Bank3::I2cMstCtrl, 0x07).await?;
572
573 self.enable_i2c_master(true).await?;
575
576 self.write_to(Bank3::I2cSlv0Addr, MAGNET_ADDR).await?;
578
579 let [mag_whoami] = self.mag_read_from(MagBank::DeviceId, delay).await?;
581
582 if mag_whoami != MAG_WHOAMI {
583 return Err(SetupError::MagWhoAmI(mag_whoami));
584 }
585
586 self.mag_reset(delay).await?;
588
589 self.mag_write_to(MagBank::Control2, 0b01000, delay).await?;
591
592 self.write_to(Bank3::I2cSlv0Reg, MagBank::XDataLow.reg())
594 .await?;
595
596 self.write_to(Bank3::I2cSlv0Ctrl, (1 << 7) | 8).await?;
598
599 Ok(())
600 }
601
602 async fn mag_reset(&mut self, delay: &mut impl DelayNs) -> Result<(), TRANSPORT::Error> {
604 self.mag_write_to(MagBank::Control3, 1, delay).await?;
606 delay.delay_ms(100).await;
607
608 self.reset_i2c_master().await
610 }
611
612 pub async fn read_mag(&mut self) -> Result<[f32; 3], TRANSPORT::Error> {
614 let mag = self.read_mag_unscaled().await?;
615 let mag = mag.map(|x| 0.15 * x as f32);
616
617 Ok(mag)
618 }
619
620 pub async fn read_mag_unscaled(&mut self) -> Result<[i16; 3], TRANSPORT::Error> {
622 let raw: [u8; 6] = self.read_from(Bank0::ExtSlvSensData00).await?;
623 let mag = collect_3xi16_mag(raw);
624
625 Ok(mag)
626 }
627
628 pub async fn read_9dof(&mut self) -> Result<Data9Dof<f32>, TRANSPORT::Error> {
630 let raw: [u8; 20] = self.read_from(Bank0::AccelXoutH).await?;
631 let [axh, axl, ayh, ayl, azh, azl, gxh, gxl, gyh, gyl, gzh, gzl, tph, tpl, mxl, mxh, myl, myh, mzl, mzh] =
632 raw;
633
634 let acc = self.scaled_acc_from_bytes([axh, axl, ayh, ayl, azh, azl]);
635 let gyr = self.scaled_gyr_from_bytes([gxh, gxl, gyh, gyl, gzh, gzl]);
636 let mag = self.scaled_mag_from_bytes([mxl, mxh, myl, myh, mzl, mzh]);
637
638 let tmp = self.scaled_tmp_from_bytes([tph, tpl]);
639
640 Ok(Data9Dof { acc, gyr, mag, tmp })
641 }
642
643 pub async fn read_9dof_unscaled(&mut self) -> Result<Data9Dof<i16>, TRANSPORT::Error> {
645 let raw: [u8; 20] = self.read_from(Bank0::AccelXoutH).await?;
646 let [axh, axl, ayh, ayl, azh, azl, gxh, gxl, gyh, gyl, gzh, gzl, tph, tpl, mxl, mxh, myl, myh, mzl, mzh] =
647 raw;
648
649 let acc = collect_3xi16([axh, axl, ayh, ayl, azh, azl]);
650 let gyr = collect_3xi16([gxh, gxl, gyh, gyl, gzh, gzl]);
651 let mag = collect_3xi16_mag([mxl, mxh, myl, myh, mzl, mzh]);
652
653 let tmp = i16::from_be_bytes([tph, tpl]);
654
655 Ok(Data9Dof { acc, gyr, mag, tmp })
656 }
657
658 fn scaled_mag_from_bytes(&self, bytes: [u8; 6]) -> [f32; 3] {
660 collect_3xi16_mag(bytes).map(|x| 0.15 * x as f32)
661 }
662}
663
664impl<TRANSPORT, MAG> Icm20948<TRANSPORT, MAG>
665where
666 TRANSPORT: Icm20948Transport,
667{
668 fn scaled_acc_from_bytes(&self, bytes: [u8; 6]) -> [f32; 3] {
670 collect_3xi16(bytes).map(|x| f32::from(x) * self.acc_scalar())
671 }
672
673 fn scaled_gyr_from_bytes(&self, bytes: [u8; 6]) -> [f32; 3] {
675 collect_3xi16(bytes).map(|x| f32::from(x) * self.gyr_scalar())
676 }
677
678 fn scaled_tmp_from_bytes(&self, bytes: [u8; 2]) -> f32 {
680 f32::from(i16::from_be_bytes(bytes)) / 333.87 + 21.
681 }
682
683 pub async fn read_acc_unscaled(&mut self) -> Result<[i16; 3], TRANSPORT::Error> {
685 let raw = self.read_from(Bank0::AccelXoutH).await?;
686 Ok(collect_3xi16(raw))
687 }
688
689 pub async fn read_acc(&mut self) -> Result<[f32; 3], TRANSPORT::Error> {
691 let acc = self
692 .read_acc_unscaled()
693 .await?
694 .map(|x| f32::from(x) * self.acc_scalar());
695 Ok(acc)
696 }
697
698 pub async fn read_gyr_unscaled(&mut self) -> Result<[i16; 3], TRANSPORT::Error> {
700 let raw = self.read_from(Bank0::GyroXoutH).await?;
701 Ok(collect_3xi16(raw))
702 }
703
704 pub async fn read_gyr(&mut self) -> Result<[f32; 3], TRANSPORT::Error> {
706 let gyr = self
707 .read_gyr_unscaled()
708 .await?
709 .map(|x| f32::from(x) * self.gyr_scalar());
710 Ok(gyr)
711 }
712
713 pub async fn read_6dof(&mut self) -> Result<Data6Dof<f32>, TRANSPORT::Error> {
715 let raw: [u8; 14] = self.read_from(Bank0::AccelXoutH).await?;
716 let [axh, axl, ayh, ayl, azh, azl, gxh, gxl, gyh, gyl, gzh, gzl, tph, tpl] = raw;
717
718 let acc = self.scaled_acc_from_bytes([axh, axl, ayh, ayl, azh, azl]);
719 let gyr = self.scaled_gyr_from_bytes([gxh, gxl, gyh, gyl, gzh, gzl]);
720
721 let tmp = self.scaled_tmp_from_bytes([tph, tpl]);
722
723 Ok(Data6Dof { acc, gyr, tmp })
724 }
725
726 pub async fn read_6dof_unscaled(&mut self) -> Result<Data6Dof<i16>, TRANSPORT::Error> {
728 let raw: [u8; 14] = self.read_from(Bank0::AccelXoutH).await?;
729 let [axh, axl, ayh, ayl, azh, azl, gxh, gxl, gyh, gyl, gzh, gzl, tph, tpl] = raw;
730
731 let acc = collect_3xi16([axh, axl, ayh, ayl, azh, azl]);
732 let gyr = collect_3xi16([gxh, gxl, gyh, gyl, gzh, gzl]);
733
734 let tmp = i16::from_be_bytes([tph, tpl]);
735
736 Ok(Data6Dof { acc, gyr, tmp })
737 }
738
739 pub async fn set_gyr_offsets(&mut self, offsets: [i16; 3]) -> Result<(), TRANSPORT::Error> {
741 let [[xh, xl], [yh, yl], [zh, zl]]: [[u8; 2]; 3] = offsets.map(|x| (-x).to_be_bytes());
742
743 self.set_user_bank::<Bank2>(false).await?;
744
745 self.transport
746 .write_registers(Bank2::XgOffsH.addr(), &[xh, xl])
747 .await?;
748 self.transport
749 .write_registers(Bank2::YgOffsH.addr(), &[yh, yl])
750 .await?;
751 self.transport
752 .write_registers(Bank2::ZgOffsH.addr(), &[zh, zl])
753 .await?;
754
755 Ok(())
756 }
757
758 pub async fn set_acc_offsets(&mut self, offsets: [i16; 3]) -> Result<(), TRANSPORT::Error> {
760 let [[xh, xl], [yh, yl], [zh, zl]]: [[u8; 2]; 3] = offsets.map(|x| (-x).to_be_bytes());
761
762 self.set_user_bank::<Bank1>(false).await?;
763
764 self.transport
765 .write_registers(Bank1::XaOffsH.addr(), &[xh, xl])
766 .await?;
767 self.transport
768 .write_registers(Bank1::YaOffsH.addr(), &[yh, yl])
769 .await?;
770 self.transport
771 .write_registers(Bank1::ZaOffsH.addr(), &[zh, zl])
772 .await?;
773
774 Ok(())
775 }
776
777 pub async fn new_data_ready(&mut self) -> u8 {
779 self.read_from(Bank0::DataRdyStatus)
780 .await
781 .map_or(0, |[b]| b & 0b1111)
782 }
783
784 pub const fn acc_scalar(&self) -> f32 {
786 self.config.acc_unit.scalar() / self.config.acc_range.divisor()
787 }
788
789 pub const fn gyr_scalar(&self) -> f32 {
791 self.config.gyr_unit.scalar() / self.config.gyr_range.divisor()
792 }
793}
794
795const fn collect_3xi16(values: [u8; 6]) -> [i16; 3] {
797 let [xh, xl, yh, yl, zh, zl] = values;
798 [
799 i16::from_be_bytes([xh, xl]),
800 i16::from_be_bytes([yh, yl]),
801 i16::from_be_bytes([zh, zl]),
802 ]
803}
804
805const fn collect_3xi16_mag(values: [u8; 6]) -> [i16; 3] {
807 let [xl, xh, yl, yh, zl, zh] = values;
808
809 #[cfg(feature = "align-mag")]
810 let mag = [
811 i16::from_be_bytes([xh, xl]),
812 -i16::from_be_bytes([yh, yl]),
813 -i16::from_be_bytes([zh, zl]),
814 ];
815
816 #[cfg(not(feature = "align-mag"))]
817 let mag = [
818 i16::from_be_bytes([xh, xl]),
819 i16::from_be_bytes([yh, yl]),
820 i16::from_be_bytes([zh, zl]),
821 ];
822
823 mag
824}