From 95a75e23925bef576c26e452ece5c99d5875749e Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Thu, 11 Jan 2024 23:38:10 +1100 Subject: [PATCH 1/5] Add ms_since function to McycleDelay --- src/delay.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/delay.rs b/src/delay.rs index 98d12e8..12b9602 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -41,6 +41,11 @@ impl McycleDelay { while McycleDelay::cycles_since(start_cycle_count) <= cycle_count {} } + + pub fn ms_since(&mut self, previous_cycle_count: u64) -> u64 { + let elapsed_cycles = Self::cycles_since(previous_cycle_count); + (elapsed_cycles * 1000) / self.core_frequency as u64 + } } // embedded-hal 1.0 traits From 789f8c4cbfd3586b82cb696296ede75039b8b8bd Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Thu, 11 Jan 2024 23:39:44 +1100 Subject: [PATCH 2/5] Use McycleDelay for i2c timeouts --- src/i2c.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/i2c.rs b/src/i2c.rs index 1eb5b25..522d6c4 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -23,6 +23,7 @@ use embedded_hal_zero::blocking::i2c::Read as ReadZero; use embedded_hal_zero::blocking::i2c::Write as WriteZero; use embedded_time::rate::Hertz; +use crate::delay::McycleDelay; use crate::{clock::Clocks, pac}; use self::private::Sealed; @@ -237,13 +238,15 @@ where .set_bit() }); + // We don't know what the CPU frequency is. Assume maximum of 192Mhz + // This might make our timeouts longer than expected if frequency is lower. + let mut delay = McycleDelay::new(192_000_000); for value in tmp.iter_mut() { - let mut timeout_countdown = self.timeout; + let start_time = McycleDelay::get_cycle_count(); while self.i2c.i2c_fifo_config_1.read().rx_fifo_cnt().bits() == 0 { - if timeout_countdown == 0 { + if delay.ms_since(start_time) > self.timeout.into() { return Err(Error::Timeout); } - timeout_countdown -= 1; } *value = self.i2c.i2c_fifo_rdata.read().i2c_fifo_rdata().bits(); } @@ -304,21 +307,27 @@ where .set_bit() }); + // We don't know what the CPU frequency is. Assume maximum of 192Mhz + // This might make our timeouts longer than expected if frequency is lower. + let mut delay = McycleDelay::new(192_000_000); for value in tmp.iter() { - let mut timeout_countdown = self.timeout; + let start_time = McycleDelay::get_cycle_count(); while self.i2c.i2c_fifo_config_1.read().tx_fifo_cnt().bits() == 0 { - if timeout_countdown == 0 { + if delay.ms_since(start_time) > self.timeout.into() { return Err(Error::Timeout); } - timeout_countdown -= 1; } self.i2c .i2c_fifo_wdata .write(|w| unsafe { w.i2c_fifo_wdata().bits(*value) }); } + let start_time = McycleDelay::get_cycle_count(); while self.i2c.i2c_bus_busy.read().sts_i2c_bus_busy().bit_is_set() { // wait for transfer to finish + if delay.ms_since(start_time) > self.timeout.into() { + return Err(Error::Timeout); + } } self.i2c From 42572e152459f19dbfbf3b07cef3658b394e2d54 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Thu, 11 Jan 2024 23:40:47 +1100 Subject: [PATCH 3/5] Wait for i2c tx fifo empty to disable xmit --- src/i2c.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/i2c.rs b/src/i2c.rs index 522d6c4..05e111e 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -322,6 +322,14 @@ where .write(|w| unsafe { w.i2c_fifo_wdata().bits(*value) }); } + let start_time = McycleDelay::get_cycle_count(); + while self.i2c.i2c_fifo_config_1.read().tx_fifo_cnt().bits() < 2 { + // wait for write fifo to be empty + if delay.ms_since(start_time) > self.timeout.into() { + return Err(Error::Timeout); + } + } + let start_time = McycleDelay::get_cycle_count(); while self.i2c.i2c_bus_busy.read().sts_i2c_bus_busy().bit_is_set() { // wait for transfer to finish From dcd6c9f65d7ff10255466a229f6d316bc7b57ba2 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Thu, 11 Jan 2024 23:57:30 +1100 Subject: [PATCH 4/5] Update i2c timeout docs --- src/i2c.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/i2c.rs b/src/i2c.rs index 05e111e..8770f67 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -99,8 +99,11 @@ where /// I2C peripheral operating in master mode supporting seven bit addressing pub struct I2c { + /// i2c peripheral instance i2c: I2C, + /// sda and scl pins for this i2c interface pins: PINS, + /// timeout (in milliseconds) timeout: u16, } @@ -175,8 +178,7 @@ where (self.i2c, self.pins) } - /// Set the timeout when waiting for fifo (rx and tx). - /// It's not a time unit but the number of cycles to wait. + /// Set the timeout (in milliseconds) when waiting for fifo (rx and tx). /// This defaults to 2048 pub fn set_timeout(&mut self, timeout: u16) { self.timeout = timeout; From 103da0fc625cd19faf4aeb31749bf63becea086b Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Fri, 12 Jan 2024 00:04:50 +1100 Subject: [PATCH 5/5] I2C: Replace millisecond with microsecond timeouts --- src/delay.rs | 5 +++++ src/i2c.rs | 14 +++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/delay.rs b/src/delay.rs index 12b9602..affeed2 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -46,6 +46,11 @@ impl McycleDelay { let elapsed_cycles = Self::cycles_since(previous_cycle_count); (elapsed_cycles * 1000) / self.core_frequency as u64 } + + pub fn us_since(&mut self, previous_cycle_count: u64) -> u64 { + let elapsed_cycles = Self::cycles_since(previous_cycle_count); + (elapsed_cycles * 1_000_000) / self.core_frequency as u64 + } } // embedded-hal 1.0 traits diff --git a/src/i2c.rs b/src/i2c.rs index 8770f67..b21d021 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -103,7 +103,7 @@ pub struct I2c { i2c: I2C, /// sda and scl pins for this i2c interface pins: PINS, - /// timeout (in milliseconds) + /// timeout (in microseconds) timeout: u16, } @@ -178,8 +178,8 @@ where (self.i2c, self.pins) } - /// Set the timeout (in milliseconds) when waiting for fifo (rx and tx). - /// This defaults to 2048 + /// Set the timeout (in microseconds) when waiting for fifo (rx and tx). + /// This defaults to 2000us (2 milliseconds) pub fn set_timeout(&mut self, timeout: u16) { self.timeout = timeout; } @@ -246,7 +246,7 @@ where for value in tmp.iter_mut() { let start_time = McycleDelay::get_cycle_count(); while self.i2c.i2c_fifo_config_1.read().rx_fifo_cnt().bits() == 0 { - if delay.ms_since(start_time) > self.timeout.into() { + if delay.us_since(start_time) > self.timeout.into() { return Err(Error::Timeout); } } @@ -315,7 +315,7 @@ where for value in tmp.iter() { let start_time = McycleDelay::get_cycle_count(); while self.i2c.i2c_fifo_config_1.read().tx_fifo_cnt().bits() == 0 { - if delay.ms_since(start_time) > self.timeout.into() { + if delay.us_since(start_time) > self.timeout.into() { return Err(Error::Timeout); } } @@ -327,7 +327,7 @@ where let start_time = McycleDelay::get_cycle_count(); while self.i2c.i2c_fifo_config_1.read().tx_fifo_cnt().bits() < 2 { // wait for write fifo to be empty - if delay.ms_since(start_time) > self.timeout.into() { + if delay.us_since(start_time) > self.timeout.into() { return Err(Error::Timeout); } } @@ -335,7 +335,7 @@ where let start_time = McycleDelay::get_cycle_count(); while self.i2c.i2c_bus_busy.read().sts_i2c_bus_busy().bit_is_set() { // wait for transfer to finish - if delay.ms_since(start_time) > self.timeout.into() { + if delay.us_since(start_time) > self.timeout.into() { return Err(Error::Timeout); } }