diff --git a/firmware/rust1/src/bin/heizung.rs b/firmware/rust1/src/bin/heizung.rs index 020332467454b578401c7176f5f0d9e02a99e88b..2ce1775c035a086c55a32dcb0f6b0f52d65401e7 100644 --- a/firmware/rust1/src/bin/heizung.rs +++ b/firmware/rust1/src/bin/heizung.rs @@ -72,7 +72,12 @@ fn format_scan_result<const N : usize>(msg : &mut String<N>, scan_result : [Scan Ok(()) } -async fn _clockStretch<'d, SCL: gpio::Pin>(scl: &mut Flex<'d, SCL>) -> Result<(), i2c::Error> { + +// adapted from arduino-pico: +// https://github.com/earlephilhower/arduino-pico/blob/6e52b72523b11470b2ad2b0578ca1500be238108/libraries/Wire/src/Wire.cpp#L257 +// This seems to be the only way to do zero-length writes: +// see https://github.com/raspberrypi/pico-sdk/issues/238 +async fn handle_clock_stretching<'d, SCL: gpio::Pin>(scl: &mut Flex<'d, SCL>) -> Result<(), i2c::Error> { use i2c::Error::*; use i2c::AbortReason::*; @@ -88,26 +93,24 @@ async fn _clockStretch<'d, SCL: gpio::Pin>(scl: &mut Flex<'d, SCL>) -> Result<() Second(_) => Err(Abort(ArbitrationLoss)), } } - -// adapted from https://github.com/earlephilhower/arduino-pico/blob/6e52b72523b11470b2ad2b0578ca1500be238108/libraries/Wire/src/Wire.cpp#L257 async fn i2c_write_zero_bytes_middle_part<'d, SCL: gpio::Pin, SDA: gpio::Pin, const FREQ : u64>( mut addr: u16, delay: Duration, scl: &mut Flex<'d, SCL>, sda: &mut Flex<'d, SDA>) -> Result<(), i2c::Error> { sda.set_as_input(); Timer::after(delay).await; scl.set_as_input(); - _clockStretch(scl).await?; + handle_clock_stretching(scl).await?; sda.set_as_output(); Timer::after(delay).await; scl.set_as_output(); Timer::after(delay).await; - for i in 0..8 { + for _ in 0..8 { addr <<= 1; sda.set_level(if (addr & (1 << 7)) != 0 { gpio::Level::High } else { gpio::Level::Low }); Timer::after(delay).await; scl.set_as_input(); Timer::after(delay).await; - _clockStretch(scl).await?; + handle_clock_stretching(scl).await?; scl.set_as_output(); Timer::after(Duration::from_micros(5)).await; // Ensure we don't change too close to clock edge } @@ -115,7 +118,7 @@ async fn i2c_write_zero_bytes_middle_part<'d, SCL: gpio::Pin, SDA: gpio::Pin, co sda.set_as_input(); Timer::after(delay).await; scl.set_as_input(); - _clockStretch(scl).await?; + handle_clock_stretching(scl).await?; let result = if sda.is_low() { Ok(()) @@ -129,13 +132,12 @@ async fn i2c_write_zero_bytes_middle_part<'d, SCL: gpio::Pin, SDA: gpio::Pin, co result } -async fn i2c_write_zero_bytes<SCL: gpio::Pin, SDA: gpio::Pin, const FREQ : u64>(mut addr: u16, scl: &mut SCL, sda: &mut SDA) +async fn i2c_write_zero_bytes<SCL: gpio::Pin, SDA: gpio::Pin, const FREQ : u64>(addr: u16, scl: &mut SCL, sda: &mut SDA) -> Result<(), i2c::Error> { use i2c::Error::*; use i2c::AbortReason::*; let delay = Duration::from_micros((1000000 / FREQ) / 2); - let ack = false; let mut sda = Flex::new(sda); let mut scl = Flex::new(scl); @@ -181,18 +183,13 @@ async fn i2c_task(mut i2c_peri: embassy_rp::peripherals::I2C0, const MAX_ADDRESS : u8 = 128; let mut scan_result = [ScanResult::Error; MAX_ADDRESS as usize]; for i in 0..MAX_ADDRESS { - match i2c_write_zero_bytes::<_, _, 400_000>(i as u16, &mut scl, &mut sda).await { - Result::Ok(()) => { - //info!("I2C ok: {}", i); - scan_result[i as usize] = ScanResult::Ack - }, - Result::Err(Abort(NoAcknowledge)) => - scan_result[i as usize] = ScanResult::NAck, - Result::Err(AddressReserved(_)) => - scan_result[i as usize] = ScanResult::Reserved, + scan_result[i as usize] = match i2c_write_zero_bytes::<_, _, 400_000>(i as u16, &mut scl, &mut sda).await { + Result::Ok(()) => ScanResult::Ack, + Result::Err(Abort(NoAcknowledge)) => ScanResult::NAck, + Result::Err(AddressReserved(_)) => ScanResult::Reserved, Result::Err(e) => { - scan_result[i as usize] = ScanResult::Error; - warn!("I2C problem: {:?}", e); + warn!("I2C problem: {:02x}: {:?}", i, e); + ScanResult::Error } } }