From e5d68fdcb1e0cecff9840b262b287624e52ee42f Mon Sep 17 00:00:00 2001 From: Sebastian Urban Date: Mon, 17 Jun 2024 13:17:07 +0200 Subject: [PATCH] supply: reset STUSB4500 when BQ25713 fails When BQ25713 has no I2C communication, this is often caused by STUSB4500 blocking the I2C bus. Therefore, reset the STUSB4500 in this case. --- openemc-firmware/src/bq25713.rs | 8 ++++++-- openemc-firmware/src/main.rs | 19 +++++++++++++++++-- openemc-firmware/src/supply/stusb4500/mod.rs | 7 +++++++ openemc-firmware/src/supply/stusb4500/nvm.rs | 9 ++++++--- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/openemc-firmware/src/bq25713.rs b/openemc-firmware/src/bq25713.rs index eaa003a..080c141 100644 --- a/openemc-firmware/src/bq25713.rs +++ b/openemc-firmware/src/bq25713.rs @@ -708,11 +708,15 @@ where } /// Call this periodically (approx. every second) to handle communication with the device. - pub fn periodic(&mut self, i2c: &mut I2C, chrg_ok: bool) { - if let Err(err) = self.do_periodic(i2c, chrg_ok) { + pub fn periodic(&mut self, i2c: &mut I2C, chrg_ok: bool) -> Result<()> { + let res = self.do_periodic(i2c, chrg_ok); + + if let Err(err) = &res { defmt::warn!("BQ25713 failed: {}", err); self.initialized = false; } + + res } /// Update status and measurements without programming charger. diff --git a/openemc-firmware/src/main.rs b/openemc-firmware/src/main.rs index 0ec59e8..77d3896 100644 --- a/openemc-firmware/src/main.rs +++ b/openemc-firmware/src/main.rs @@ -578,7 +578,7 @@ mod app { // Check that battery voltage is sufficient. if let (Some(bq25713), Some(i2c2)) = (&mut bq25713, &mut i2c2) { - bq25713.periodic(i2c2, board.check_bq25713_chrg_ok()); + let _ = bq25713.periodic(i2c2, board.check_bq25713_chrg_ok()); watchman.force_pet(); let v_bat = loop { @@ -910,6 +910,16 @@ mod app { defmt::unwrap!(stusb4500_periodic::spawn_after(500u64.millis())); } + /// STUSB4500 reset task. + #[task(shared = [stusb4500])] + fn stusb4500_reset(mut cx: stusb4500_reset::Context) { + cx.shared.stusb4500.lock(|stusb4500| { + if let Some(stusb4500) = stusb4500.as_mut() { + stusb4500.reset(); + } + }); + } + /// Updates the power supply status. #[task( shared = [i2c2, stusb4500, max14636, bq25713, power_supply, irq, board, &power_mode], @@ -1023,7 +1033,12 @@ mod app { |i2c2, bq25713, battery, irq, board| { if let Some(bq25713) = bq25713.as_mut() { let i2c2 = defmt::unwrap!(i2c2.as_mut()); - bq25713.periodic(i2c2, board.check_bq25713_chrg_ok()); + let res = bq25713.periodic(i2c2, board.check_bq25713_chrg_ok()); + + if let Err(bq25713::Error::I2c) = &res { + defmt::warn!("Resetting STUSB4500 due to BQ25713 I2C error"); + let _ = stusb4500_reset::spawn(); + } let mut ac = false; if let Some(status) = bq25713.status().cloned() { diff --git a/openemc-firmware/src/supply/stusb4500/mod.rs b/openemc-firmware/src/supply/stusb4500/mod.rs index 71a3656..454cd91 100644 --- a/openemc-firmware/src/supply/stusb4500/mod.rs +++ b/openemc-firmware/src/supply/stusb4500/mod.rs @@ -790,6 +790,13 @@ where pub fn reset_pin_level(&self) -> bool { matches!(self.reset, ResetState::PinResetHigh(_)) } + + /// Initiates a reset. + pub fn reset(&mut self) { + defmt::info!("Initiating STUSB4500 reset by request"); + self.reset = ResetState::None; + self.start_pin_reset(); + } } // Register definitions. diff --git a/openemc-firmware/src/supply/stusb4500/nvm.rs b/openemc-firmware/src/supply/stusb4500/nvm.rs index cbfa2d7..7297f0c 100644 --- a/openemc-firmware/src/supply/stusb4500/nvm.rs +++ b/openemc-firmware/src/supply/stusb4500/nvm.rs @@ -38,10 +38,13 @@ where I2C: i2c::Write + i2c::WriteRead, { /// Mask of programmable bits within NVM. + #[rustfmt::skip] pub const NVM_PROGRAMABLE: [u8; 40] = [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x20, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x20, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; /// Read I2C register(s).