From 03c3e9ac03fc26dce2bb7d2bbf8efce35fe46960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirco=20Telth=C3=B6rster?= Date: Wed, 16 Mar 2022 09:10:22 +0100 Subject: [PATCH 01/11] enable Polling --- src/storage.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/storage.rs b/src/storage.rs index de645c1..4c9649f 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -70,7 +70,7 @@ where } let page_size = self.eeprom.page_size(); while !bytes.is_empty() { - let _ = nb::block!(self.count_down.wait()); // CountDown::wait() never fails + //let _ = nb::block!(self.count_down.wait()); // CountDown::wait() never fails let this_page_offset = offset as usize % page_size; let this_page_remaining = page_size - this_page_offset; let chunk_size = min(bytes.len(), this_page_remaining); @@ -80,10 +80,24 @@ where // TODO At least ST's eeproms allow polling, i.e. trying the next i2c access which will // just be NACKed as long as the device is still busy. This could potentially speed up // the write process. + loop { + match self.eeprom.read_byte(0){ + // ready + Ok(_) => { + break; + } + + // not yet ready + Err(Error::I2C(_)) => {} + + // any other error + Err(_) => {} + } + } // TODO Currently outdated comment: // A (theoretically needless) delay after the last page write ensures that the user can // call Storage::write() again immediately. - self.count_down.start(Duration::from_millis(5)); + //self.count_down.start(Duration::from_millis(5)); } Ok(()) } From ae151beff09663279e6f4ba5bc4f77ac740229a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirco=20Telth=C3=B6rster?= Date: Wed, 16 Mar 2022 14:09:41 +0100 Subject: [PATCH 02/11] added timeout to write polling --- Cargo.toml | 1 + src/storage.rs | 43 +++++++++++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 662900f..09e8cb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ resolver = "2" embedded-hal = "0.2" embedded-storage = "0.2.0" nb = "1.0.0" +embedded-timeout-macros = "0.3" [dev-dependencies] linux-embedded-hal = "0.3" diff --git a/src/storage.rs b/src/storage.rs index 4c9649f..ae2f02b 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -8,6 +8,7 @@ use embedded_hal::{ timer::CountDown, }; use embedded_storage::ReadStorage; +use embedded_timeout_macros::repeat_timeout; /// Common methods impl Storage {} @@ -70,7 +71,7 @@ where } let page_size = self.eeprom.page_size(); while !bytes.is_empty() { - //let _ = nb::block!(self.count_down.wait()); // CountDown::wait() never fails + let _ = nb::block!(self.count_down.wait()); // CountDown::wait() never fails let this_page_offset = offset as usize % page_size; let this_page_remaining = page_size - this_page_offset; let chunk_size = min(bytes.len(), this_page_remaining); @@ -80,24 +81,38 @@ where // TODO At least ST's eeproms allow polling, i.e. trying the next i2c access which will // just be NACKed as long as the device is still busy. This could potentially speed up // the write process. - loop { - match self.eeprom.read_byte(0){ - // ready - Ok(_) => { - break; - } + self.count_down.start(Duration::from_millis(10)); + repeat_timeout!( + &mut self.count_down, + { + match self.eeprom.read_byte(0){ + // ready (ACK) + Ok(_) => { + Ok(()) + } - // not yet ready - Err(Error::I2C(_)) => {} + // not yet ready (NACK) + Err(Error::I2C(_)) => {Err(())} - // any other error - Err(_) => {} - } - } + // any other error + Err(e) => { + return Err(e); + } + } + }, + (_ack) { + // eeprom done writing => Leaving + break; + }; + (_nack) { + // eeprom still busy + continue; + }; + ); // TODO Currently outdated comment: // A (theoretically needless) delay after the last page write ensures that the user can // call Storage::write() again immediately. - //self.count_down.start(Duration::from_millis(5)); + self.count_down.start(Duration::from_millis(5)); } Ok(()) } From 2f0221c0697ef9fcac506d6c91475167a5317bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirco=20Telth=C3=B6rster?= Date: Wed, 16 Mar 2022 16:05:55 +0100 Subject: [PATCH 03/11] fix --- src/storage.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storage.rs b/src/storage.rs index ae2f02b..847a62b 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -71,7 +71,7 @@ where } let page_size = self.eeprom.page_size(); while !bytes.is_empty() { - let _ = nb::block!(self.count_down.wait()); // CountDown::wait() never fails + //let _ = nb::block!(self.count_down.wait()); // CountDown::wait() never fails let this_page_offset = offset as usize % page_size; let this_page_remaining = page_size - this_page_offset; let chunk_size = min(bytes.len(), this_page_remaining); @@ -112,7 +112,7 @@ where // TODO Currently outdated comment: // A (theoretically needless) delay after the last page write ensures that the user can // call Storage::write() again immediately. - self.count_down.start(Duration::from_millis(5)); + //self.count_down.start(Duration::from_millis(5)); } Ok(()) } From c5a6e3b6386a53e7859c5ff8f60f5ca2527d8a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirco=20Telth=C3=B6rster?= Date: Mon, 4 Apr 2022 11:38:16 +0200 Subject: [PATCH 04/11] Added distinction between polling and no polling support --- src/eeprom24x.rs | 68 ++++++++++++++++++++++++++++++------------------ src/lib.rs | 10 +++++++ src/storage.rs | 60 +++++++++++++++++++++++------------------- 3 files changed, 86 insertions(+), 52 deletions(-) diff --git a/src/eeprom24x.rs b/src/eeprom24x.rs index ca96c08..b275eec 100644 --- a/src/eeprom24x.rs +++ b/src/eeprom24x.rs @@ -1,4 +1,8 @@ -use crate::{addr_size, page_size, private, Eeprom24x, Error, SlaveAddr}; +use crate::{ + addr_size, page_size, + polling::{self, NoPolling, Polling}, + private, Eeprom24x, Error, SlaveAddr, +}; use core::marker::PhantomData; use embedded_hal::blocking::i2c::{Write, WriteRead}; @@ -25,6 +29,18 @@ impl MultiSizeAddr for addr_size::TwoBytes { } } +pub trait HasPollingSupport { + const SUPPORT: bool; +} + +impl HasPollingSupport for polling::Polling { + const SUPPORT: bool = true; +} + +impl HasPollingSupport for polling::NoPolling { + const SUPPORT: bool = false; +} + /// Common methods impl Eeprom24x { /// Destroy driver instance, return I²C bus instance. @@ -124,6 +140,7 @@ where i2c, address, address_bits: 4, + polling: false, _ps: PhantomData, _as: PhantomData, } @@ -131,17 +148,17 @@ where } macro_rules! impl_create { - ( $dev:expr, $part:expr, $address_bits:expr, $create:ident ) => { + ( $dev:expr, $part:expr, $address_bits:expr, $create:ident, $HPS:ident ) => { impl_create! { @gen [$create, $address_bits, - concat!("Create a new instance of a ", $dev, " device (e.g. ", $part, ")")] + concat!("Create a new instance of a ", $dev, " device (e.g. ", $part, ")"), $HPS] } }; - (@gen [$create:ident, $address_bits:expr, $doc:expr] ) => { + (@gen [$create:ident, $address_bits:expr, $doc:expr, $HPS:ident] ) => { #[doc = $doc] pub fn $create(i2c: I2C, address: SlaveAddr) -> Self { - Self::new(i2c, address, $address_bits) + Self::new(i2c, address, $address_bits, $HPS::SUPPORT) } }; } @@ -149,32 +166,33 @@ macro_rules! impl_create { // This macro could be simplified once https://github.com/rust-lang/rust/issues/42863 is fixed. macro_rules! impl_for_page_size { ( $AS:ident, $addr_bytes:expr, $PS:ident, $page_size:expr, - $( [ $dev:expr, $part:expr, $address_bits:expr, $create:ident ] ),* ) => { + $( [ $dev:expr, $part:expr, $address_bits:expr, $create:ident, $HPS:ident ] ),* ) => { impl_for_page_size!{ @gen [$AS, $addr_bytes, $PS, $page_size, concat!("Specialization for devices with a page size of ", stringify!($page_size), " bytes."), concat!("Create generic instance for devices with a page size of ", stringify!($page_size), " bytes."), - $( [ $dev, $part, $address_bits, $create ] ),* ] + $( [ $dev, $part, $address_bits, $create, $HPS ] ),* ] } }; (@gen [$AS:ident, $addr_bytes:expr, $PS:ident, $page_size:expr, $doc_impl:expr, $doc_new:expr, - $( [ $dev:expr, $part:expr, $address_bits:expr, $create:ident ] ),* ] ) => { + $( [ $dev:expr, $part:expr, $address_bits:expr, $create:ident, $HPS:ident] ),* ] ) => { #[doc = $doc_impl] impl Eeprom24x where - I2C: Write + I2C: Write, { $( - impl_create!($dev, $part, $address_bits, $create); + impl_create!($dev, $part, $address_bits, $create, $HPS); )* #[doc = $doc_new] - fn new(i2c: I2C, address: SlaveAddr, address_bits: u8) -> Self { + fn new(i2c: I2C, address: SlaveAddr, address_bits: u8, polling_support: bool) -> Self { Eeprom24x { i2c, address, address_bits, + polling: polling_support, _ps: PhantomData, _as: PhantomData, } @@ -257,48 +275,48 @@ impl_for_page_size!( 1, B8, 8, - ["24x01", "AT24C01", 7, new_24x01], - ["24x02", "AT24C02", 8, new_24x02] + ["24x01", "AT24C01", 7, new_24x01, NoPolling], + ["24x02", "AT24C02", 8, new_24x02, NoPolling] ); impl_for_page_size!( OneByte, 1, B16, 16, - ["24x04", "AT24C04", 9, new_24x04], - ["24x08", "AT24C08", 10, new_24x08], - ["24x16", "AT24C16", 11, new_24x16], - ["M24C01", "M24C01", 7, new_m24x01], - ["M24C02", "M24C02", 8, new_m24x02] + ["24x04", "AT24C04", 9, new_24x04, NoPolling], + ["24x08", "AT24C08", 10, new_24x08, NoPolling], + ["24x16", "AT24C16", 11, new_24x16, NoPolling], + ["M24C01", "M24C01", 7, new_m24x01, Polling], + ["M24C02", "M24C02", 8, new_m24x02, Polling] ); impl_for_page_size!( TwoBytes, 2, B32, 32, - ["24x32", "AT24C32", 12, new_24x32], - ["24x64", "AT24C64", 13, new_24x64] + ["24x32", "AT24C32", 12, new_24x32, NoPolling], + ["24x64", "AT24C64", 13, new_24x64, NoPolling] ); impl_for_page_size!( TwoBytes, 2, B64, 64, - ["24x128", "AT24C128", 14, new_24x128], - ["24x256", "AT24C256", 15, new_24x256] + ["24x128", "AT24C128", 14, new_24x128, NoPolling], + ["24x256", "AT24C256", 15, new_24x256, NoPolling] ); impl_for_page_size!( TwoBytes, 2, B128, 128, - ["24x512", "AT24C512", 16, new_24x512] + ["24x512", "AT24C512", 16, new_24x512, NoPolling] ); impl_for_page_size!( TwoBytes, 2, B256, 256, - ["24xM01", "AT24CM01", 17, new_24xm01], - ["24xM02", "AT24CM02", 18, new_24xm02] + ["24xM01", "AT24CM01", 17, new_24xm01, NoPolling], + ["24xM02", "AT24CM02", 18, new_24xm02, NoPolling] ); diff --git a/src/lib.rs b/src/lib.rs index 4f80d04..0270589 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -217,6 +217,14 @@ pub mod page_size { pub struct B256(()); } +/// Eeprom supports polling +pub mod polling { + /// has polling support + pub struct Polling(()); + /// has no polling support + pub struct NoPolling(()); +} + /// EEPROM24X driver #[derive(Debug)] pub struct Eeprom24x { @@ -226,6 +234,8 @@ pub struct Eeprom24x { address: SlaveAddr, /// Number or bits used for memory addressing. address_bits: u8, + /// Has polling Support + polling: bool, /// Page size marker type. _ps: PhantomData, /// Address size marker type. diff --git a/src/storage.rs b/src/storage.rs index 847a62b..d51adf1 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -71,7 +71,10 @@ where } let page_size = self.eeprom.page_size(); while !bytes.is_empty() { - //let _ = nb::block!(self.count_down.wait()); // CountDown::wait() never fails + if self.eeprom.polling { + let _ = nb::block!(self.count_down.wait()); + } + let this_page_offset = offset as usize % page_size; let this_page_remaining = page_size - this_page_offset; let chunk_size = min(bytes.len(), this_page_remaining); @@ -81,38 +84,41 @@ where // TODO At least ST's eeproms allow polling, i.e. trying the next i2c access which will // just be NACKed as long as the device is still busy. This could potentially speed up // the write process. - self.count_down.start(Duration::from_millis(10)); - repeat_timeout!( - &mut self.count_down, - { - match self.eeprom.read_byte(0){ - // ready (ACK) - Ok(_) => { - Ok(()) - } + if self.eeprom.polling { + self.count_down.start(Duration::from_millis(5)); + repeat_timeout!( + &mut self.count_down, + { + match self.eeprom.read_byte(0){ + // ready (ACK) + Ok(_) => { + Ok(()) + } - // not yet ready (NACK) - Err(Error::I2C(_)) => {Err(())} + // not yet ready (NACK) + Err(Error::I2C(_)) => {Err(())} - // any other error - Err(e) => { - return Err(e); + // any other error + Err(e) => { + return Err(e); + } } - } - }, - (_ack) { - // eeprom done writing => Leaving - break; - }; - (_nack) { - // eeprom still busy - continue; - }; - ); + }, + (_ack) { + // eeprom done writing => Leaving + break; + }; + (_nack) { + // eeprom still busy + continue; + }; + ); + } else { + self.count_down.start(Duration::from_millis(5)); + } // TODO Currently outdated comment: // A (theoretically needless) delay after the last page write ensures that the user can // call Storage::write() again immediately. - //self.count_down.start(Duration::from_millis(5)); } Ok(()) } From 4dc71b1de3ec3e45d9ef143915c36308b27f034d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirco=20Telth=C3=B6rster?= Date: Mon, 4 Apr 2022 12:33:11 +0200 Subject: [PATCH 05/11] fix --- src/storage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storage.rs b/src/storage.rs index d51adf1..e6707be 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -71,7 +71,7 @@ where } let page_size = self.eeprom.page_size(); while !bytes.is_empty() { - if self.eeprom.polling { + if !self.eeprom.polling { let _ = nb::block!(self.count_down.wait()); } From 91896bcdcfd3f2f4ef57c95f41e70ebebf811276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirco=20Telth=C3=B6rster?= Date: Mon, 27 Jun 2022 09:51:08 +0200 Subject: [PATCH 06/11] Comments added --- src/storage.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/storage.rs b/src/storage.rs index e6707be..3146c78 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -81,11 +81,10 @@ where self.eeprom.page_write(offset, &bytes[..chunk_size])?; offset += chunk_size as u32; bytes = &bytes[chunk_size..]; - // TODO At least ST's eeproms allow polling, i.e. trying the next i2c access which will - // just be NACKed as long as the device is still busy. This could potentially speed up - // the write process. if self.eeprom.polling { + // eeprom with polling support self.count_down.start(Duration::from_millis(5)); + // start polling repeat_timeout!( &mut self.count_down, { @@ -114,11 +113,10 @@ where }; ); } else { + // eeprom without polling support + // using timeout instead self.count_down.start(Duration::from_millis(5)); } - // TODO Currently outdated comment: - // A (theoretically needless) delay after the last page write ensures that the user can - // call Storage::write() again immediately. } Ok(()) } From e3dfa0a9c0ca7d90c727479fa76da2131c5bc8e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirco=20Telth=C3=B6rster?= Date: Wed, 6 Jul 2022 12:01:48 +0200 Subject: [PATCH 07/11] changed polling struct to enum and do polling before writes instead of afterwards --- src/eeprom24x.rs | 24 ++++++------------------ src/lib.rs | 9 +++++---- src/storage.rs | 26 ++++++++++---------------- 3 files changed, 21 insertions(+), 38 deletions(-) diff --git a/src/eeprom24x.rs b/src/eeprom24x.rs index b275eec..a3fc465 100644 --- a/src/eeprom24x.rs +++ b/src/eeprom24x.rs @@ -1,7 +1,7 @@ use crate::{ - addr_size, page_size, - polling::{self, NoPolling, Polling}, - private, Eeprom24x, Error, SlaveAddr, + addr_size, page_size, private, Eeprom24x, Error, + PollingSupport::{self, NoPolling, Polling}, + SlaveAddr, }; use core::marker::PhantomData; use embedded_hal::blocking::i2c::{Write, WriteRead}; @@ -29,18 +29,6 @@ impl MultiSizeAddr for addr_size::TwoBytes { } } -pub trait HasPollingSupport { - const SUPPORT: bool; -} - -impl HasPollingSupport for polling::Polling { - const SUPPORT: bool = true; -} - -impl HasPollingSupport for polling::NoPolling { - const SUPPORT: bool = false; -} - /// Common methods impl Eeprom24x { /// Destroy driver instance, return I²C bus instance. @@ -140,7 +128,7 @@ where i2c, address, address_bits: 4, - polling: false, + polling: NoPolling, _ps: PhantomData, _as: PhantomData, } @@ -158,7 +146,7 @@ macro_rules! impl_create { (@gen [$create:ident, $address_bits:expr, $doc:expr, $HPS:ident] ) => { #[doc = $doc] pub fn $create(i2c: I2C, address: SlaveAddr) -> Self { - Self::new(i2c, address, $address_bits, $HPS::SUPPORT) + Self::new(i2c, address, $address_bits, $HPS) } }; } @@ -187,7 +175,7 @@ macro_rules! impl_for_page_size { )* #[doc = $doc_new] - fn new(i2c: I2C, address: SlaveAddr, address_bits: u8, polling_support: bool) -> Self { + fn new(i2c: I2C, address: SlaveAddr, address_bits: u8, polling_support: PollingSupport) -> Self { Eeprom24x { i2c, address, diff --git a/src/lib.rs b/src/lib.rs index 0270589..9d8dc96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -218,11 +218,12 @@ pub mod page_size { } /// Eeprom supports polling -pub mod polling { +#[derive(Debug)] +enum PollingSupport { /// has polling support - pub struct Polling(()); + Polling, /// has no polling support - pub struct NoPolling(()); + NoPolling, } /// EEPROM24X driver @@ -235,7 +236,7 @@ pub struct Eeprom24x { /// Number or bits used for memory addressing. address_bits: u8, /// Has polling Support - polling: bool, + polling: PollingSupport, /// Page size marker type. _ps: PhantomData, /// Address size marker type. diff --git a/src/storage.rs b/src/storage.rs index 3146c78..33700b5 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -71,19 +71,7 @@ where } let page_size = self.eeprom.page_size(); while !bytes.is_empty() { - if !self.eeprom.polling { - let _ = nb::block!(self.count_down.wait()); - } - - let this_page_offset = offset as usize % page_size; - let this_page_remaining = page_size - this_page_offset; - let chunk_size = min(bytes.len(), this_page_remaining); - self.eeprom.page_write(offset, &bytes[..chunk_size])?; - offset += chunk_size as u32; - bytes = &bytes[chunk_size..]; - if self.eeprom.polling { - // eeprom with polling support - self.count_down.start(Duration::from_millis(5)); + if let crate::PollingSupport::Polling = self.eeprom.polling { // start polling repeat_timeout!( &mut self.count_down, @@ -113,10 +101,16 @@ where }; ); } else { - // eeprom without polling support - // using timeout instead - self.count_down.start(Duration::from_millis(5)); + let _ = nb::block!(self.count_down.wait()); } + + let this_page_offset = offset as usize % page_size; + let this_page_remaining = page_size - this_page_offset; + let chunk_size = min(bytes.len(), this_page_remaining); + self.eeprom.page_write(offset, &bytes[..chunk_size])?; + offset += chunk_size as u32; + bytes = &bytes[chunk_size..]; + self.count_down.start(Duration::from_millis(5)); } Ok(()) } From a1d947acdec5a2d8ffac8b5ff56117406a5a1614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirco=20Telth=C3=B6rster?= Date: Wed, 6 Jul 2022 13:20:09 +0200 Subject: [PATCH 08/11] added polling to read --- src/storage.rs | 78 +++++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/src/storage.rs b/src/storage.rs index 33700b5..0ff30a2 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -39,6 +39,49 @@ impl Storage { } } +impl Storage +where + I2C: Write + WriteRead, + AS: MultiSizeAddr, + CD: CountDown