From 0109fd9648adb5805ae4679f9dcc52d8a691a38d Mon Sep 17 00:00:00 2001 From: Abraham Hamidi Date: Fri, 12 Sep 2025 14:00:02 -0500 Subject: [PATCH 1/2] Fix SPI --- src/bmi2.rs | 13 ++++++++++--- src/bmi2_async.rs | 33 ++++++++++++++++++++------------- src/interface.rs | 11 ++++------- src/interface_async.rs | 11 ++++------- 4 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/bmi2.rs b/src/bmi2.rs index a0a24a0..63ea712 100644 --- a/src/bmi2.rs +++ b/src/bmi2.rs @@ -41,17 +41,21 @@ impl Bmi2, D, N> { } } -impl Bmi2, D, N> +impl Bmi2, D, N> where + SPI: embedded_hal::spi::SpiDevice, D: DelayNs, { /// Create a new Bmi270 device with SPI communication. pub fn new_spi(spi: SPI, delay: D, burst: Burst) -> Self { - Bmi2 { + let mut bmi2 = Bmi2 { iface: SpiInterface { spi }, max_burst: burst.val(), delay, - } + }; + let _ = bmi2.get_chip_id(); + bmi2.delay.delay_us(450); + bmi2 } /// Release I2C and CS. @@ -736,6 +740,9 @@ where self.send_cmd(Cmd::SoftReset)?; self.delay.delay_us(2000); + let _ = self.get_chip_id(); + self.delay.delay_us(450); + // Disable advanced power mode self.disable_power_save()?; diff --git a/src/bmi2_async.rs b/src/bmi2_async.rs index 59b6540..5ffe010 100644 --- a/src/bmi2_async.rs +++ b/src/bmi2_async.rs @@ -1,4 +1,4 @@ -use embedded_hal::delay::DelayNs; +use embedded_hal_async::delay::DelayNs; use fixedvec::FixedVec; use crate::registers::Registers; @@ -41,17 +41,21 @@ impl Bmi2, D, N> { } } -impl Bmi2, D, N> +impl Bmi2, D, N> where + SPI: embedded_hal_async::spi::SpiDevice, D: DelayNs, { /// Create a new Bmi270 device with SPI communication. - pub fn new_spi(spi: SPI, delay: D, burst: Burst) -> Self { - Bmi2 { + pub async fn new_spi(spi: SPI, delay: D, burst: Burst) -> Self { + let mut bmi2 = Bmi2 { iface: SpiInterface { spi }, max_burst: burst.val(), delay, - } + }; + let _ = bmi2.get_chip_id().await; + bmi2.delay.delay_us(450).await; + bmi2 } /// Release I2C and CS. @@ -63,7 +67,7 @@ where impl Bmi2 where I: ReadData> + WriteData>, - D: embedded_hal::delay::DelayNs, // Add constraint for D + D: DelayNs, // Add constraint for D { /// Get the chip id. pub async fn get_chip_id(&mut self) -> Result> { @@ -744,7 +748,7 @@ where pwr_conf.power_save = false; self.set_pwr_conf(pwr_conf).await?; // Critical delay after disabling power save - self.delay.delay_us(450); + self.delay.delay_us(450).await; Ok(()) } @@ -754,7 +758,7 @@ where pwr_conf.power_save = true; self.set_pwr_conf(pwr_conf).await?; // Critical delay after enabling power save - self.delay.delay_us(450); + self.delay.delay_us(450).await; Ok(()) } @@ -768,7 +772,10 @@ where // Reset Chip, mandatory per datasheet self.send_cmd(Cmd::SoftReset).await?; - self.delay.delay_us(2000); + self.delay.delay_us(2000).await; + + let _ = self.get_chip_id().await?; + self.delay.delay_us(450).await; // Disable advanced power mode self.disable_power_save().await?; @@ -792,7 +799,7 @@ where let init_ctrl = self.get_init_ctrl().await?; self.set_init_ctrl(init_ctrl & 0b1111_1110).await?; - self.delay.delay_us(450); + self.delay.delay_us(450).await; while offset < max_len { // INIT_ADDR should point to 16-bit words @@ -822,17 +829,17 @@ where self.iface.write(vec.as_mut_slice()).await?; offset += chunk_size; - self.delay.delay_us(2); + self.delay.delay_us(2).await; } // This operation must not be performed more than once after POR or soft reset. self.set_init_ctrl(1).await?; - self.delay.delay_us(2); + self.delay.delay_us(2).await; self.enable_power_save().await?; // Initialization takes at most 20ms per datasheet - self.delay.delay_us(20_000); + self.delay.delay_us(20_000).await; let internal_status = self.iface.read_reg(Registers::INTERNAL_STATUS).await?; diff --git a/src/interface.rs b/src/interface.rs index 0476c85..bc54719 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -37,15 +37,12 @@ where { type Error = Error; fn write(&mut self, payload: &mut [u8]) -> Result<(), Self::Error> { - payload[0] += 0x80; - // `write` asserts and deasserts CS for us. No need to do it manually! - self.spi.write(payload).map_err(Error::Comm) } fn write_reg(&mut self, register: u8, data: u8) -> Result<(), Self::Error> { - let payload: [u8; 2] = [register + 0x80, data]; + let payload: [u8; 2] = [register, data]; // `write` asserts and deasserts CS for us. No need to do it manually! @@ -87,13 +84,13 @@ where } fn read_reg(&mut self, register: u8) -> Result { - let mut payload = [register, 0]; + let mut payload = [register + 0x80, 0, 0]; // `read` asserts and deasserts CS for us. No need to do it manually! - let res = self.spi.read(&mut payload).map_err(Error::Comm); + let res = self.spi.transfer_in_place(&mut payload).map_err(Error::Comm); match res { - Ok(_) => Ok(payload[1]), + Ok(_) => Ok(payload[2]), Err(e) => Err(e), } } diff --git a/src/interface_async.rs b/src/interface_async.rs index fd2afeb..16c314e 100644 --- a/src/interface_async.rs +++ b/src/interface_async.rs @@ -45,15 +45,12 @@ where { type Error = Error; async fn write(&mut self, payload: &mut [u8]) -> Result<(), Self::Error> { - payload[0] += 0x80; - // `write` asserts and deasserts CS for us. No need to do it manually! - self.spi.write(payload).await.map_err(Error::Comm) } async fn write_reg(&mut self, register: u8, data: u8) -> Result<(), Self::Error> { - let payload: [u8; 2] = [register + 0x80, data]; + let payload: [u8; 2] = [register, data]; // `write` asserts and deasserts CS for us. No need to do it manually! @@ -97,13 +94,13 @@ where } async fn read_reg(&mut self, register: u8) -> Result { - let mut payload = [register, 0]; + let mut payload = [register + 0x80, 00, 00]; // `read` asserts and deasserts CS for us. No need to do it manually! - let res = self.spi.read(&mut payload).await.map_err(Error::Comm); + let res = self.spi.transfer_in_place(&mut payload).await.map_err(Error::Comm); match res { - Ok(_) => Ok(payload[1]), + Ok(_) => Ok(payload[2]), Err(e) => Err(e), } } From 7c54df8575c9db97875e2dd6b37044f2cd3f2395 Mon Sep 17 00:00:00 2001 From: Abraham Hamidi Date: Tue, 23 Sep 2025 18:46:41 -0500 Subject: [PATCH 2/2] Make SPI read function compatible with I2C examples --- src/interface_async.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/interface_async.rs b/src/interface_async.rs index 16c314e..cc1cdd9 100644 --- a/src/interface_async.rs +++ b/src/interface_async.rs @@ -1,6 +1,7 @@ pub use crate::interface_common::{I2cAddr, I2cInterface, SpiInterface}; use crate::types::Error; +use embedded_hal::spi::Operation; use embedded_hal_async::i2c::I2c; use embedded_hal_async::spi::SpiDevice; @@ -86,10 +87,21 @@ where { type Error = Error; async fn read(&mut self, payload: &mut [u8]) -> Result<(), Self::Error> { - // `read` asserts and deasserts CS for us. No need to do it manually! - let res = self.spi.read(payload).await.map_err(Error::Comm); + if payload.is_empty() { + return Ok(()); + } + let addr = payload[0] | 0x80; + let mut dummy = [0u8; 1]; + + self.spi + .transaction(&mut [ + Operation::Write(&[addr]), // send address with R bit + Operation::Read(&mut dummy), // consume 1 dummy byte + Operation::Read(&mut payload[1..]), // read real data directly into caller buffer + ]) + .await + .map_err(Error::Comm)?; - res?; Ok(()) }