diff --git a/esp-hal-common/src/i2c.rs b/esp-hal-common/src/i2c.rs index 8f2c199e5a6..51372d723c7 100644 --- a/esp-hal-common/src/i2c.rs +++ b/esp-hal-common/src/i2c.rs @@ -274,6 +274,20 @@ where scl: impl Peripheral

+ 'd, frequency: HertzU32, clocks: &Clocks, + ) -> Self { + Self::new_with_timeout(i2c, sda, scl, frequency, clocks, None) + } + + /// Create a new I2C instance with a custom timeout value. + /// This will enable the peripheral but the peripheral won't get + /// automatically disabled when this gets dropped. + pub fn new_with_timeout( + i2c: impl Peripheral

+ 'd, + sda: impl Peripheral

+ 'd, + scl: impl Peripheral

+ 'd, + frequency: HertzU32, + clocks: &Clocks, + timeout: Option, ) -> Self { crate::into_ref!(i2c, sda, scl); @@ -302,7 +316,7 @@ where .connect_peripheral_to_output(i2c.peripheral.sda_output_signal()) .connect_input_to_peripheral(i2c.peripheral.sda_input_signal()); - i2c.peripheral.setup(frequency, clocks); + i2c.peripheral.setup(frequency, clocks, timeout); i2c } @@ -638,7 +652,7 @@ pub trait Instance { fn i2c_number(&self) -> usize; - fn setup(&mut self, frequency: HertzU32, clocks: &Clocks) { + fn setup(&mut self, frequency: HertzU32, clocks: &Clocks, timeout: Option) { self.register_block().ctr().modify(|_, w| unsafe { // Clear register w.bits(0) @@ -671,9 +685,9 @@ pub trait Instance { // Configure frequency #[cfg(esp32)] - self.set_frequency(clocks.i2c_clock.convert(), frequency); + self.set_frequency(clocks.i2c_clock.convert(), frequency, timeout); #[cfg(not(esp32))] - self.set_frequency(clocks.xtal_clock.convert(), frequency); + self.set_frequency(clocks.xtal_clock.convert(), frequency, timeout); self.update_config(); @@ -750,7 +764,7 @@ pub trait Instance { /// Sets the frequency of the I2C interface by calculating and applying the /// associated timings - corresponds to i2c_ll_cal_bus_clk and /// i2c_ll_set_bus_timing in ESP-IDF - fn set_frequency(&mut self, source_clk: HertzU32, bus_freq: HertzU32) { + fn set_frequency(&mut self, source_clk: HertzU32, bus_freq: HertzU32, timeout: Option) { let source_clk = source_clk.raw(); let bus_freq = bus_freq.raw(); @@ -761,7 +775,12 @@ pub trait Instance { let sda_sample = scl_high / 2; let setup = half_cycle; let hold = half_cycle; - let tout = half_cycle * 20; // default we set the timeout value to 10 bus cycles. + let tout = if let Some(timeout) = timeout { + timeout + } else { + // default we set the timeout value to 10 bus cycles + half_cycle * 20 + }; // SCL period. According to the TRM, we should always subtract 1 to SCL low // period @@ -823,7 +842,7 @@ pub trait Instance { /// Sets the frequency of the I2C interface by calculating and applying the /// associated timings - corresponds to i2c_ll_cal_bus_clk and /// i2c_ll_set_bus_timing in ESP-IDF - fn set_frequency(&mut self, source_clk: HertzU32, bus_freq: HertzU32) { + fn set_frequency(&mut self, source_clk: HertzU32, bus_freq: HertzU32, timeout: Option) { let source_clk = source_clk.raw(); let bus_freq = bus_freq.raw(); @@ -838,8 +857,12 @@ pub trait Instance { let sda_sample = half_cycle / 2 - 1; let setup = half_cycle; let hold = half_cycle; - // default we set the timeout value to 10 bus cycles - let tout = half_cycle * 20; + let tout = if let Some(timeout) = timeout { + timeout + } else { + // default we set the timeout value to 10 bus cycles + half_cycle * 20 + }; // scl period let scl_low_period = scl_low - 1; @@ -877,7 +900,7 @@ pub trait Instance { /// Sets the frequency of the I2C interface by calculating and applying the /// associated timings - corresponds to i2c_ll_cal_bus_clk and /// i2c_ll_set_bus_timing in ESP-IDF - fn set_frequency(&mut self, source_clk: HertzU32, bus_freq: HertzU32) { + fn set_frequency(&mut self, source_clk: HertzU32, bus_freq: HertzU32, timeout: Option) { let source_clk = source_clk.raw(); let bus_freq = bus_freq.raw(); @@ -901,9 +924,14 @@ pub trait Instance { let sda_sample = half_cycle / 2 + scl_wait_high; let setup = half_cycle; let hold = half_cycle; - // default we set the timeout value to about 10 bus cycles - // log(20*half_cycle)/log(2) = log(half_cycle)/log(2) + log(20)/log(2) - let tout = (4 * 8 - (5 * half_cycle).leading_zeros()) + 2; + + let tout = if let Some(timeout) = timeout { + timeout + } else { + // default we set the timeout value to about 10 bus cycles + // log(20*half_cycle)/log(2) = log(half_cycle)/log(2) + log(20)/log(2) + (4 * 8 - (5 * half_cycle).leading_zeros()) + 2 + }; // According to the Technical Reference Manual, the following timings must be // subtracted by 1. However, according to the practical measurement and